β¬’ DragonFlyBSD Kernel Audit
← triage Β· dashboard
DF-2563

Compress path heap buffer overflow via incorrect worst-case expansion bound

Summary

Input size check at :397 uses PRED1_BUF_SIZE*8/9+1+4=3645 but mathematically correct maximum guaranteeing worst-case compressed output fits in outbuf+2(4094 bytes) is 3639. For inlen=3645 with all-wrong dictionary guesses on freshly-initialized node Pred1Compress writes 4101 bytes to outbuf+2 overflowing 7 bytes past 4096-byte outbuf boundary. Overflow lands in struct padding between outbuf and stats field on x86-64 no observable effect. Overflow path write-only compressed output never sent on wire (uncompressed branch taken when len>=inlen). Off by 6 in formula producing 6 extra input bytes each adding ~1.125 output bytes = ~7 bytes overflow. [VERIFIED pass2: reproduced padding-exact - adversarial all-wrong-guess input at inlen 3645 writes exactly 7 compressed bytes landing entirely in struct padding as the finding predicted, stats intact]

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-2563 Β· 5 files
FileTypeDescriptionSize
harness.c β€” 8.2 KB view raw
build.sh β€” 91 B view raw
worstcase.h β€” 12.8 KB view raw
run.log β€” 1.3 KB view raw
run.2.log β€” 0 B ↓ download

Fix verification

not_testable
↓ fix.diffper-fix-DF-2563

Confirmed kernel references

Detail

Evidence (decisive lines)

pred1_all.log: outbuf[4096..4102] nonzero with inlen=3645; layout printout (padding); control clean at 3639

PoC changes

adversarial worst-case input generated by simulating the real hash; harness module

Verified recommended fix

bound inputs at 3639 (PRED1_BUF_SIZE - 2 - ceil((PRED1_BUF_SIZE-2)/9))

Verdict

The compress input bound (ng_pred1.c:397) is PRED1_BUF_SIZE*8/9+1+4 = 3645, but the worst-case Pred1Compress output is n+ceil(n/8) = 4101 at outbuf+2 -- 7 bytes past the 4096-byte outbuf. Verified with the REAL ng_pred1.c compiled into the harness and an adversarial 3645-byte input generated against the real HASH(x)=(Hash<<4)^x (every guess wrong, confirmed by offline simulation): the kernel log shows compressed-stream bytes at outbuf[4096..4102] (8d 8e 8f d0 d6 01...), exactly 7 bytes -- and &stats-&outbuf=4103 proves those bytes land entirely in STRUCT PADDING (sizeof(cfg)=1 alignment), leaving stats.FramesPlain intact: no observable effect, precisely as the finding itself states. Control inlen=3639: zero bytes past outbuf. Netgraph7 latent file (compiled via module; not in stock kernel config).