litespeedtech / litespeedtech/ls-qpack
Decoder accepts a Sign bit of 1 when Required Insert Count is 0 (RFC 9204 §4.5.1.2 MUST)
Nobody has claimed this yet.
- Dominant language
- C
- Stars
- 86
- Forks
- 36
- PR merge metrics
- No merged PRs in 30d
Description
# Decoder accepts a Sign bit of 1 when Required Insert Count is 0 (RFC 9204 §4.5.1.2 MUST)
**Version:** 2.7.0 (`9156770`); the relevant code is unchanged back through at least 2.6.x.
## Summary
`lsqpack_dec_read_header` accepts an encoded field section whose prefix has the Delta Base Sign bit set to 1 while the Required Insert Count is 0. RFC 9204 §4.5.1.2 requires:
> An endpoint MUST treat a field block with a Sign bit of 1 as invalid if the value of Required Insert Count is less than or equal to the value of Delta Base.
When Required Insert Count is 0, every non-negative Delta Base satisfies `RIC <= Delta Base`, so a Sign bit of 1 is always invalid. The decoder returns success instead.
## Mechanism
In the prefix state machine (`lsqpack.c`, `PREFIX_STATE_READ_DELTA_BASE_IDX`), the Sign bit is only consulted when a dynamic-table reference was signalled (`HBRC_LARGEST_REF_SET`). With Required Insert Count 0 the `else` branch runs and sets the base unconditionally, discarding `DELB.sign`:
```c
case PREFIX_STATE_READ_DELTA_BASE_IDX:
r = lsqpack_dec_int(&buf, end, prefix_bits, &DELB.value, &DELB.dec_int_state);
if (r == 0)
{
if (read_ctx->hbrc_flags & HBRC_LARGEST_REF_SET)
{
if (DELB.sign)
read_ctx->hbrc_base_index =
ID_MINUS(read_ctx->hbrc_largest_ref, DELB.value + 1);
else
read_ctx->hbrc_base_index =
ID_PLUS(read_ctx->hbrc_largest_ref, DELB.value);
}
else /* Sign bit is never checked here */
read_ctx->hbrc_base_index = 0;
...
```
## Reproduction
Each of these field sections is accepted (verified with the decoder returning `:scheme: https`); RFC 9204 §4.5.1.2 requires each to be rejected. Byte 1 is Required Insert Count = 0; byte 2 has the Sign bit (0x80) set with the low 7 bits carrying Delta Base; the remainder is a well-formed representation (`0xd7` = Indexed Field Line, static table entry 23, `:scheme: https`).
```
00 80 d7
00 81 d7
00 87 d7
00 fe d7
00 ff 00 d7 (Delta Base spelled with a continuation octet)
00 ff 49 d7
```
## Note
Found by a differential decoding oracle run against a third-party HTTP/3 implementation; every other divergence it surfaced adjudicated in ls-qpack's favor or was a deliberate layering choice on our side. This is the one that came out the other way. Reporting it upstream as a courtesy — we do not depend on ls-qpack directly.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in lsqpack.c at the PREFIX_STATE_READ_DELTA_BASE_IDX state and compare the Required Insert Count zero path with RFC 9204 §4.5.1.2. Use the listed byte sequences as reproductions; done means each field section with Sign bit 1 and Required Insert Count 0 is rejected rather than decoded successfully.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- c
- Domain
- networking
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 76/100