fix: proxy dos caps — connections, hpack, http2 streams - #446
Merged
Conversation
the listener incremented active_connections but never checked it before std.Thread.spawn — a connection flood would spawn threads until the OS limit. add a max_connections cap (1024) and shed at the cap by closing the accepted fd, mirroring the api server's guard. extracted the count+admit decision into admitConnection() with a unit test.
decodeInteger could accumulate a near-usize value that overflows the downstream start+len arithmetic in decodeString. cap the running value (16 MiB). also cap headers-per-block (256), total decoded header bytes (1 MiB), and clamp a peer's dynamic-table-size update (1 MiB) so a crafted header block can't exhaust memory. three new tests.
a single http2 connection could open unlimited streams (growing the streams list + dialing an upstream each) or stream bytes without ever completing a frame (growing downstream_buf). cap concurrent streams at 128 — refused past the limit with 503 before any upstream dial, so no fd leaks — and bound un-parsed downstream bytes at 1 MiB.
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.
summary
second of the four-PR hardening pass. caps that stop a single client from
exhausting threads or memory on the L7 proxy. all reject-the-excess /
bound-the-unbounded — normal traffic is unaffected.
what's in here
1. listener connection cap (
listener_runtime.zig)the accept loop incremented
active_connectionsbut never checked itbefore
std.Thread.spawn— a connection flood spawned detached threadsuntil the OS thread/fd limit. added
max_connections = 1024; at the capthe accepted fd is closed immediately (load shed) rather than spawning.
mirrors the API server's existing guard. count+admit decision extracted
into
admitConnection()with a unit test.2. hpack decode bounds (
hpack.zig)decodeIntegercould accumulate a near-usize value that overflows thestart + lenarithmetic indecodeString(panic). capped the runningvalue at 16 MiB; also capped headers-per-block (256), total decoded
header bytes (1 MiB), and clamped a peer's dynamic-table-size update to
1 MiB. three new tests.
3. http2 stream + buffer caps (
http2_connection_router.zig)a single connection could open unlimited streams (each growing the
stream list and dialing an upstream) or stream bytes without completing
a frame (growing
downstream_buf). capped concurrent streams at 128 —refused past the limit with a 503 before any upstream dial, so no fd
leak — and bounded un-parsed downstream bytes at 1 MiB.
note: the downstream read already had a timeout via the poll loop +
expireTimedOutStreams, so the agent-flagged "no read timeout" wasalready mitigated; the real gaps were the unbounded buffers, fixed here.
tests
admitConnection sheds load at the connection capdecodeInteger rejects a value above the capdecodeHeaderBlock rejects too many headersupdateMaxSize clamps a peer's oversized table-size updateverification
YOQ_SKIP_SLOW_TESTS=1 zig build test— 2239 passedtools/panic_audit.shclean;zig fmt --checkcleanunaffected)