Decompress path signed integer underflow from missing minimum packet size check
Summary
ng_pred1_decompress checks only upper bound on packet size (:468 inlen>PRED1_BUF_SIZE) but no minimum. When compressed frame (cf bit set in 2-byte header) has fewer than 4 bytes total expression inlen-4 at :492 underflows to negative value passed as slen to Pred1Decompress. Pred1Decompress outer loop while(slen) treats negative slen as non-zero running unboundedly bounded only by dlen=4096 reading up to ~514 bytes past inbuf into outbuf within same heap allocation thoroughly corrupting prediction dictionary. Remote PPP peer sends 2-byte compressed frame [0x80 0x00]. Dictionary desync all subsequent frames fail CRC/length checks DoS. [VERIFIED pass2: reproduced - 2-byte frame 80 00 feeds inlen-4 -2 into Pred1Decompress, kernel log shows uint16 of the -1 return proving the full 4096-iteration stale walk; dictionary desync DoS]
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-2564 Β· 5 files| File | Type | Description | Size | |
|---|---|---|---|---|
| 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_testableConfirmed kernel references
Detail
Evidence (decisive lines)
pred1_all.log mode 3 + dmesg Comp length error (0) --> len (65535); mode 4 fixed guard rejects
PoC changes
seed frame + 2-byte compressed frame through the real decompress
Verified recommended fix
reject inlen < 4 (minimum = 2 header + 2 FCS) before the compressed branch
Verdict
ng_pred1_decompress checks only the upper bound; a 2-byte compressed frame [0x80,0x00] makes inlen-4 = -2 at :492 and Pred1Decompresss while(slen) loop runs on negative slen until dlen exhaustion. REAL-code run: kernel logged ng_pred1: Comp length error (0) --> len (65535) -- len1=0xFFFF is the uint16_t truncation of the dlen-exhausted return(-1), proving the full 4096-iteration walk fed by bytes past the 2 valid input bytes (stale inbuf content); rc=EIO with stats.Errors incremented. Dictionary desync + reset-request storm for the PPP peer as filed; the walk stays inside the priv allocation (no crash).
No comments yet.