Repository navigation
reject negative attachment_size in baidu_std request/response parsing - #3604
sahvx655-wq wants to merge 2 commits into
Conversation
attachment_size is a peer-controlled int32 but both guards only check an upper bound, so a negative value reaches res_size - attachment_size (int) and overflows for INT32_MIN. Reject attachment_size < 0 at both sites.
There was a problem hiding this comment.
Warning
Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.
Copilot review overview
2 open issues
What changed in this PR
Tightens baidu_std request/response parsing validation to reject negative RpcMeta.attachment_size, preventing signed overflow/UB and payload/body desynchronization.
Changes:
- Add
attachment_size < 0guards in both request and response parsing paths. - Update failure messages to reflect invalid
attachment_sizevalues.
| File | Description |
|---|---|
| src/brpc/policy/baidu_rpc_protocol.cpp | Adds lower-bound validation for attachment_size in request/response parsing and updates related SetFailed messages. |
Review effort: Lite
| if (meta.attachment_size() < 0 || | ||
| req_size < meta.attachment_size()) { | ||
| cntl->SetFailed(EREQUEST, | ||
| "attachment_size=%d is larger than request_size=%d", | ||
| "Invalid attachment_size=%d (request_size=%d)", |
| if (meta.attachment_size() < 0 || | ||
| meta.attachment_size() > res_size) { | ||
| cntl->SetFailed( | ||
| ERESPONSE, "attachment_size=%d is larger than response_size=%d", | ||
| ERESPONSE, "Invalid attachment_size=%d (response_size=%d)", | ||
| meta.attachment_size(), res_size); |
|
[replied by brpc-oncall robot] The negative-value guards correctly close the signed-overflow/desync at both the request and response sites, and no compatibility concern for well-formed messages. One request before merge: add a regression test. The claim that this path needs a full round trip is not accurate: test/brpc_channel_unittest.cpp already constructs a policy::MostCommonMessage and calls brpc::policy::ProcessRpcResponse directly (see ResponseSocketTest), so a case setting a negative attachment_size can assert ERESPONSE and that no crash occurs. Please add such a case (and, if feasible, a request-side one) so this guard does not silently regress. The split error messages suggested by Copilot are not necessary: the updated message already logs both the offending value and the payload size, which is enough to distinguish the two cases. |
…nd response parsing
|
Fair point on the round trip, I'd missed that I built the suite locally against the unpatched parser first to make sure the cases actually bite: both paths served the payload with |
There was a problem hiding this comment.
🟡 Changes recommended
The new tests leave socket creation references unreleased, leaking socket resources and request-side file descriptors.
4 open issues
Release socket creation reference in response-test iterations · New Release socket and descriptor creation references in request tests · New The new error string collapses two distinct failure modes (negative vs larger-than-payload) into a…meta.attachment_size()is evaluated multiple times in the condition and again in the error…
Review effort: Balanced
| ASSERT_EQ(0, brpc::Socket::Create(brpc::SocketOptions(), &sending_id)); | ||
| ASSERT_EQ(0, brpc::Socket::Address( | ||
| sending_id, &cntl._current_call.sending_sock)); | ||
| brpc::Socket* socket = cntl._current_call.sending_sock.get(); |
| ASSERT_EQ(0, brpc::Socket::Create(options, &socket_id)); | ||
| request_fd.release(); | ||
| brpc::SocketUniquePtr socket; | ||
| ASSERT_EQ(0, brpc::Socket::Address(socket_id, &socket)); |


What problem does this PR solve?
Issue Number: resolve
Problem Summary:
RpcMeta.attachment_sizeisoptional int32(baidu_rpc_meta.proto) and is copied from the peer. InProcessRpcRequestandProcessRpcResponse(src/brpc/policy/baidu_rpc_protocol.cpp) it is validated only against an upper bound (req_size < attachment_size,attachment_size > res_size). A negative value passes both guards and reachesWith
attachment_size = INT32_MINand a small body (an empty body is a valid baidu_std message),res_size - attachment_sizeoverflows signedint, which is undefined behavior; the UBSan job in CI aborts on it. For other negative values the subtraction yields a size larger than the payload, so the body/attachment split silently desyncs.Reproduced the arithmetic with the real types under
-fsanitize=undefined:attachment_size=INT32_MIN,req_size=0givesruntime error: signed integer overflow: 0 - -2147483648 cannot be represented in type 'int'and aborts; with the negative value rejected it returns cleanly.Siblings checked: hulu uses
cutn(user_message_size)(bounded by IOBuf, no subtraction) and sofa has no attachment, so neither shares the pattern. Both affected sites are in this file.What is changed and the side effects?
Changed:
attachment_size < 0at the request and response guards, so the laterintsubtraction always has a non-negative operand.Side effects:
Performance effects: none.
Breaking backward compatibility: none. A valid
attachment_sizeis a byte count and is always>= 0; only malformed negative values are now rejected with the existingSetFailedpath.Check List:
INT32_MIN; after: clean reject). No committed unit test since this parser path needs a full server/client round-trip to exercise and I could not build the suite in my environment; happy to add one if you prefer.This fix was found and prepared with AI assistance and reviewed by me before submitting.