Skip to content

[rust] use saturating arithmetic in DNS record length checks#6748

Open
winstoncrooker wants to merge 1 commit into
cloudflare:mainfrom
winstoncrooker:fix-dns-parse-overflow
Open

[rust] use saturating arithmetic in DNS record length checks#6748
winstoncrooker wants to merge 1 commit into
cloudflare:mainfrom
winstoncrooker:fix-dns-parse-overflow

Conversation

@winstoncrooker
Copy link
Copy Markdown

While reading through src/rust/api/dns.rs I noticed the bounds checks added in #6311 use unchecked addition between an attacker-supplied length (parsed via usize::from_str_radix from a hex token in the DNS record) and a small offset. With -Cdebug-assertions=n in release builds (per .bazelrc), a length value of usize::MAX makes length + offset wrap to a small integer, the > input.len() check passes, and the subsequent slice/index panics — the exact behavior the test commentary above the malformed-input block says we want to avoid ("these previously caused panics (index out of bounds) which would abort the process via CXX. They must return Err, not panic.").

The fix is one token per check site: length + offsetlength.saturating_add(offset). Saturated overflow at usize::MAX is always greater than data.len(), so the existing Err branch fires.

Sites changed

Function Line Length field
parse_replacement ~98 hex frame length
parse_caa_record ~170 prefix_length
parse_naptr_record ~247 flag_length
parse_naptr_record ~256 service_length
parse_naptr_record ~265 regexp_length

Tests

Five new tests in dns.rs::tests, mirroring the existing test_parse_*_too_short_* / _truncated_at_* cases but with FFFFFFFFFFFFFFFF (or its decimal form for CAA) as the length token:

  • test_parse_replacement_length_overflow
  • test_parse_caa_record_prefix_length_overflow
  • test_parse_naptr_record_flag_length_overflow
  • test_parse_naptr_record_service_length_overflow
  • test_parse_naptr_record_regexp_length_overflow

Each one panics on main and passes with this patch. I ran them in a standalone Cargo crate that mirrors the function bodies (the workerd build is bazel-only, but the math is identical in isolation); CI will run the in-tree versions via bazel test //src/rust/....

Reachability note

The whole-process impact is mitigated by jsg::catch_panic wrapping #[jsg_method] calls — a slice panic in parse_replacement is caught and surfaces as throw_internal_error + terminate_execution() on the calling isolate, not a workerd-wide abort. So in practice this is a per-request failure on Workers that call dns.resolveNaptr / dns.resolveCaa with attacker-influenced hostnames, not a tenant-isolation bug. Still seems worth fixing both because the test commentary explicitly forbids panicking here and because future callers outside the jsg catch boundary would lose that protection.

The bounds checks added in cloudflare#6311 use unchecked addition between an
attacker-supplied length (parsed via `usize::from_str_radix` from a hex
token) and a small offset. With overflow-checks disabled in release
builds, a length value of `usize::MAX` makes `length + offset` wrap to
a small integer. The bounds check then passes and the subsequent
`input[start..end]` slice (or `data[i]` index) panics — exactly the
process-abort behavior cloudflare#6311 was meant to prevent (per the test
commentary at the top of the malformed-input block in dns.rs).

Switch each affected check to `saturating_add` so an overflowing length
saturates at `usize::MAX`, which is always greater than `data.len()`,
firing the existing `Err` branch as intended.

Affected sites: `parse_replacement` (~line 98), `parse_caa_record`
(~line 170), and the flag / service / regexp length checks in
`parse_naptr_record` (~lines 247, 256, 265).

Five new tests in `dns.rs::tests` mirror the existing
`test_parse_*_too_short_*` cases but use `FFFFFFFFFFFFFFFF` (or its
decimal form for CAA) as the length token. They panic on `main` and
pass with this patch.
@winstoncrooker winstoncrooker requested review from a team as code owners May 10, 2026 23:58
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 10, 2026

All contributors have signed the CLA ✍️ ✅
Posted by the CLA Assistant Lite bot.

@winstoncrooker
Copy link
Copy Markdown
Author

I have read the CLA Document and I hereby sign the CLA

github-actions Bot added a commit that referenced this pull request May 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant