# 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

1. `aac_check_firmware()` sends `AAC_MONKER_GETCOMMPREF`
   (aac.c:1800).  On success it stores `(options & 0xFFFF)` from
   mailbox 1 into `sc->aac_max_fib_size` (aac.c:1802) and from mailbox 3
   into `sc->aac_max_fibs` (aac.c:1807) — 16-bit, unvalidated values
   produced by the controller firmware.
2. The only sanitization is `if (sc->aac_max_fib_size > PAGE_SIZE)
   sc->aac_max_fib_size = PAGE_SIZE;` (aac.c:1809-1810).
3. `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 inside
     `aac_check_firmware` before `aac_alloc`).
   - **1..511** → FIB slots smaller than `sizeof(struct aac_fib)`.
4. Slot layout: `aac_alloc_commands()` carves `aac_max_fibs_alloc ×
   aac_max_fib_size` bytes and sets `cm->cm_fib = base +
   i*aac_max_fib_size` (aac.c:1470-1476); `bus_dmamem_alloc` sizes the
   whole pool accordingly (aac.c:1455).
5. `aac_ioctl_sendfib()` unconditionally copies the 28-byte
   `struct aac_fib_header` into `cm->cm_fib` before 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 whenever
   `aac_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.
