# DF-3690 VERDICT

**Status: reproduced** (panic; deterministic kernel heap corruption from one
crafted disk; no user interaction beyond presenting the disk).

## How it was reproduced
1. Built a 128 MB raw disk image whose last-17-sector Adaptec metadata block
   (`ADP_LBA = total_secs - 17 = 262063`) is an otherwise-valid Adaptec
   HostRAID header (`magic_0`/`magic_3` raw compares pass, `generation` = 1
   big-endian, `configs[0].type = ADP_T_RAID0`) with
   `configs[0].total_disks = be16(60000)`.
2. Attached it as `ata0-master` (QEMU `ide.0` unit 0, bootindex deferred to
   the virtio system disk) and booted the unmodified guest kernel
   (DragonFly 6.5-DEVELOPMENT, X86_64_GENERIC, ataraid compiled in).
3. The kernel parsed the metadata during `ata_raid_subdisk_attach` and
   panicked immediately:

```
panic: vm_fault: fault on stack guard, addr: 0xfffff8008df60000
vm_fault() at vm_fault+0x12eb
trap_pfault() at trap_pfault+0x9a
trap() at trap+0x17c
calltrap() at calltrap+0x9
--- trap 000000000000000c, rip = ffffffff8033330b ---
ata_raid_subdisk_attach() at ata_raid_subdisk_attach+0x42b
device_doattach() at device_doattach+0x3af
Debugger("panic")
```

## Why it happens (path:line)
- `sys/dev/disk/nata/ata-raid.c:1704` — `raid->total_disks =
  be16toh(meta->configs[0].total_disks)`; u_int16_t, no bound vs MAX_DISKS=16.
- `sys/dev/disk/nata/ata-raid.c:1703` sets `raid->generation` from metadata
  *before* `sys/dev/disk/nata/ata-raid.c:1716` tests it, so the "clear out any
  old info" loop at `:1717-1720` executes on the very first parse of a fresh
  array slot (the historical "second disk / higher generation" framing is not
  even needed).
- The loop body writes `raid->disks[disk].dev = NULL; .flags = 0` for
  `disk < 60000` — i.e. a NULL/0 write every `sizeof(struct ar_disk)` (48)
  bytes across ~2.88 MB starting inside the `kmalloc`'d `ar_softc`, through
  adjacent kernel heap, until it faults (here: a kernel stack guard page).

## Primitive characterization
Attacker-controlled **length** (2..65535 entries) of a strided zeroing write
(8-byte NULL pointer at `disks+n*48`, 4-byte zero at `disks+n*48+40`) starting
at a known offset inside a fresh kernel heap allocation. Deterministic, at
attach. In this run it manifested as a guard-page fault panic; with heap
layout control (e.g. arranging for the swept region to contain allocator
metadata or adjacent objects' pointers) this is a heap-corruption primitive
that zeroes security-relevant pointers — the *upper bound* on impact is
arbitrary-object-pointer NULLing, the *demonstrated* impact is a reliable
persistent DoS (system cannot finish booting / disk cannot attach while the
image is present). Not pushed to uid0 within this run (see notes).

## Fix validation
`fix.diff` adds (hunk at the Adaptec parser):
```c
if (be16toh(meta->configs[0].total_disks) > MAX_DISKS) {
    device_printf(parent, "Adaptec total_disks out of range\n");
    goto adaptec_out;
}
```
Baseline (unpatched): panic at boot, guest wedged in DDB.
Patched   (fix + nativekernel rebuild): `Adaptec total_disks out of range`,
no array created, guest boots to login. See `run.patched.log`.
fix_status = fixed.

## Not covered / notes
- The known pass-1 findings (DF-1173/DF-2493: disk_number/total_disks OOB in
  the *other* parsers) did not list Adaptec; its `disk_number` is computed
  from channel/unit (bounded), but its `total_disks` path is a distinct,
  16-bit-wide sink and the loop runs on the FIRST parse.
- `ata_raid_adaptec_print_meta` also loops to `be16toh(total_configs)` (u16)
  over `configs[127]` (bootverbose only) — noted, not fixed here.

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