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

arcmsr_action() invalid kfree() of bus_dmamem SRB-pool interior pointer on CAM SG error path

Summary

In the XPT_SCSI_IO scatter/gather rejection branch, the driver kfree()s an SRB obtained from arcmsr_get_freesrb() - an interior pointer of the single bus_dmamem_alloc() coherent pool - memory that never came from kmalloc(). DFly _kfree on such a pointer hits the oversized path or the zone path KKASSERTs z_Magic: INVARIANTS panic, silent slab-metadata corruption otherwise. The SRB is also permanently leaked from the srbworkingQ recycle ring (384 hits -> adapter EBUSY). Upstream FreeBSD removed this branch; the DFly port retains it. VERIFIED: userland harness modeling the exact allocator discipline - DragonFly's own slab allocator aborts with 'assertion: z->z_Magic == ZALLOC_SLAB_MAGIC' (the same check kernel _kfree performs). Fix validated on rebuilt guest kernel (make nativekernel RC=0 -Werror clean; recycle instead of free).

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-3708 Β· 9 files
FileTypeDescriptionSize
harness.c trigger-source models get_freesrb pool handout + the kfree(srb) error path; child invalid-free caught by DFly slab allocator 5.9 KB view raw
build.sh build cc -O2 -Wall -o harness harness.c 65 B view raw
run.sh run executes harness 89 B view raw
build.log log untrimmed guest build output 67 B view raw
run.log log decisive run: slab assertion on invalid free 646 B view raw
run.2.log log repeat run 646 B view raw
fix.diff fix kfree(srb) -> arcmsr_free_srb(srb) 460 B view raw
fix_build.log log patched-source kernel build log (arcmsr.c compiled -Werror clean, in-kernel + KLD) 870 B view raw
env.txt env guest uname/compiler/no-HW evidence 643 B view raw

Fix verification

fixed
baseline reproduced→ patch + rebuild →patched clean

fix.diff (kfree->arcmsr_free_srb) applied to guest /usr/src copy; arcmsr.c recompiled clean with -Werror in both the in-kernel and KLD module builds of make nativekernel (fix_build.log). Behavioral validation on hardware impossible in this guest (no Areca HBA), so fix_patched_reproduced=0 refers to on-hardware behavior only.

fix_build.log:0 'error:' count for arcmsr compile lines at log lines 7058 (kernel, -Werror) and 13902 (KLD, -Werror); patched guard visible at arcmsr.c:3069-3071 in guest tree before restore
↓ fix.diffper-fix-DF-3708

Confirmed kernel references

Detail

Exploit chain

invalid free of a 576-byte-stride interior pointer into the ~209KB SRB pool -> slab metadata corruption on production kernels (INVARIANTS panic otherwise); concrete uid=0 chain not developed (privileged-only trigger, hardware-gated driver); realistic impact is kernel panic / heap corruption on first occurrence

Evidence (decisive lines)

run.log lines: 'error-path taken: freeing srb=... (pool=... + 1728 bytes)' then 'assertion: z->z_Magic == ZALLOC_SLAB_MAGIC in _slabfree' then '[+] DF-3708 CONFIRMED'; VERDICT.md traces arcmsr.c:3013/3053-3058/4231-4233/4413 and kern_slaballoc.c:1475-1478

PoC changes

authored from scratch (no seed): harness models pool handout at SRB_SIZE strides + the exact error-branch free(); child fork so the allocator abort is observable; unbuffered stdout to keep fork buffers clean

Verified recommended fix

replace kfree(srb, M_DEVBUF) with arcmsr_free_srb(srb) in the arcmsr_action() SG error path

Verdict

arcmsr_action() XPT_SCSI_IO error path (arcmsr.c:3057) kfree()s an SRB that is an interior pointer of the bus_dmamem_alloc() coherent pool (arcmsr.c:4413/4231/4233) -- an invalid free that DFly's slab allocator rejects. The in-driver path requires an Areca HBA (absent from the QEMU guest: 0 PCI devices vendor 0x17D3), so reproduction is via a harness that replicates the exact allocator discipline: the freed interior pointer trips DragonFly's own slab check ('assertion: z->z_Magic == ZALLOC_SLAB_MAGIC in _slabfree'), the same check kernel _kfree performs (kern_slaballoc.c:1478) -- INVARIANTS panic / silent slab-metadata corruption in-kernel, plus a permanent SRB-slot leak per occurrence. Trigger is a legal CAM flag combination (CAM_SCATTER_VALID with virtual SG list), reachable via CAM pass-through (privileged) or kernel CAM clients. Upstream FreeBSD removed this branch; the DFly port retains it.