Heap overflow in cdcheckmedia via uncapped num_entries from device-supplied TOC header
Summary
cdcheckmedia() computes num_entries directly from device-supplied TOC header starting_track/ending_track (each u_char range up to 0-255) only checks num_entries<=0. Passes num_entries*sizeof(cd_toc_entry)+sizeof(ioc_toc_header) (up to 2060 bytes) as both destination-buffer bound and READ_TOC allocation length when calling cdreadtoc() against &softc->toc (buffer of only sizeof(struct cd_tocdata)=804 bytes). Malicious SCSI/USB CD device advertising ending_track-starting_track>=99 causes kernel to DMA up to ~1256 bytes past end of in-kernel TOC cache into adjacent kmalloc heap with attacker-controlled byte content. Same uncapped num_entries also drives OOB writes in leadout fixup and OOB read/writes in BCD-conversion and search loops. num_entries=(toch->ending_track-toch->starting_track)+2 can reach (255-0)+2=257 with crafted device data. cdreadtoc sets data_ptr=&softc->toc dxfer_len=len cam_fill_csio performs no bounds check. Attacker: physical access or control of SCSI/USB device (USB mass-storage gadget iSCSI LUN scsi_target LUN). Victim: SYSCAP_RESTRICTEDROOT opener (cdopen gate). cdcheckmedia runs on open() or first read(). Impact: kernel heap corruption up to ~1256 bytes attacker-controlled enabling panic DoS reliably and arbitrary kernel-memory write with heap grooming.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-2268 Β· 6 files| File | Type | Description | Size | |
|---|---|---|---|---|
| VERDICT.md | verdict | gate analysis + source trace + exploit-chain stop reason | 3.9 KB | β raw |
| fix.diff | suggested-fix | cap num_entries at nitems(softc->toc.entries)=100 | 764 B | view raw |
| fix_build.log | build-log | nativekernel rc=0 with all fixes applied (-Werror -DINVARIANTS) | 5.6 MB | β download |
| env.txt | environment | guest uname, kldstat, camcontrol devlist, /dev perms, pciconf, maxx groups | 2.7 KB | view raw |
| build.sh | build-log | documents the HW gate (no PoC binary) | 549 B | view raw |
| run.sh | run-log | prints the gate proof | 518 B | view raw |
DF-2268 β Heap overflow in cdcheckmedia via uncapped num_entries
Verdict: NOT REPRODUCED (hardware-gated) β source bug CONFIRMED real; fix.diff compiles.
Classification: not_reproduced / HW-gated / impact=none (on this guest, for an
unprivileged user). The cited memory-corruption bug is real in source and the
defense-in-depth fix.diff compiles cleanly in a full nativekernel build
(rc=0, -Werror, -DINVARIANTS).
Why not reproduced (the gate)
cdcheckmedia() runs in the cd(4) CAM peripheral, which only attaches to a
CAM-registered SCSI/ATAPI CD target. The audit QEMU guest has exactly one CAM
target β the QEMU DVD-ROM reached through the Intel PIIX3 IDE controller via
ata-cam, exposing /dev/cd0 (mode 0640 root:operator). The trigger further
requires a malicious SCSI target that returns a crafted READ TOC whose
ending_track/starting_track produce num_entries > 100. The trusted QEMU
DVD-ROM with no medium (NOT READY, Medium not present) cannot be coerced into
emitting such a TOC. The unprivileged actor maxx (uid 1001, in no privileged
group β not operator, not wheel) additionally cannot even open("/dev/cd0").
Gate proof (this guest):
$ camcontrol devlist <QEMU QEMU DVD-ROM 2.5+> at scbus1 target 0 lun 0 (sg0,pass0,cd0) $ ls -la /dev/cd0 crw-r----- root operator /dev/cd0 # maxx not in operator -> EACCES $ id maxx uid=1001(maxx) gid=1001(maxx) groups=1001(maxx)
(No /dev/ch*, no /dev/da*, no SCSI HBA β see env.txt.)
The source bug (real, cited path:line)
sys/bus/cam/scsi/scsi_cd.c:
- struct cd_tocdata cache holds 100 entries + leadout (scsi_cd.c:136-139,
softc->toc at :172).
- cdcheckmedia() computes num_entries = (toch->ending_track - toch->starting_track) + 2
(scsi_cd.c:2947) directly from the device-supplied TOC header, then guards
only num_entries <= 0 (:2949). With ending_track=255, starting_track=0,
num_entries = 257.
- toclen = num_entries * sizeof(struct cd_toc_entry) (:2952) and
cdreadtoc(periph, CD_MSF_FORMAT, ..., &softc->toc, toclen + sizeof(*toch), ...)
(:2954-2956) DMA up to 257*8 + 4 = 2060 bytes into the 804-byte softc->toc
cache β ~1256-byte heap overflow with attacker-controlled content.
- The same uncapped num_entries drives OOB writes in the leadout fixup
(softc->toc.entries[cdindex - toch->starting_track] at :2983, cdindex up to
starting_track + 256) and the BCD-conversion / search loops at :2987, :2997
(iterate num_entries - 1 = 256 times into entries[100]).
Attacker model (per the finding): control of the SCSI/USB CD device (USB mass-storage
gadget, iSCSI LUN, scsi_target LUN). Victim: a SYSCAP_RESTRICTEDROOT-ok opener
(cdopen gate). cdcheckmedia runs on open() / first read.
Exploit chain
Not developed β the primitive requires a malicious device that is absent on this guest, and the device node is not reachable by the unprivileged actor. This is the valid hard blocker "device-controlled primitive, no malicious device present": the write content is fully attacker-controlled but only a malicious SCSI target can supply it, and there is no such target here. No userspace-only path can shape the TOC the trusted QEMU DVD-ROM returns.
Fix (defense-in-depth, validated to compile)
fix.diff caps num_entries at nitems(softc->toc.entries) (=100) before the READ
TOC and the fixup/conversion loops, turning an uncapped device-driven overflow into a
clean early-out. Validated: applies cleanly and the patched scsi_da.c/scsi_cd.c
tree builds nativekernel rc=0 with -Werror -DINVARIANTS (fix_build.log).
Reproduce
No runnable PoC on this guest (no malicious CD target, /dev/cd0 not openable by
maxx). build.sh/run.sh are placeholders that document the gate; the
authoritative artifacts are env.txt (gate proof), fix.diff, and fix_build.log.
Fix verification
not_testablenot_testable: PoC cannot run on this guest (HW/permission gated). fix.diff validated to APPLY cleanly and COMPILE in full nativekernel build (rc=0, -Werror, -DINVARIANTS) alongside sibling fixes (findings/poc/DF-2268/fix_build.log).
Compile validation: nativekernel build of patched tree -> 'NK_DONE rc=0'. No runtime test possible (HW/permission gated).
Confirmed kernel references
Detail
Exploit chain
none β valid hard blocker (driver code path dead / device node root-only / no malicious device present). No unprivileged->root path.
Evidence (decisive lines)
kldstat -> kernel, ehci.ko, xhci.ko (no target driver module); pciconf -l -> no SCSI/HBA HW; camcontrol devlist -> only <QEMU QEMU DVD-ROM> (sg0,pass0,cd0) on PIIX3 ata-cam; id maxx -> uid=1001(maxx) gid=1001(maxx) groups=1001(maxx) [not operator]. Source confirmed at cited lines.
PoC changes
Created findings/poc/DF-2268/{VERDICT.md, fix.diff, manifest.json, build.sh, run.sh, env.txt, fix_build.log}. No PoC source (HW/permission gated).
Verified recommended fix
fix.diff caps num_entries at nitems(softc->toc.entries)=100. Full git-apply-able diff in findings/poc/DF-2268/fix.diff.
Verdict
NOT REPRODUCED β HW/permission gated on this guest. The bug is REAL in source (traced line-by-line). scsi_cd.c cdcheckmedia heap overflow via uncapped num_entries; /dev/cd0 present but trusted QEMU DVD-ROM cannot produce malicious TOC, maxx EACCES. Gate confirmed via kldstat (only kernel+ehci+xhci), pciconf -l (no SCSI/HBA HW), camcontrol devlist (only QEMU DVD-ROM on PIIX3 ata-cam), and id maxx (uid 1001 not in operator) for the device-node findings.
No comments yet.