# DF-4185 VERDICT

**Status: reproduced** (impact: `panic` — kernel panic / local DoS; no memory
corruption: trap 18 is a faulting divide, not a write primitive)
Confidence: certain.

## Narrative

`acd_get_cap()` populates `cap.cur_write_speed` only inside the success branch
of its 5-attempt MODE SENSE(0x2a) loop (`atapi-cd.c:1706-1716`); on total
failure the zero-initialized softc keeps `cur_write_speed == 0` for the life
of the device. The guard `max(...,177)` everyone remembers only protects the
success path. `acd_fixate()` later computes `timeout / (cur_write_speed / 177)`
(`atapi-cd.c:1159`) — with speed 0 the divisor is 0 and the kernel takes an
integer-divide fault.

Reproduced on the audit guest with the DF-3690-family device-state emulation:
`df_audit.capfail=1` fails the capability senses at attach (hook converts every
page-0x2a MODE SENSE to EIO — the trace shows the 5 failing attempts at boot),
`df_audit.mode=1` lets the burner-only commands succeed so `acd_fixate` walks
to the division. One `ioctl(CDRIOCFIXATE)` from the trigger binary produced:

```
Fatal trap 18: integer divide fault while in kernel mode
Stopped at      acd_ioctl+0x1842:       idivl   %ecx,%eax
```

(`acd_ioctl+0x1842` = inlined `acd_fixate`; RIP 0xffffffff80340232.) The guest
went to DDB; in-flight ssh died — the honest `panic` signature. Same run also
re-captured the DF-4184 over-read sample (see `panic_serial_full.log`), which
is the full acd_fixate trace up to the trap.

## Why "panic" and nothing more

`idiv` with zero divisor raises #DE before any result is written; there is no
attacker-controlled quotient/remainder, no OOB write. Impact ceiling: local
DoS (repeatable per fixate call whenever the speed field is 0).

## Preconditions (honest)

1. All five capability-page senses fail at `acd_attach` (real-world: drive
   erroring/timing out during probe; crafted device; some USB enclosures) —
   OR any future path that leaves the field 0.
2. `CDRIOCFIXATE` callable: `/dev/acd0` is root:operator 0640 **and** the DF
   disk layer gates opens with `SYSCAP_RESTRICTEDROOT` (`subr_disk.c:1072`,
   verified live: plain operator-group user gets EPERM), so the caller is
   root/RESTRICTEDROOT software; a drive that failed cap-read at attach but
   later accepts write-param mode pages + CLOSE TRACK (burner-family behavior
   or crafted device) walks the whole path.

## Fix validation

Same emulation kernel + `fix.diff` divisor clamp, `capfail=1`, `pl=50`:
the traced sequence reaches `TEST_UNIT_READY err=5 (!= EBUSY)` — i.e. the
division executed — and the ioctl returns EIO after the normal fixate wait;
**no trap**, guest uptime clean. Baseline identical configuration = trap 18.
Logs: `panic.txt` (baseline) vs `../DF-4184/fix.2.log` (patched).

## Path references

* `sys/dev/disk/nata/atapi-cd.c:1158-1160` — the division
* `sys/dev/disk/nata/atapi-cd.c:1706-1716` — speed set only on cap-sense success
* `sys/dev/disk/nata/atapi-cd.c:144` — softc `M_INTWAIT | M_ZERO` (speed 0 default)

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