Commit bac7789
committed
Fix: Configured DNS64 prefixes longer than /96 trigger out-of-bounds synthesis write
=== Summary
A configured `dns64Prefixes` entry with an IPv6 mask longer than `/96` is accepted during initialization and later used for AAAA synthesis. During synthesis, the code writes four IPv4 bytes starting at `n/8` within a 16-byte IPv6 buffer. For `/104`, that start offset is `13`, so the final write hits index `16` and panics, allowing request-triggered denial of service.
=== Provenance
This finding was reproduced from a verified report and validated against the current code path. Reproduction and patching were prepared as part of a Swival Security Scanner workflow: https://swival.dev
=== Preconditions
- `dns64Prefixes` contains an IPv6 CIDR with prefix length greater than `/96`
=== Proof
`PluginDNS64.Init()` parses configured prefix strings and appends them to `plugin.pref64` without bounding the prefix length. `PluginDNS64.Eval()` later iterates those prefixes and calls `translateToIPv6()` when synthesizing AAAA answers from A records.
In `translateToIPv6()`, the code derives:
```go
ipShift := n / 8
```
It then writes four IPv4 bytes into a 16-byte IPv6 slice:
```go
for i := 0; i < 4; i++ {
ipv6[ipShift+i] = ip4[i]
}
```
For `64:ff9b::/104`, `n == 104`, so `ipShift == 13`. The loop writes indices `13`, `14`, `15`, and `16`; index `16` is out of bounds for a 16-byte slice and causes:
```text
runtime error: index out of range [16] with length 16
```
This is reachable from a request path because AAAA synthesis is invoked when an AAAA query lacks native AAAA answers but has A answers, and the relevant plugin and listener execution paths do not recover from panics.
=== Why This Is A Real Bug
The crash condition depends only on valid configuration input and normal request traffic. Once a too-long DNS64 prefix is configured, a matching synthesis path causes a deterministic panic in live request handling. Because the surrounding execution path lacks panic recovery, the process terminates, producing denial of service.
=== Fix Requirement
Reject configured DNS64 prefixes whose mask length exceeds `/96` before storing them for synthesis.
=== Patch Rationale
The patch adds validation in `PluginDNS64.Init()` to refuse any configured IPv6 CIDR with prefix length greater than `/96`. This enforces the invariant required by `translateToIPv6()` and prevents unsafe offsets from ever reaching synthesis logic, preserving existing behavior for valid DNS64 prefixes.
=== Residual Risk
None
=== Patch
Patched in `003-configured-prefixes-can-trigger-out-of-bounds-synthesis-writ.patch`.
Key change in `dnscrypt-proxy/plugin_dns64.go`:
- validate parsed IPv6 CIDRs during initialization and reject entries with prefix lengths greater than `/96` before appending to `plugin.pref64`1 parent 4a3c8a0 commit bac7789
1 file changed
+3
-0
lines changed| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
52 | 52 | | |
53 | 53 | | |
54 | 54 | | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
55 | 58 | | |
56 | 59 | | |
57 | 60 | | |
| |||
0 commit comments