This is an automated email from the ASF dual-hosted git repository.
wasphin pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/brpc.git
The following commit(s) were added to refs/heads/master by this push:
new 9ea2eae8 reject out-of-range AMF numbers in ReadAMFUint32 (#3593)
9ea2eae8 is described below
commit 9ea2eae8f1abcf059735003d1a4f5c065f8bea01
Author: UB <[email protected]>
AuthorDate: Mon Oct 12 10:10:28 2026 +0530
reject out-of-range AMF numbers in ReadAMFUint32 (#3593)
The AMF0 number is a peer-controlled double; casting NaN or values outside
[0, UINT32_MAX] to uint32_t is undefined behavior (UBSan float-cast-overflow)
and decodes to different ids per platform. Validate the range before the cast.
---
src/brpc/amf.cpp | 6 ++++++
test/brpc_rtmp_unittest.cpp | 39 +++++++++++++++++++++++++++++++++++++++
2 files changed, 45 insertions(+)
diff --git a/src/brpc/amf.cpp b/src/brpc/amf.cpp
index d4c4829f..808f42d3 100644
--- a/src/brpc/amf.cpp
+++ b/src/brpc/amf.cpp
@@ -392,6 +392,12 @@ bool ReadAMFUint32(uint32_t* val, AMFInputStream* stream) {
if (!ReadAMFNumber(&d, stream)) {
return false;
}
+ // The number comes from the peer and may be NaN or out of [0, UINT32_MAX],
+ // for which the conversion below is undefined. The check is false for NaN.
+ if (!(d >= 0.0 && d <= 4294967295.0)) {
+ LOG(ERROR) << "Invalid AMF number=" << d << " for uint32";
+ return false;
+ }
*val = (uint32_t)d;
return true;
}
diff --git a/test/brpc_rtmp_unittest.cpp b/test/brpc_rtmp_unittest.cpp
index 3694df3a..cbc21b7e 100644
--- a/test/brpc_rtmp_unittest.cpp
+++ b/test/brpc_rtmp_unittest.cpp
@@ -19,6 +19,7 @@
// Date: Fri May 20 15:52:22 CST 2016
+#include <limits>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/socket.h>
@@ -734,6 +735,44 @@ TEST(RtmpTest, amf) {
ASSERT_EQ("heheda", info3.description());
}
+TEST(RtmpTest, amf_rejects_out_of_range_uint32) {
+ // Each value below encodes legally in an AMF0 number but has no uint32
+ // representation; the cast in ReadAMFUint32 was undefined for them.
+ const double bad_values[] = { -1.0, 4294967296.0, 1e30, -1e30,
+ std::numeric_limits<double>::infinity(),
+ std::numeric_limits<double>::quiet_NaN() };
+ for (size_t i = 0; i < arraysize(bad_values); ++i) {
+ std::string buf;
+ {
+ google::protobuf::io::StringOutputStream zc_stream(&buf);
+ brpc::AMFOutputStream ostream(&zc_stream);
+ brpc::WriteAMFNumber(bad_values[i], &ostream);
+ ASSERT_TRUE(ostream.good());
+ }
+ google::protobuf::io::ArrayInputStream zc_stream(buf.data(),
buf.size());
+ brpc::AMFInputStream istream(&zc_stream);
+ uint32_t val = 0;
+ EXPECT_FALSE(brpc::ReadAMFUint32(&val, &istream)) << "i=" << i;
+ }
+
+ const double good_values[] = { 0.0, 42.5, 4294967295.0 };
+ const uint32_t expected_values[] = { 0, 42, 4294967295u };
+ for (size_t i = 0; i < arraysize(good_values); ++i) {
+ std::string buf;
+ {
+ google::protobuf::io::StringOutputStream zc_stream(&buf);
+ brpc::AMFOutputStream ostream(&zc_stream);
+ brpc::WriteAMFNumber(good_values[i], &ostream);
+ ASSERT_TRUE(ostream.good());
+ }
+ google::protobuf::io::ArrayInputStream zc_stream(buf.data(),
buf.size());
+ brpc::AMFInputStream istream(&zc_stream);
+ uint32_t val = 0;
+ ASSERT_TRUE(brpc::ReadAMFUint32(&val, &istream)) << "i=" << i;
+ ASSERT_EQ(expected_values[i], val);
+ }
+}
+
TEST(RtmpTest, amf_rejects_oversized_string_before_growing_output) {
std::string req_buf;
AppendAMFLongStringHeader(&req_buf, 16);
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]