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

Scatter/gather list heap overflow via unchecked sglist_cnt in amdexecutesrb

Summary

When SCSI I/O CCB carries CAM_SCATTER_VALID|CAM_SG_LIST_PHYS amd_action hands pcsio->sglist_cnt straight to amdexecutesrb which copies that many 8-byte scatter/gather entries into fixed-size srb->SGsegment[AMD_NSEG] array with no bounds check. AMD_NSEG only 33 but sglist_cnt is user-controlled u_int16_t (up to 65535) so any value > 33 overflows amd_srb object and corrupts adjacent entry in contiguous SRB_array[256]. SGcount=nseg truncates to u_int8_t so e.g. sglist_cnt=256 silently becomes SGcount=0 after 256-entry overflow already happened. bus_dmamap_load path safe (dmat nsegments=AMD_NSEG) but SG_LIST_PHYS path bypasses bus_dma. Attacker: local /dev/passN CAMIOCOMMAND XPT_SCSI_IO CAM_SCATTER_VALID|CAM_SG_LIST_PHYS sglist_cnt>33. Impact: kernel memory corruption privilege escalation.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-2424 Β· 6 files
FileTypeDescriptionSize
VERDICT.md verdict gate analysis + source trace + exploit-chain stop reason 2.8 KB ↓ raw
fix.diff suggested-fix reject pcsio->sglist_cnt > AMD_NSEG at the CAM_SG_LIST_PHYS call site (CAM_PROVIDE_FAIL) 758 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) 478 B view raw
run.sh run-log prints the gate proof 464 B view raw
VERDICT.md verdict gate analysis + source trace + exploit-chain stop reason
↓ download raw

DF-2424 β€” amd.c scatter/gather list heap overflow via unchecked sglist_cnt

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

Classification: not_reproduced / HW-gated / impact=none. No AMD 53c974 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 amdexecutesrb() of the amd(4) SCSI HBA driver (sys/dev/disk/amd/amd.c, AMD 53c974). The guest has no AMD SCSI HBA (pciconf -l: no 0x1022/0x2020) and the amd module is not loaded. The CAM_SCATTER_VALID|CAM_SG_LIST_PHYS path is in a dead SIM. The trigger would also need a /dev/passN on an amd bus with a crafted CCB; the only pass0 here is on the PIIX3 ata-cam bus, served by a different SIM.

Gate proof (this guest):

$ kldstat              ->  kernel, ehci.ko, xhci.ko   (no amd)
$ pciconf -l           ->  no AMD 53c974 / no SCSI HBA at all
$ camcontrol devlist   ->  only QEMU DVD-ROM (pass0) on PIIX3 ata-cam, not amd

The source bug (real, cited path:line)

sys/dev/disk/amd/amd.c: - #define AMD_NSEG (btoc(MAXPHYS) + 1) (sys/dev/disk/amd/amd.h:99; MAXPHYS=128KiB β†’ AMD_NSEG = 33) and struct amd_sg SGsegment[AMD_NSEG]; (amd.h:170) β€” a fixed 33-entry SG array inside each SRB. - In amd_action, the CAM_SCATTER_VALID|CAM_SG_LIST_PHYS branch hands pcsio->sglist_cnt (a user-controlled u_int16_t, up to 65535) straight to amdexecutesrb(pSRB, segs, pcsio->sglist_cnt, 0) (amd.c:455). - amdexecutesrb copies that many 8-byte amd_sg entries into the fixed srb->SGsegment[AMD_NSEG] array via sg = srb->pSGlist; sg++; (amd.c:311-318), with no bounds check. Any sglist_cnt > 33 overflows the SRB object and corrupts the contiguous SRB_array[256]. - srb->SGcount = nseg; (:328) truncates nseg to u_int8_t, so e.g. sglist_cnt=256 becomes SGcount=0 after the 256-entry overflow already happened. The bus_dmamap_load path is safe (buffer_dmat nsegments=AMD_NSEG, amd.c:2297), but the CAM_SG_LIST_PHYS path bypasses bus_dmamap_load.

Attacker model (per finding): local user issuing CAMIOCOMMAND XPT_SCSI_IO with CAM_SCATTER_VALID|CAM_SG_LIST_PHYS and sglist_cnt > 33 through a /dev/passN on an amd bus.

Exploit chain

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

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

fix.diff rejects pcsio->sglist_cnt > AMD_NSEG at the CAM_SG_LIST_PHYS call site (CAM_PROVIDE_FAIL + xpt_done). Validated in the combined nativekernel build (fix_build.log).

Reproduce

No runnable PoC on this guest (no amd 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-2424/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-2424/{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 > AMD_NSEG at CAM_SG_LIST_PHYS call site (CAM_PROVIDE_FAIL). Full git-apply-able diff in findings/poc/DF-2424/fix.diff.

Verdict

NOT REPRODUCED β€” HW/permission gated on this guest. The bug is REAL in source (traced line-by-line). amd.c scatter/gather list heap overflow via unchecked sglist_cnt; no AMD 53c974 HBA, module not loaded, no amd-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.