You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Multiple OOB reads in DNS wire format parser — section counts, compression pointers, RDLENGTH not bounds-checked #549
I found several out-of-bounds read bugs in getdns's DNS message parsing while doing differential fuzzing against Unbound, LDNS, c-ares, and Knot DNS. They're all in the wire-to-dict parsing path. Tested on v1.7.3.
1. Heap-buffer-overflow in gldns_read_uint32() — truncated RR TTL (CWE-125)
When a DNS message header claims more RRs than actually exist in the data (e.g. ANCOUNT=1 but the answer section is truncated before the TTL field), getdns_wire2msg_dict() reads past the buffer in gldns_read_uint32() at gbuffer.h:59.
Call chain: getdns_wire2msg_dict() → _getdns_wire2msg_dict_scan() → _getdns_rr_iter2rr_dict() → _getdns_rr_iter2rr_dict_canonical() → gldns_read_uint32() — reads 4 bytes at i->rr_type + 4 which may be past the buffer end.
ASAN trace:
READ of size 4 at 0x...
gldns_read_uint32 (gbuffer.h:59)
_getdns_rr_iter2rr_dict_canonical (util-internal.c:230)
2. OOB read via compression pointer to offset 0
When a DNS name contains a compression pointer pointing to offset 0 (the beginning of the message), getdns's dname decompression follows it and can read out of bounds depending on the message structure.
So getdns returns GETDNS_RETURN_GOOD for packets where RDLENGTH claims more data than exists. c-ares, LDNS, Knot, and Unbound all reject the same wire bytes.
4. Label type validation missing
The dname decompression loop doesn't properly validate label type bytes, allowing OOB reads via unexpected label types.
Cross-implementation comparison (across all findings):
Every one of these malformed inputs is rejected by the other 4 implementations I tested. getdns is consistently the only one that accepts them.
Reproduction:
# Build with ASAN
clang -fsanitize=address -g -O0 \
-I/path/to/getdns-src/build-clangfuzz/include \
-I/path/to/getdns-src/src \
h_getdns.c -L/path/to/getdns-src/build -lgetdns -o h_getdns
# Crash on truncated RR
./h_getdns crash_truncated_ttl.bin
# ASAN: heap-buffer-overflow in gldns_read_uint32# Accept invalid RDLENGTH (other impls reject)
./h_getdns seed_71_ptr_rdlen_oob.bin
# Returns GETDNS_RETURN_GOOD instead of error
Suggested fixes:
In rr_iter_find_nxt(): return an error when rr_type + 10 + RDLENGTH > pkt_end instead of clamping
In the RR iterator: validate that enough bytes remain before reading TTL/RDLENGTH fields
In dname decompression: validate compression pointer targets and label types
Found through differential fuzzing (PathDiff v22-v23) against Unbound, LDNS, c-ares, Knot DNS.
Activity