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

hpfs_bmlookup off-by-one ('lsn > su_btotal' admits lsn == su_btotal): step-1 probe reads exactly one word past the hpm_bitmap kmalloc on exact-band volumes

Summary

The volume check at :340 rejects lsn > su_btotal but admits lsn == su_btotal; valid LSNs are 0..su_btotal-1. With su_btotal an exact band multiple (attacker-chosen), i = lsn>>5 equals hpm_dbnum*BMSIZE/4 words - exactly one word past the bitmap allocation - and the probe reads 4 bytes OOB (up to 32 more reads of the same word in the k-loop). Reached from hpfs_addextent's append branch (alsubr.c:435, lsn = al_lsn+al_len, both on-disk) via a single unpriv pwrite that extends a file. VERIFIED via diagnostic kernel: 'OOB PROBE: i=512 alloc_words=512 lsn=0x4000 su_btotal=0x4000 dbnum=1' (the triggering pwrite completed normally; no disclosure path - hardening-grade). Fix validated (>=): probe never fires.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-3142 Β· 7 files
FileTypeDescriptionSize
craft_img.py β€” 4.6 KB view raw
poc.c β€” 1.3 KB view raw
probe_line.txt β€” 77 B view raw
run.log β€” 1.5 KB view raw
fix.diff β€” 301 B view raw
env.txt β€” 150 B view raw
build.log β€” 288 B view raw

Fix verification

fixed
baseline reproduced→ patch + rebuild →patched clean

Baseline: probe line proves word 512 read past a 512-word allocation. Patched: no probe line; the same pwrite-extend returns ENOSPC (OUT OF VOLUME) instead of consulting out-of-range memory.

run.log (baseline + fix sections)
↓ fix.diffDragonFly 6.5-DEVELOPMENT #2 (quickkernel with lsn>= fix)

Confirmed kernel references

Detail

Evidence (decisive lines)

['probe_line.txt / run.log: DF3142 OOB PROBE: i=512 alloc_words=512 lsn=0x4000 su_btotal=0x4000 dbnum=1', 'run.log fix section: pwrite extend = -1 (ENOSPC), zero DF3142 lines post-fix']

PoC changes

Initial image put the fnode at the last sector (0x3FFF, LSN%8==7) to use the h_no+1 call site - that tripped DF-3141's vget read-fault first (inherent: last sector of an exact-band volume is always LSN%8==7). Reworked to a page-safe fnode (0x48) whose leaf {al_off:0, al_len:2, al_lsn:0x3FFE} reaches the same OOB via the al_lsn+al_len call site (alsubr.c:435).

Verified recommended fix

hpfs_subr.c:340: change lsn > hpmp->hpm_su.su_btotal to lsn >= hpmp->hpm_su.su_btotal

Verdict

Reproduced via a one-line kernel probe in bmlookup step 1 (diag build): extending a file whose leaf satisfies al_lsn+al_len == su_btotal == 0x4000 drives i=512 against a 512-word bitmap allocation - the probe line printed i=512 alloc_words=512 lsn=0x4000. The OOB read's value only feeds a bit test/run count and downstream bmmarkbusy rejects out-of-volume results (pwrite completed normally); no disclosure or corruption path identified, so impact is 'none' beyond the OOB read itself. Fix (lsn > su_btotal -> lsn >= su_btotal) validated on the rebuilt kernel: pwrite returns ENOSPC (OUT OF VOLUME) and no probe line appears.