Repository navigation
fix(http): reject impossible body length in elide_transport_http_respond before forming slice - #62
Conversation
…ond before forming slice
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #62 +/- ##
============================================
- Coverage 86.82% 86.81% -0.01%
Complexity 616 616
============================================
Files 60 60
Lines 16979 16980 +1
Branches 490 490
============================================
Hits 14742 14742
- Misses 1913 1914 +1
Partials 324 324
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. |
Merging this PR will degrade performance by 10.41%
|
| Mode | Benchmark | BASE |
HEAD |
Efficiency | |
|---|---|---|---|---|---|
| ❌ | Simulation | retain-drop[1048576] |
300.8 ns | 354.9 ns | -15.26% |
| ❌ | Simulation | retain-drop[4096] |
300.8 ns | 354.9 ns | -15.26% |
| ❌ | Simulation | retain-drop[64] |
300.8 ns | 354.9 ns | -15.26% |
| ❌ | Simulation | retain-drop[65536] |
300.8 ns | 354.9 ns | -15.26% |
| ❌ | WallTime | established-encrypt[64] |
150 ns | 167 ns | -10.18% |
| ⚡ | Simulation | overwrite[64] |
520.2 ns | 466.1 ns | +11.62% |
Tip
Investigate this regression by commenting @codspeedbot fix this regression on this PR, or directly use the CodSpeed MCP with your agent.
Comparing detail/bug-fix/fix-http-reject-impossible-body-length-in-elide-tr-2c26cc (ad47ba9) with main (26fb123)
Footnotes
-
65 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports. ↩
Detail bug report: View on Detail
Change
elide_transport_http_respondincrates/bemo/src/abi/http.rs(the public C-ABI entry point consumed by Java FFM and GraalVM Native Image bindings) constructed a&[u8]viastd::slice::from_raw_parts(body, length)before validating thatlengthcould fit inisize::MAX. On the crate's mandated 64-bit targets,usize::try_from(u64::MAX)succeeds, so the catch-all_ => return INVALIDarm never fired for the documented-1L/u64::MAX"unknown length" sentinel whenRESPOND_STREAMwas absent — the invalid slice was formed first, causing instant undefined behavior (debug-build abort, formal UB in release).Ok(length) if !body.is_null()match arm lacked anisize::MAXbound, so anybody_length > isize::MAX(including the sentinel) reached the unsafefrom_raw_partscall before downstream rejection inencode_responsecould run.length <= isize::MAX as usizeto the guard, routing impossible lengths to_ => return INVALIDwithout forming the slice. No ABI symbol, layout, or ownership semantics change — the fix only tightens validation for an out-of-contract flag/length combination that no caller can ever satisfy the safety contract for.Closes #55
Validation
respond_rejects_impossible_body_length_without_streaming_instead_of_ubincrates/bemo/tests/http.rs): callselide_transport_http_respondwithbody_length = u64::MAXandbody_length = (isize::MAX as u64) + 1withoutRESPOND_STREAM, assertsINVALIDfor both, then verifies the exchange is still usable with a normalrespondthat produces correct wire output.bemolib tests (182/182),httpintegration tests (69/70 — the one failurearm_receive_failure_leaves_socket_dormantis pre-existing and environment-dependent, confirmed by stashing the fix),abiintegration tests (14/14), clippy (-D warnings), andcargo fmt --check.--lib --test buffers --test abi --test pool --test workload): 184 passed, 0 failed, 55 ignored — no UB detected in any covered path.-Zbuild-std): 382/384 passed, no memory errors. The 2 failures (arm_receive_failure_leaves_socket_dormant,persistent_keepalive_reuses_receive_registration_and_fixed_send_state) are pre-existing and confirmed to fail identically without the fix.cargo-fuzz v0.13.1(pinned intools/versions.json) does not compile with the current nightly toolchain due to arustixattribute incompatibility;v0.13.2was used instead.cargo build --workspace --locked): clean.body_lengththrough unchanged; the fix only rejects an out-of-contract combination that was already intended to returnINVALID.Automatic Fixes PRs can be configured here.