# DF-4151 — Unvalidated RISC-LRAM `free_q_head` selects the sense DMA bus address (write-side twin of DF-2412)

File: `sys/dev/disk/advansys/advlib.c` (pass 2)

## Reproduced?

**No — hardware-gated.** The QEMU audit guest (DragonFly 6.5-DEVELOPMENT
X86_64_GENERIC) has no AdvanSys HBA: `pciconf -l` shows only i440fx/PIIX4,
virtio-net, virtio-blk and a virtio VGA (chip 0x1111:1234); no 0x10cd/0xCD
AdvanSys device and no `adv` driver attachment in dmesg (see `env.txt`).
The defect is established at source level.

## Source trace

`adv_send_scsi_queue()` (`sys/dev/disk/advansys/advlib.c:1700-1727`) reads the
free-queue head from firmware-shared LRAM and uses it directly as a queue
index:

```c
1709:  free_q_head = adv_read_lram_16(adv, ADVV_FREE_Q_HEAD_W) & 0xFF;   /* u8: 0..255 */
1710:  if ((next_qp = adv_alloc_free_queues(adv, free_q_head, n_q_required))
1711:      != ADV_QLINK_END) {
1712:          scsiq->q1.q_no = free_q_head;
1719:          scsiq->q1.sense_addr = adv->sense_physbase
1720:              + ((free_q_head - 1) * sizeof(struct scsi_sense_data));
```

The DMA sense arena is allocated for exactly `max_openings` sense slots:
`advansys.c:1345` (`sizeof(struct scsi_sense_data) * adv->max_openings` tag)
and `advansys.c:1363-1366` (load of the same size; `sense_physbase` is the
bus address of `adv->sense_buffers`). `max_openings` is clamped to
`ADV_MAX_TOTAL_QNG` = 240 (`advansys.c:843-852`), so the arena is at most
`32 * 240 = 7680` bytes.

Invariant required for safety: `free_q_head ∈ [1, max_openings]`. Nothing
enforces it:

* `free_q_head == 0` → `sense_addr = sense_physbase - 32`: the RISC engine
  DMAs CHECK-CONDITION sense data **32 bytes below the allocation**.
* `free_q_head > max_openings` (up to 255) → `sense_addr` up to
  `sense_physbase + 254*32 = +8128`, i.e. up to ~448 bytes **past the end**
  of a 7680-byte arena (proportionally more headroom for smaller
  `max_openings`; e.g. a 16-slot INRAM config (512 bytes) gives a 7.6 KB
  window past the end).

`adv_alloc_free_queues()` (`advlib.c:1669-1698`) only follows FWD links and
returns `ADV_QLINK_END` when the head slot has `QS_READY` set — it never
range-checks the head value itself. The companion read-side index
(`adv->sense_buffers[q_no - 1]` in `advansys.c:1185-1186`) is the already
filed DF-2412; this is the *write-side* (DMA target address) twin at a
different site in a different file, with a strictly stronger primitive
(32+ bytes of device-written data at a corrupted bus address vs. a
read-only struct copy).

The DMA length is separately unclamped (`q1.sense_len = csio->sense_len`,
DF-1546), so the write length is also attacker-of-firmware-chosen up to 255.

## Threat model / preconditions

Same trust model already accepted by this audit for DF-2412 / DF-2414: the
value lives in RISC-maintained LRAM, so the trigger is (a) a firmware bug or
LRAM desync (e.g. queue-state corruption after hostile-target-induced
malfunction — the mechanism DF-2414 documents), or (b) a genuinely hostile
HBA. The guest has no such HBA, so no runtime trigger is possible here.
Impact if triggered: device-DMA write of sense bytes into kernel heap
adjacent to `sense_buffers` — memory corruption (bounded window, partially
attacker-influenced content via a hostile target's sense data).

## Verdict

INCONCLUSIVE (hardware-gated / not reachable on the audit guest). Source
defect is real and certain; exploitability requires AdvanSys ASC hardware
with corrupted firmware queue state. Severity Low (hardware-gated,
firmware-trust precondition), same tier as DF-2412.

## 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.
