Bound wire-declared sizes and decompressed output during parsing - #3476
Open
wwbmmm wants to merge 1 commit into
Open
Bound wire-declared sizes and decompressed output during parsing#3476wwbmmm wants to merge 1 commit into
wwbmmm wants to merge 1 commit into
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
Adds protections against oversized wire-declared values and decompression output across bRPC parsers, with regression tests.
Changes:
- Adds configurable gzip, zlib, and Snappy decompression limits.
- Bounds AMF and RTMP parsing and resets incomplete bodies.
- Validates mcpack counts and caps generated reservations.
- Adds tests for oversized and truncated inputs.
Reviewed changes
Copilot reviewed 13 out of 13 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Summary / final review status |
|---|---|
test/brpc_sofa_pbrpc_protocol_unittest.cpp |
Tests oversized SOFA metadata. No final comments. |
test/brpc_snappy_compress_unittest.cpp |
Tests decompression caps. Moderate: use FlagSaver for global flag mutations. |
test/brpc_rtmp_unittest.cpp |
Tests AMF and RTMP bounds. Moderate: use FlagSaver to restore max_body_size safely. |
test/brpc_mcpack2pb_unittest.cpp |
Tests mcpack count validation. No final comments. |
src/mcpack2pb/parser.h |
Adds bounded reservation support. No final comments. |
src/mcpack2pb/parser-inl.h |
Validates object item counts. Critical: check the size before cut_packed_pod reads ItemsHead. |
src/mcpack2pb/generator.cpp |
Applies bounded reservations to generated parsers. No final comments. |
src/brpc/policy/snappy_compress.cpp |
Bounds Snappy decompression output. No final comments. |
src/brpc/policy/rtmp_protocol.cpp |
Bounds RTMP message lengths and resets partial bodies. No final comments. |
src/brpc/policy/gzip_compress.cpp |
Bounds gzip/zlib decompression output. No final comments. |
src/brpc/compress.h |
Declares decompression configuration. Critical: include gflags/gflags_declare.h before DECLARE_uint64. |
src/brpc/compress.cpp |
Defines decompression-size configuration and limits. No final comments. |
src/brpc/amf.cpp |
Reads AMF strings incrementally. No final comments. |
Suppressed comments (1)
src/mcpack2pb/parser-inl.h:160
item_countis peer-controlled, so this rejection path is reachable from a malformed request.CHECK(false)is fatal in bRPC, which aborts the process instead of returning a bad stream; the newly added regression test also terminates here rather than passing. Use non-fatal logging followed byset_bad()so the parser rejects the input without taking down the server.
CHECK(false) << "inconsistent item_count(" << items_head.item_count
<< ") and value_size(" << size << ")";
return set_bad();
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
wwbmmm
force-pushed
the
fix/BoundMessageSizesAndDecompressedOutput
branch
from
August 22, 2026 12:19
b16e013 to
ea2d150
Compare
Contributor
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 13 out of 13 changed files in this pull request and generated 3 comments.
Suppressed comments (3)
src/mcpack2pb/parser-inl.h:163
- The new inconsistent-count branch is also driven entirely by peer-controlled bytes, but
CHECK(false)is fatal here. The regression test'sitem_count = 0x7fffffffinput will abort at this line beforeit == NULLcan be observed, and a remote client can use the same packet to crash the process; log the parse error and then callset_bad()without a fatal check.
CHECK(false) << "inconsistent item_count(" << items_head.item_count
<< ") and value_size(" << size << ")";
test/brpc_rtmp_unittest.cpp:697
- The added RTMP test returns at the preceding oversized-length check, so it never exercises the new partial-body reset in either the type-0 or type-1 branch. Add a case that feeds a partial message followed by a new header and verifies the stale bytes are discarded; otherwise this security-sensitive reassembly behavior is untested.
TEST(RtmpTest, chunk_stream_rejects_message_length_over_max_body_size) {
test/brpc_snappy_compress_unittest.cpp:272
- This assertion only checks that decompression eventually returns false; it would still pass if the full 64-KB body were materialized before failure. Please assert that
outremains within the configured cap, and add rejection coverage for the separate Message/Zlib paths, since the new Message limiter and shared Zlib output path are otherwise untested.
ASSERT_FALSE(brpc::policy::GzipDecompress(gzipped, &out));
Several parsers that handle client-controlled input trusted sizes declared on the wire without bounding them, which could make a connection consume far more memory than the message itself: - gzip/zlib/snappy decompression had no output cap: -max_body_size is only checked against the compressed bytes, so a small body could decompress to tens of GiB. Add -max_decompressed_body_size (default 32x -max_body_size, 0 means use the default) and enforce it in all three decompressors. The output cap is applied via a local ZeroCopyInputStream wrapper so it builds against every protobuf version CI uses (>= 3.5.1); the wrapper clips oversized blocks without double-backing-up the wrapped stream. - AMF string readers resized the output buffer to the declared length before checking how many bytes were actually available; read the string in bounded chunks instead. - RTMP chunk headers may re-declare a message while a pr- RTMP chunk headers may re-declare a message while a pr- RTMP chunk headers may re-deed - RTMP chunk headers may re-declare a message while a pr- RTMP ody- RTMP chunk headers may re-declare a message while a pr- RTwir- RTMP chunk headers may re-declare a message while a pr- cou- RTMP chunk headers may re-declare a message while a pr- RTMP ch r- RTMP chunk headers may re-declare a message while a pr- RTMPvalues instead of CHECK-fatal.
wwbmmm
force-pushed
the
fix/BoundMessageSizesAndDecompressedOutput
branch
from
August 23, 2026 02:17
ea2d150 to
2be4515
Compare
Copilot stopped reviewing on behalf of
wwbmmm due to an error
August 23, 2026 02:38
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What problem does this PR solve?
Problem Summary:
Wire input to bRPC parsers contains lengths/counts that are declared
by the peer. Several parsers used those values to size buffers or
drive allocations before the corresponding bytes were known to exist,
and decompressors never bounded their output. With untrusted clients
this lets a small amount of traffic trigger disproportionate memory
usage.
What is changed and the side effects?
Changed:
-max_decompressed_body_sizeflag (default: 32x-max_body_size, 0 = use the default) caps how much a single bodymay decompress to. Bodies that exceed the cap are rejected with a
warning log instead of being fully materialized.
64 KB chunks instead of allocating the declared length up front,
so a truncated message no longer forces the full allocation.
-max_body_sizeand discards a partially assembled body when anew message header arrives mid-message.
count against the remaining bytes (each field head is at least 2
bytes) and generated array-parse code caps its
Reserve()size.Side effects:
allocations that were already on the path to failure.
-max_body_sizeare unaffected unless they also exceed the newdecompression cap; operators with legitimately larger compressed
bodies can raise
-max_decompressed_body_size.Check List:
test/brpc_snappy_compress_unittest.cpp,test/brpc_rtmp_unittest.cpp,test/brpc_mcpack2pb_unittest.cpp,test/brpc_sofa_pbrpc_protocol_unittest.cpp.