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)
PoC verification
Evidence pack
findings/poc/DF-3708 Β· 9 files| File | Type | Description | Size | |
|---|---|---|---|---|
| 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
fixedfix.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
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.
No comments yet.