qpack: fix heap-buffer-overflow in blocked-streams compaction#1
qpack: fix heap-buffer-overflow in blocked-streams compaction#1tc-agent wants to merge 2 commits into
Conversation
|
[CLAUDE CODE REVIEW - claude-opus-4-6] PR Review:
|
|
Update from reviewer feedback: The two checklist items raised in review have been addressed:
The Fuzz Verify CI check shows 'Coverage summary not found' — this appears to be a CI infrastructure issue (the coverage build step doesn't run for upstream fix PRs that don't include harness changes). The compilation checks (ASan/UBSan, boringssl, OpenSSL variants) all pass. |
In h2o_qpack_decoder_handle_input, when evicting newly-unblocked entries from the blocked_streams list, the source pointer passed to memmove was wrong: entries + remaining instead of entries + num_unblocked. With N entries and K unblocked entries: remaining = N - K buggy source = entries[N - K] (starts too late) correct source = entries[K] (first still-blocked entry) Reading remaining entries from the wrong offset walks past the allocated end of the array whenever K < N/2, producing a heap-buffer-overflow. Found by libFuzzer + ASan with a targeted QPACK fuzzer.
e56eb1c to
1a5e99c
Compare
|
[CLAUDE CODE REVIEW - claude-opus-4-6] [review skipped — PR_SERVER_SKIP_REVIEW=1] [CLAUDE CODE REVIEW - claude-opus-4-6] |
Fuzzing Coverage ReportTested: project Per-harness
Same harness config applied to both sides (baseline = base source + PR harness). Per-harness data from |
Summary
Heap-buffer-overflow in h2o_qpack_decoder_handle_input when compacting
the blocked-streams list after entries become unblocked.
Found by libFuzzer + AddressSanitizer using a new targeted QPACK fuzzer.
Reproduces reliably with the seed corpus after ~130 iterations.
Root Cause
h2o_qpack_decoder_handle_input (qpack.c:422-428) removes newly-unblocked
entries from the head of the blocked_streams.list by memmove-ing the
remaining entries to the front. The source pointer was computed as
entries + remaining instead of entries + num_unblocked, so the read
started too late in the array.
With N total entries and K unblocked entries (remaining = N - K):
When K < N/2, the buggy source starts past the valid buffer end, reading
remaining bytes beyond the allocated region.
Fix
Change the source offset from remaining to num_unblocked in the memmove call.
The bug has been present since commit 11041d467 (Jan 2019).