Unvalidated GETCOMMPREF geometry: aac_max_fib_size of zero divides by zero at attach (boot panic); sizes below the 28-byte FIB header make the unconditional header copyin overflow the undersized FIB slots
Summary
aac_check_firmware() stores (options & 0xFFFF) from the adapter mailbox into aac_max_fib_size, clamps only an upper bound, then computes aac_max_fibs_alloc = PAGE_SIZE / aac_max_fib_size: zero panics (#DE) at attach; 1..511 yields FIB slots smaller than the 28-byte struct aac_fib_header that aac_ioctl_sendfib() unconditionally copyins into the last slot - up to 27 bytes of user-controlled data past the bus_dmamem_alloc'd pool. Buggy firmware revision -> machine panics at boot when the driver attaches; malicious firmware -> user-content heap overflow adjacent to the FIB DMA pool. Clamp into [sizeof(struct aac_fib), PAGE_SIZE].
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-3821 Β· 5 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 2.3 KB | β raw | |
| VERDICT.md | β | 2.7 KB | β raw | |
| fix.diff | β | 842 B | view raw | |
| env.txt | β | 323 B | view raw | |
| verdict.json | β | 2.2 KB | view raw |
DF-3821 β aac(4) trusts the adapter-reported FIB geometry from GETCOMMPREF: zero max_fib_size panics at attach (divide by zero), sub-header sizes overflow FIB slots
- File:
sys/dev/raid/aac/aac.c - Lines: 1800-1811 (geometry), 3010-3011 (28-byte header copyin)
- Class: CWE-20/CWE-369 (unvalidated external value β divide-by-zero panic) + CWE-787 (undersized DMA heap slots overflowed by fixed-size header copy)
- Reach: attach-time only, driven by adapter mailbox data.
Analysis
aac_check_firmware() (aac.c:1800-1811):
1800: if (!aac_sync_command(sc, AAC_MONKER_GETCOMMPREF, 0, 0, 0, 0, NULL)) {
1801: options = AAC_GET_MAILBOX(sc, 1);
1802: sc->aac_max_fib_size = (options & 0xFFFF);
...
1809: if (sc->aac_max_fib_size > PAGE_SIZE)
1810: sc->aac_max_fib_size = PAGE_SIZE;
1811: sc->aac_max_fibs_alloc = PAGE_SIZE / sc->aac_max_fib_size;
Only an upper clamp exists.
options & 0xFFFF == 0(firmware returns 0 in the low mailbox word): line 1811 executesPAGE_SIZE / 0β x86 #DE β kernel panic during device attach (boot-time DoS on machines whose (buggy) card reports that).0 < max_fib_size < sizeof(struct aac_fib)(512): FIB slots are allocatedaac_max_fibs_alloc * aac_max_fib_sizebytes with eachcm->cm_fibspacedaac_max_fib_sizeapart (aac.c:1455-1476). With a sub-512 report (e.g. 64),aac_ioctl_sendfib()still does an unconditionalcopyin(ufib, cm->cm_fib, sizeof(struct aac_fib_header))(28 bytes, aac.c:3010-3011) β for the last slot of the finalaac_alloc_commands()block this writes past the end of thebus_dmamem_alloc'd FIB pool (heap/DMA memory corruption, up to 27 bytes past formax_fib_size == 1, up to 12 bytes past for 16, β¦).- Note
sc->aac_max_fibs = (options & 0xFFFF)(aac.c:1807) is likewise unvalidated but only drives an allocation size (β€ 65535 Γ ~120 bytes), not an overflow.
Both require misbehaving/compromised controller firmware β the classic device-trust precondition β but the divide-by-zero is a boot-time panic on a merely buggy firmware revision, which elevates it above pure hardening.
Verdict
inconclusive β no AAC hardware on the audit guest (see
../DF-3819/env.txt); the geometry values come from the adapter mailbox.
Source-level: certain.
VERDICT β DF-3821
Status: inconclusive (device-gated: the offending values come from the adapter's GETCOMMPREF mailbox reply; no AAC HBA on the audit guest). Source-level confidence: certain.
Proof path
aac_check_firmware()sendsAAC_MONKER_GETCOMMPREF(aac.c:1800). On success it stores(options & 0xFFFF)from mailbox 1 intosc->aac_max_fib_size(aac.c:1802) and from mailbox 3 intosc->aac_max_fibs(aac.c:1807) β 16-bit, unvalidated values produced by the controller firmware.- The only sanitization is
if (sc->aac_max_fib_size > PAGE_SIZE) sc->aac_max_fib_size = PAGE_SIZE;(aac.c:1809-1810). sc->aac_max_fibs_alloc = PAGE_SIZE / sc->aac_max_fib_size;(aac.c:1811): - zero β integer division by zero β #DE β panic in the boot/attach path (aac_attachβaac_allocβ β¦ the division happens insideaac_check_firmwarebeforeaac_alloc). - 1..511 β FIB slots smaller thansizeof(struct aac_fib).- Slot layout:
aac_alloc_commands()carvesaac_max_fibs_alloc Γ aac_max_fib_sizebytes and setscm->cm_fib = base + i*aac_max_fib_size(aac.c:1470-1476);bus_dmamem_allocsizes the whole pool accordingly (aac.c:1455). aac_ioctl_sendfib()unconditionally copies the 28-bytestruct aac_fib_headerintocm->cm_fibbefore size negotiation (aac.c:3010-3011). For the last slot of the last block this writes(28 - aac_max_fib_size)bytes beyond the allocation wheneveraac_max_fib_size < 28(and stays inside otherwise). The copyin target is the FIB slot, not user memory: heap DMA-pool overflow with fully user-controlled header bytes (the FIB header is user-supplied content), i.e. adjacent kernel heap corruption on a sub-28 report.
The FreeBSD ancestor carries the same code; this is shared-hardening plus a realistic buggy-firmware panic.
Guest evidence
No AAC controller: pciconf -l vendor scan β 0 hits, no /dev/aacd0,
driver compiled into X86_64_GENERIC but never attaches
(../DF-3819/env.txt). GETCOMMPREF cannot be answered by anything, so
the geometry values cannot be steered on this guest.
Fix
fix.diff: clamp aac_max_fib_size into
[sizeof(struct aac_fib), PAGE_SIZE] β kills both the divide-by-zero and
the sub-header slot under-sizing in one check.
Fix validation
not_testable β same hardware precondition.
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_testableCannot be exercised without an AAC controller answering GETCOMMPREF; absent on the guest. fix.diff adds the floor clamp.
fix.diff
Confirmed kernel references
Detail
Exploit chain
faulty/compromised firmware reports max_fib_size in 1..27 -> aac_ioctl_sendfib copyin writes 28 user-controlled bytes into the final slot -> up to 27 bytes past the FIB DMA pool -> adjacent kernel heap corruption.
Evidence (decisive lines)
VERDICT.md (five-step proof with line refs); fix.diff (floor clamp); ../DF-3819/env.txt (guest has no AAC hardware)
PoC changes
No seed; analysis pack (attach-time device data cannot be synthesized on the guest).
Verified recommended fix
Clamp aac_max_fib_size into [sizeof(struct aac_fib), PAGE_SIZE] after GETCOMMPREF (aac.c:1809).
Verdict
aac_check_firmware() takes sc->aac_max_fib_size directly from the adapter's GETCOMMPREF mailbox (options & 0xFFFF, aac.c:1802) and only clamps an upper bound (aac.c:1809) before dividing PAGE_SIZE by it (aac.c:1811). A zero report panics the kernel at attach (integer divide-by-zero, #DE); a report below sizeof(struct aac_fib) (512) creates FIB slots smaller than the 28-byte struct aac_fib_header that aac_ioctl_sendfib() unconditionally copyins into the last slot of the DMA pool (aac.c:3010), overflowing the bus_dmamem_alloc allocation with user-controlled bytes. Device-gated: no AAC HBA on the audit guest (no /dev/aacd0, zero matching PCI vendors), so the mailbox values cannot be produced; source analysis is certain.
No comments yet.