cd9660_ioctl's catch-all ENOTTY hides FIOSEEKDATA/FIOSEEKHOLE from cd9660 (lseek SEEK_DATA returns EINVAL) and leaves cd9660_bmap's alignment-only contract one wiring away from an unprivileged INVARIANTS panic
Summary
cd9660 is the only mainstream filesystem not wired into DragonFly's SEEK_DATA/SEEK_HOLE infrastructure: cd9660_ioctl intercepts every ioctl and returns ENOTTY except FIOGETLBA, so lseek(SEEK_DATA/SEEK_HOLE) on any cd9660 file returns EINVAL while ufs/ext2/hammer2 all dispatch to vn_bmap_seekhole. This gap is today the ONLY thing keeping cd9660_bmap's KKASSERT((loffset & (bsize-1))==0) (:76) unreachable: vn_bmap_seekhole_locked passes the raw user-supplied file offset to VOP_BMAP on its first loop iteration ('noff += bsize - noff % bsize' only aligns subsequent iterations), so wiring cd9660 up the way the other filesystems are wired would make 'lseek(fd, 1, SEEK_DATA)' - unprivileged, needing only read access to any file on a mounted ISO - panic every INVARIANTS/DEBUG kernel instantly. No impact as shipped (unreachability proven by enumeration of all seven VOP_BMAP caller classes + the ENOTTY catch-all). Latent trap + functional gap. Fix (either suffices): make cd9660_bmap tolerant (round loffset down instead of asserting - the mapping is a pure offset shift, so rounding is semantically correct); optionally wire FIOSEEK* through vn_bmap_seekhole for parity. [VERIFIED pass2: reproduced - lseek SEEK_DATA HOLE EINVAL on cd9660 vs ufs working; F40FIX wires FIOSEEKDATA HOLE through vn_bmap_seekhole, aligned and unaligned work no panic]
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-3257 Β· 6 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 261 B | β raw | |
| df3257.c | β | 674 B | view raw | |
| fix.diff | β | 1.1 KB | view raw | |
| manifest.json | β | 395 B | view raw | |
| run.log | β | 445 B | view raw | |
| verdict.json | β | 1.8 KB | view raw |
DF-3257 evidence pack
What
cd9660_ioctl ENOTTY hides FIOSEEKDATA/FIOSEEKHOLE (and the bmap KKASSERT is one wiring away)
Verdict
status=reproduced impact=none confidence=certain
See VERDICT.md for the full narrative and fix.diff for the verified fix.
Fix verification
fixedA/B complete: lseek(SEEK_DATA/SEEK_HOLE) on cd9660 now returns 0/filesize (stock: EINVAL); unaligned lseek(1,SEEK_DATA) also works with no KKASSERT panic, validating the bmap alignment companion fix.
Confirmed kernel references
Detail
Evidence (decisive lines)
VERDICT.md with path:line citations; run.log where a live demo exists; fix.diff
PoC changes
n/a
Verified recommended fix
align loffset down in cd9660_bmap; dispatch FIOSEEKDATA/FIOSEEKHOLE to vn_bmap_seekhole
Verdict
Reproduced on the stock INVARIANTS guest: lseek(fd, 0, SEEK_DATA) and SEEK_HOLE on a cd9660 file both return EINVAL (cd9660_vnops.c:226 catch-all ENOTTY) while the same calls on a UFS file return 0/58 - cd9660 is the only mainstream filesystem not wired into the SEEK_DATA/SEEK_HOLE infrastructure. The findings second half is confirmed from source: vn_bmap_seekhole_locked hands the RAW user offset to VOP_BMAP on its first iteration, so the naive wiring would reach cd9660_bmaps KKASSERT((loffset & (bsize-1))==0) at cd9660_bmap.c:76 with lseek(fd,1,SEEK_DATA). The fix wires both ioctls to vn_bmap_seekhole AND aligns the offset down inside cd9660_bmap; compiled in the F40FIX build; post-fix A/B: lseek SEEK_DATA/SEEK_HOLE on cd9660 return 0 and filesize.
No comments yet.