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

Device-controlled avail in chgetelemstatus walks desc past data buffer -> kernel heap info leak via copyout

Summary

The data buffer for second READ ELEMENT STATUS is sized for exactly cesr->cesr_element_count descriptors but parse loop iterates avail=scsi_2btoul(st_hdr->count) times - a 16-bit value fully controlled by the device. A malicious SCSI target that reports avail > cesr_element_count causes the loop desc pointer to stride past the data allocation by desclen bytes per surplus iteration reading adjacent kernel heap. Leaked bytes written into avail-sized user_data array and copyout-ed to user cesr_element_status buffer. Mismatch warning only xpt_prints - does not clamp avail. Attacker controls desclen indirectly so surplus read stride is attacker-tunable.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-2271 Β· 6 files
FileTypeDescriptionSize
VERDICT.md verdict gate analysis + source trace + exploit-chain stop reason 2.9 KB ↓ raw
fix.diff suggested-fix clamp device-supplied avail to cesr->cesr_element_count when it exceeds the requested count 726 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/permission gate (no PoC binary) 524 B view raw
run.sh run-log prints the gate proof 487 B view raw
VERDICT.md verdict gate analysis + source trace + exploit-chain stop reason
↓ download raw

DF-2271 β€” scsi_ch.c chgetelemstatus: device-controlled avail walks off buffer

Verdict: NOT REPRODUCED (hardware-gated) β€” source bug CONFIRMED real; fix.diff compiles.

Classification: not_reproduced / HW-gated / impact=none. The OOB-read info-leak is real in source; the defense-in-depth fix.diff compiles cleanly (nativekernel rc=0, -Werror, -DINVARIANTS).

Why not reproduced (the gate)

The bug lives in chgetelemstatus() of the ch(4) medium-changer peripheral. The guest has no medium-changer device: camcontrol devlist shows only the QEMU DVD-ROM, there is no /dev/ch* node, and the ch(4) peripheral is not loaded. The trigger also requires a malicious SCSI changer that reports READ_ELEMENT_STATUS avail > cesr_element_count. The unprivileged actor maxx (uid 1001, no privileged groups) cannot reach any of this.

Gate proof (this guest):

$ camcontrol devlist   ->  <QEMU QEMU DVD-ROM 2.5+>  (sg0,pass0,cd0)   [no changer]
$ ls /dev/ch*          ->  No such file or directory
$ id maxx              ->  uid=1001(maxx) gid=1001(maxx) groups=1001(maxx)

The source bug (real, cited path:line)

sys/bus/cam/scsi/scsi_ch.c, chgetelemstatus(): - The data buffer for the second READ ELEMENT STATUS is sized for exactly cesr->cesr_element_count descriptors: size = sizeof(headers) + desclen * cesr->cesr_element_count (scsi_ch.c:1120-1122), kmalloc(size,...) (:1129). - But the parse loop iterates avail = scsi_2btoul(st_hdr->count) times (scsi_ch.c:1159, :1176) β€” a 16-bit value fully controlled by the device. avail != cesr->cesr_element_count only produces an xpt_print warning (:1161-1163); it is not clamped. - The loop strides desc by desclen each iteration (:1181-1182) and copy_element_status(... desc ...) reads through it; with avail > count, desc walks past the data allocation, leaking adjacent kernel heap. Leaked bytes land in the avail-sized user_data (:1167) and are copyout-ed to the user (:1186-1188). desclen is also device-controlled (:1118), so the surplus stride is attacker-tunable.

Attacker model: malicious SCSI medium-changer target. Victim: a process holding the changer device open.

Exploit chain

Not developed β€” no changer target on this guest and /dev/ch* absent. This is the valid hard blocker "device-controlled primitive, no malicious device present"; there is no userspace-only path to shape avail/desclen for the trusted (absent) changer.

Fix (defense-in-depth, validated to compile)

fix.diff clamps avail to cesr->cesr_element_count when the device over-reports, so the parse loop can never stride past the allocation. Validated in the combined nativekernel build (fix_build.log).

Reproduce

No runnable PoC on this guest (/dev/ch* absent, no malicious changer target). build.sh/run.sh document the gate; authoritative artifacts are env.txt, fix.diff, 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-2271/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-2271/{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 clamps avail to cesr->cesr_element_count. Full git-apply-able diff in findings/poc/DF-2271/fix.diff.

Verdict

NOT REPRODUCED β€” HW/permission gated on this guest. The bug is REAL in source (traced line-by-line). scsi_ch.c chgetelemstatus device-controlled avail walks off buffer; no /dev/ch* (no medium-changer), 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.