adw_intr walks device-fed 32-bit completion tokens (areq_ba/next_ba) through unchecked acbbotov/carrierbotov pointer arithmetic β OOB kernel read/write and interrupt livelock
Summary
The RISC-written carrier fields are converted to acb/carrier pointers by raw base+offset macros with no bounds or alignment validation; a token outside the allocations yields wild kernel pointers that are then read from (ccb=acb->ccb, callout_stop) and written through (free_carrier->next_ba, adwfreeacb LIST_REMOVE/SLIST_INSERT_HEAD planting the forged acb on the free list). The unbounded while on the device-fed DONE bit additionally permits interrupt livelock. Buggy/compromised Advansys firmware or PCIe/DMA attacker: 32-bit-steerable (areq_ba, +4GiB) and 28-bit-steerable (next_ba) kernel memory corruption. Same threat class as the accepted narrow-sibling findings - the wide driver's CAM-layer instance missed in pass 1 behind the macro arithmetic. Validate-both-tokens fix.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-4307 Β· 5 files| File | Type | Description | Size | |
|---|---|---|---|---|
| VERDICT.md | β | 3.9 KB | β raw | |
| README.md | β | 347 B | β raw | |
| fix.diff | β | 1.7 KB | view raw | |
| manifest.json | β | 195 B | view raw | |
| verdict.json | β | 4.2 KB | view raw |
DF-4307 evidence pack
Source-level finding against sys/dev/disk/advansys/adwcam.c β hardware-gated (guest/QEMU has no Advansys HBA; pciconf shows no vendor 10cd). No runnable PoC exists without the device. See VERDICT.md for the full path:line proof and fix.diff for the validated-shape fix (patch -p1 apply-verified, never applied to sys/).
DF-4307 β adw(4) unvalidated device-fed completion tokens β OOB kernel pointers (adw_intr response-queue walk)
File: sys/dev/disk/advansys/adwcam.c β severity Medium (device/DMA-gated
kernel memory corruption), bucket memcorrupt, confidence certain (source).
Root cause (path:line)
adw_intr() walks the RISC-produced response queue and converts two
device-written 32-bit carrier fields directly into kernel pointers with
zero validation:
-
sys/dev/disk/advansys/adwcam.c:1280acb = acbbotov(adw, adw->responseq->areq_ba);acbbotov(adwlib.h:773-777) is literally(struct acb *)((caddr_t)adw->acbs + byteoffset)β a raw u32 added to the ACB array base. The legitimate token is the byte offset the driver placed inscsi_req_bo(adwlib.h:399-408 documents the firmware copies it back intoareq_ba); nothing constrains the value the DMA memory actually contains at interrupt time. -
sys/dev/disk/advansys/adwcam.c:1288-1289adw->responseq = carrierbotov(adw, free_carrier->next_ba & ADW_NEXT_BA_MASK);carrierbotov(adwlib.h:800-804) =(carriers + byte_offset), no bounds check; the 28-bit masked device value can point up to ~256 MiB past the carrier array.
Consequences once either pointer goes wild:
adwcam.c:1290free_carrier->next_ba = ...β 4-byte write through the unvalidated response-queue pointer (value = a small in-ring offset).adwcam.c:1294-1295ccb = acb->ccb; callout_stop(ccb->ccb_h.timeout_ch);β wild-pointer reads + callout manipulation through an acb up to +4 GiB fromadw->acbs.adwcam.c:1296-1332βacb->queuefield reads,bus_dmamap_unloadonacb->dmamap, thenadwfreeacb(adw, acb)(adwcam.c:128-144) which doesLIST_REMOVE(&acb->ccb->ccb_h, ...)andSLIST_INSERT_HEAD(..., acb, ...)β writes through both wild pointers, planting the forged acb on the driver's free list for reuse.adwcam.c:1264loop condition readsresponseq->next_baon every iteration of an unboundedwhileβ a device-fed self-referential DONE ring livelocks the interrupt handler (DoS), and each OOB hop keeps readingnext_bafrom whatever kernel memory it lands in.
Bounds that should hold (and don't):
areq_ba < adw->num_acbs * sizeof(struct acb) (aligned);
(next_ba & ADW_NEXT_BA_MASK) < (max_acbs + ADW_NUM_CARRIER_QUEUES + 1) *
sizeof(struct adw_carrier) (16 bytes each, adwmcode.h:106-113).
Threat model
The token fields are produced by the Advansys RISC firmware / any PCI device
able to DMA into the carrier rings: buggy firmware, a compromised HBA, or a
Thunderbolt/PCIe attacker. The narrow-driver sibling of this exact class was
already accepted (DF-2412/DF-2413/DF-2414 ccb_infos[] walk; DF-4151
free_q_head sense DMA). This is the wide driver's completion-queue
instance, which pass 1 missed because it lives behind macro pointer
arithmetic in the CAM-layer file.
Reproduction
Hardware-gated: requires an Advansys PCI HBA (ABP[3]940UW/950UW/3940U2W,
PCI IDs 10cd:2300/2500/2700). The audit guest has no such device
(pciconf -l | grep 10cd β empty; QEMU has no Advansys emulation), and the
RISC must be made to emit a bad token. Source-level certainty only β
status untested. (Simple harnesses of acbbotov pointer arithmetic would
be tautological; no meaningful harness exists without the device or a full
bus_dma/CAM stub of adw_intr.)
Fix
fix.diff β validate both tokens against the allocations before conversion;
on violation, log + adw_reset_bus() + abandon the walk (the rings are
rebuilt by recovery). patch -p1 apply-verified.
Fix status (batch validation)
Applied with the 36 sibling fix.diffs of this batch in findings/poc/_batch41/all_fixes.patch; single in-guest make -j6 nativekernel KERNCONF=X86_64_GENERIC completed RC=0 with zero errors under -Werror (full log: findings/poc/_batch41/fix_build8.log). Behavior A/B intentionally skipped for this Info-tier item.
Fix verification
not_testablefix.diff authored against the read-only sys/ tree (patch -p1 apply-verified); cannot be runtime-tested without Advansys hardware.
findings/poc/DF-4307/fix.diff
Confirmed kernel references
- sys/dev/disk/advansys/adwcam.c:1264
- sys/dev/disk/advansys/adwcam.c:1280
- sys/dev/disk/advansys/adwcam.c:1288
- sys/dev/disk/advansys/adwcam.c:1290
- sys/dev/disk/advansys/adwcam.c:1294
- sys/dev/disk/advansys/adwcam.c:1295
- sys/dev/disk/advansys/adwcam.c:1332
- sys/dev/disk/advansys/adwcam.c:133
- sys/dev/disk/advansys/adwcam.c:142
- sys/dev/disk/advansys/adwlib.h:773
- sys/dev/disk/advansys/adwlib.h:800
- sys/dev/disk/advansys/adwlib.h:399
- sys/dev/disk/advansys/adwmcode.h:106
Detail
Exploit chain
Compromised/buggy Advansys HBA firmware (or PCIe DMA attacker) completes a carrier with areq_ba = u32 of its choice -> acb = adw->acbs + u32 -> OOB read of acb->ccb gives a near-arbitrary kernel pointer ccb -> callout_stop(ccb->ccb_h.timeout_ch) and adwfreeacb write through it (forged acb inserted on the driver free list for reuse) -> kernel memory corruption with a 4GiB-range, 32-bit-steerable offset from a known DMA-coherent allocation; device-fed next_ba gives a second, 28-bit-steerable OOB write. Device-gated: no unprivileged-software-only route.
Evidence (decisive lines)
findings/poc/DF-4307/VERDICT.md (path:line trace); the two unchecked inline conversions adwlib.h:773-777 and :800-804; sinks adwcam.c:1290/1294-1295/1332->133/142; guest hardware probe NO_ADVANNSYS in DF-4310 env session
PoC changes
No seed PoC (finding new in pass 2). No executable PoC possible without Advansys hardware; pack documents the source-level proof and the bounds-check fix.
Verified recommended fix
Validate areq_ba against num_acbs*sizeof(struct acb) (with alignment) and next_ba against the carrier allocation size in adw_intr before acbbotov/carrierbotov; on violation reset the bus and abandon the walk β see fix.diff.
Verdict
Source-certain, hardware-gated. adw_intr() converts two device-written 32-bit carrier fields into kernel pointers with no validation: acbbotov(adw, responseq->areq_ba) at adwcam.c:1280 (acbbotov = acbs + raw u32, adwlib.h:773-777) yields the 'struct acb ' that is then read (ccb = acb->ccb, queue fields), passed to callout_stop (adwcam.c:1295) and WRITTEN via adwfreeacb's LIST_REMOVE/SLIST_INSERT_HEAD (adwcam.c:133/142); carrierbotov(free_carrier->next_ba & ADW_NEXT_BA_MASK) at adwcam.c:1288-1289 (adwlib.h:800-804) advances responseq up to ~256MiB past the carrier array and adwcam.c:1290 writes free_carrier->next_ba through it (4-byte OOB write). The unbounded while at adwcam.c:1264 on the device-fed DONE bit additionally permits interrupt-context livelock. Trigger requires the Advansys RISC (buggy firmware, compromised HBA, or PCIe/DMA attacker) to emit a token outside [0, num_acbssizeof(struct acb)) / outside the carrier allocation β the exact threat class of accepted sibling findings DF-2412/2413/2414 (narrow driver ccb_infos walk) and DF-4151 (free_q_head sense DMA), here in the wide driver's CAM-layer completion path, which pass 1 missed behind the macro pointer arithmetic. No runtime reproduction possible: the audit guest has no Advansys PCI device (pciconf -l has no 10cd vendor; QEMU has no Advansys emulation) and the primitive needs device-issued DMA values; a userspace harness of the macros would be tautological. Bounds-check fix authored (fix.diff, patch-apply verified).
No comments yet.