Repository navigation
bound grpc-timeout value before converting to microseconds - #3591
sahvx655-wq wants to merge 2 commits into
Conversation
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
4 open findings
The comment above states the wire format requires a positive integer, but the current check… · New The comment above states the wire format requires a positive integer, but the current check… · New Consider making this a compile-time constant (e.g.,constexpr int64_t ...) and/or placing it in… · New The comment describes cases “beyond 8 digits” / “large ones overflow”, but the list also includes… · New
What changed in this PR
This PR hardens gRPC grpc-timeout parsing to prevent int64_t overflow/UB by bounding the parsed timeout value to the range allowed by the gRPC wire format, and extends unit tests to cover previously overflowing inputs.
Changes:
- Add an upper bound check (and malformed-value handling) in
ConvertGrpcTimeoutToUSbefore converting to microseconds. - Introduce a constant representing the maximum conforming
TimeoutValue(8 ASCII digits). - Expand
GrpcTest.GrpcTimeOuttest vectors with overflow-sized and invalid values.
| File | Description |
|---|---|
src/brpc/grpc.cpp |
Adds a max timeout bound to prevent overflow during unit conversion. |
test/brpc_grpc_protocol_unittest.cpp |
Adds regression cases for large/invalid grpc-timeout headers. |
🧠 Review effort: Lite
Give feedback about Copilot approvals in this survey to enter a drawing for a $150 gift card.
|
LGTM |
|
Pushed a comment-only follow-up for the two bot findings that were actually right. The constant's comment no longer quotes the wire format as requiring a positive integer, because the check deliberately lets 0 through, and the test comment now mentions the negative entry alongside the oversized ones. Nothing else moved: the diff is two comment blocks, so the bound and the six new table entries behave exactly as they did when CI went green. I did not take the other two. Rejecting 0 would be a behaviour change in the wrong direction - |
There was a problem hiding this comment.
🟢 Approval recommended
The bound safely covers all unit conversions and the regression cases exercise the affected behavior.
0 open findings
4 resolved since last review
The comment above states the wire format requires a positive integer, but the current check… The comment above states the wire format requires a positive integer, but the current check… The comment describes cases “beyond 8 digits” / “large ones overflow”, but the list also includes… Consider making this a compile-time constant (e.g.,constexpr int64_t ...) and/or placing it in…
🧠 Review effort: Balanced


What problem does this PR solve?
Issue Number: N/A
Problem Summary:
ConvertGrpcTimeoutToUS(src/brpc/grpc.cpp) parses thegrpc-timeoutrequest header with
strtoland then multiplies the result by its unit. Theonly validation is that the digit span equals the header length minus one, so
a value of any magnitude gets through and every unit branch overflows
int64_t:18446744073710Swrapstimeout_value * 1000000to 448384,2562047789Hwrapstimeout_value * 3600 * 1000000negative, and9223372036854775807noverflowstimeout_value + 500.9223372036854775807uis returned unchanged, so the addition atsrc/brpc/policy/http_rpc_protocol.cpp:1707overflows instead. Compiling thefunction with
-fsanitize=undefinedaborts on theScase:runtime error: signed integer overflow: 18446744073710 * 1000000 cannot be represented in type 'int64_t'.Signed overflow is undefined behaviour, and with recovery on the wrapped
values are observable. A peer that asks for an absurdly long deadline instead
gets one 448384us away, or one far in the past, and the service reads that
back through
Controller::deadline_us()and acts on it. The header is parsedbefore any service code runs, on any h2 port that serves gRPC, so nothing
about the input is privileged.
What is changed and the side effects?
Changed:
grpc-timeoutvalue outside the range the gRPC wire format allows(
TimeoutValueis "a positive integer as ASCII string of at most 8digits"), returning -1 the way the function already does for every other
malformed header. One bound covers all four arithmetic sites: 99999999 hours
in microseconds is 3.6e17, which still leaves room for the caller to add the
current time.
GrpcTest.GrpcTimeOuttable with the overflowing values plus a9-digit and a negative one.
Side effects:
Performance effects: one comparison per gRPC request carrying the header.
Breaking backward compatibility: in-spec timeouts behave exactly as before.
A value with more than 8 digits is now ignored instead of producing a
wrapped deadline. The only brpc client that can emit one is a caller with
timeout_msabove 100000000 (over 27 hours), and such a client stillenforces its own deadline. A negative value returns -1 rather than negative
microseconds, which the single call site already treated identically.
Check List:
GrpcTest.GrpcTimeOutfails on master for18446744073710S(deadline 448384us away),
9223372036854775807u(negative deadline) and100000000S, and passes with the fix. All 8 cases ofbrpc_grpc_protocol_unittestpass, along withbrpc_http_rpc_protocol_unittest(62),brpc_http_message_unittest(28)and
brpc_h2_unsent_message_unittest(5).-DBUILD_UNIT_TESTS=ON.