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

Unbounded scatter/gather copy in btexecuteccb via CAM_SCATTER_VALID CCB (kernel heap overflow)

Summary

When SCSI I/O CCB carries own scatter/gather list (CAM_SCATTER_VALID) btaction() hands csio->sglist_cnt straight to btexecuteccb() as segment count with no bound check. btexecuteccb() copies nseg segments into bccb->sg_list fixed BT_NSEG(32)-entry buffer. Only thing normally caps nseg at 32 is buffer_dmat DMA tag nsegments=BT_NSEG enforced solely inside bus_dmamap_load() but CAM_SCATTER_VALID branch bypasses bus_dmamap_load entirely. CCB via pass(4) with sglist_cnt>32 writes attacker-controlled {addr len} tuples past end of SG slot corrupting adjacent CCBs SG lists overflowing sg_map page into neighboring kernel heap.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-2428 Β· 6 files
FileTypeDescriptionSize
VERDICT.md verdict gate analysis + source trace + exploit-chain stop reason 2.8 KB ↓ raw
fix.diff suggested-fix reject csio->sglist_cnt > BT_NSEG at the CAM_SCATTER_VALID call site (CAM_PROVIDE_FAIL) 752 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) 472 B view raw
run.sh run-log prints the gate proof 461 B view raw
VERDICT.md verdict gate analysis + source trace + exploit-chain stop reason
↓ download raw

DF-2428 β€” bt.c (buslogic) unbounded scatter/gather copy

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

Classification: not_reproduced / HW-gated / impact=none. No BusLogic HBA on this guest. The SG overflow is real in source; the defense-in-depth fix.diff compiles cleanly (nativekernel rc=0, -Werror, -DINVARIANTS).

Why not reproduced (the gate)

The bug is in btexecuteccb() of the bt(4) BusLogic SCSI HBA driver (sys/dev/disk/buslogic/bt.c). The guest has no BusLogic PCI HBA (pciconf -l: no 0x104b/*) and the bt module is not loaded (kldstat: only kernel, ehci.ko, xhci.ko). The CAM_SCATTER_VALID path is in a dead SIM. The only pass0 is on the PIIX3 ata-cam bus (different SIM), so no BusLogic-attached pass device exists.

Gate proof (this guest):

$ kldstat              ->  kernel, ehci.ko, xhci.ko   (no bt/buslogic)
$ pciconf -l           ->  no BusLogic (0x104b/*) / no SCSI HBA at all
$ camcontrol devlist   ->  only QEMU DVD-ROM (pass0) on PIIX3 ata-cam, not bt

The source bug (real, cited path:line)

sys/dev/disk/buslogic/bt.c: - #define BT_NSEG 32 (sys/dev/disk/buslogic/btreg.h:40) and each CCB has a fixed bt_sg_t *sg_list of BT_NSEG entries (allocated BT_NSEG per CCB at bt.c:832-846). - In btaction, the CAM_SCATTER_VALID branch casts csio->data_ptr to a segment array and hands csio->sglist_cnt (a user-controlled u_int16_t) straight to btexecuteccb(bccb, segs, csio->sglist_cnt, 0) (bt.c:1053-1056) with no bound check. - btexecuteccb copies that many segments into bccb->sg_list via sg = bccb->sg_list; while (dm_segs < end_seg) { sg->len=...; sg->addr=...; sg++; } (bt.c:1260-1266), where end_seg = dm_segs + nseg (:1257). Any sglist_cnt > 32 writes attacker-controlled {addr,len} tuples past the end of the SG slot, corrupting adjacent CCBs / SG lists / neighboring kernel heap. - The only thing that normally caps nseg at 32 is buffer_dmat DMA tag nsegments=BT_NSEG (bt.c:618), enforced solely inside bus_dmamap_load(); the CAM_SCATTER_VALID branch bypasses bus_dmamap_load entirely.

Attacker model (per finding): local user issuing CAMIOCOMMAND XPT_SCSI_IO with CAM_SCATTER_VALID and sglist_cnt > 32 through a /dev/passN on a bt bus.

Exploit chain

Not developed β€” no BusLogic HBA, hence no bt-attached pass device. Valid hard blocker: the SIM is not instantiated on this guest.

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

fix.diff rejects csio->sglist_cnt > BT_NSEG at the CAM_SCATTER_VALID call site (btfreeccb + CAM_PROVIDE_FAIL + xpt_done). Validated in the combined nativekernel build (fix_build.log).

Reproduce

No runnable PoC on this guest (no bt HBA). Artifacts: 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-2428/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-2428/{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 rejects sglist_cnt > BT_NSEG at CAM_SCATTER_VALID call site (CAM_PROVIDE_FAIL). Full git-apply-able diff in findings/poc/DF-2428/fix.diff.

Verdict

NOT REPRODUCED β€” HW/permission gated on this guest. The bug is REAL in source (traced line-by-line). bt.c (buslogic) unbounded scatter/gather copy; no BusLogic HBA, module not loaded, no bt-attached pass. 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.