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

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)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-2268 Β· 6 files
FileTypeDescriptionSize
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
VERDICT.md verdict gate analysis + source trace + exploit-chain stop reason
↓ download 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_testable
baseline no→ patch + rebuild →patched clean

not_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).
↓ fix.diffn/a (no target HW/device on this guest)

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.