From 10817039904ae15e838a2abd4fed61d21678e0e4 Mon Sep 17 00:00:00 2001 From: ubeddulla khan Date: Thu, 9 Jul 2026 12:46:21 +0530 Subject: [PATCH] avoid undefined shift in hpack DecodeInteger on crafted integer --- src/brpc/details/hpack.cpp | 10 ++++++++++ test/brpc_hpack_unittest.cpp | 21 +++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/src/brpc/details/hpack.cpp b/src/brpc/details/hpack.cpp index e4e7890e17..b2206682c8 100644 --- a/src/brpc/details/hpack.cpp +++ b/src/brpc/details/hpack.cpp @@ -547,6 +547,16 @@ inline ssize_t DecodeInteger(butil::IOBufBytesIterator& iter, if (!iter) { return 0; } + // A well-formed integer below MAX_HPACK_INTEGER fits in a few + // continuation octets. A run of 0x80 octets (continuation bit set, + // payload bits zero) leaves tmp unchanged, so the `tmp < + // MAX_HPACK_INTEGER` guard below never trips while m keeps growing; + // once m reaches 64 the `<< m` shift is undefined behavior. Refuse the + // over-long encoding before that happens. + if (m >= 32) { + LOG(ERROR) << "Source stream is likely malformed"; + return -1; + } cur_byte = *iter; in_bytes++; tmp += static_cast(cur_byte & 0x7f) << m; diff --git a/test/brpc_hpack_unittest.cpp b/test/brpc_hpack_unittest.cpp index d6a0bd02ff..48d3ae52eb 100644 --- a/test/brpc_hpack_unittest.cpp +++ b/test/brpc_hpack_unittest.cpp @@ -96,6 +96,27 @@ TEST_F(HPackTest, dynamic_table_size_update_before_header) { ASSERT_EQ("GET", h.value); } +TEST_F(HPackTest, integer_with_overlong_continuation) { + brpc::HPacker p; + ASSERT_EQ(0, p.Init(4096)); + + // Indexed header field whose index is encoded with a 7-bit prefix of all + // ones (0xFF) followed by a long run of 0x80 continuation octets. Each + // 0x80 carries a zero payload, so the decoded value never grows past its + // MAX_HPACK_INTEGER guard, but the per-octet shift amount does. Decode must + // reject this as malformed instead of shifting by 64+ bits. + butil::IOBuf buf; + uint8_t encoded[1 + 20]; + encoded[0] = 0xFF; + for (size_t i = 1; i < sizeof(encoded); ++i) { + encoded[i] = 0x80; + } + buf.append(encoded, sizeof(encoded)); + + brpc::HPacker::Header h; + ASSERT_LT(p.Decode(&buf, &h), 0); +} + // Copied test cases from example of rfc7541 TEST_F(HPackTest, header_with_indexing) { brpc::HPacker p1;