# DF-4876 VERDICT — afd_sense() uninitialized-stack consumption

## Status: untested in situ (hardware absent); established by line trace

## Root cause

`afd_sense()` uses three uninitialized stack structs as ATAPI response
buffers (sys/dev/disk/nata/atapi-fd.c:345-347). `ata_atapicmd()`
(sys/dev/disk/nata/ata-queue.c:188-214) sets `request->data = data`,
`request->bytecount = count`, queues, and returns `request->result`; the
nata completion path treats a successful command with a short data-in
transfer (`donecount < bytecount`) as success — no zero-fill of the
untransferred tail exists anywhere on this path (verified in ata-queue.c
and the request setup; `bzero` of `request->data` is absent).

The only field validated before use is `capabilities.page_code`
(atapi-fd.c:405). A device returning a short MODE SENSE(10) page (or a
short READ_CAPACITY / READ_CAPACITY_16 block descriptor) leaves
offsets 12-17 of `struct afd_capabilities` (heads, sectors, sector_size,
cylinders — sys/dev/disk/nata/atapi-fd.h:62-65) or the tail of the
capacity structs as stale kernel stack, which the driver then publishes as
disk geometry (atapi-fd.c:406-410, 383-384, 395-396).

## Consequences

* Kernel stack bytes are multiplied into `fdp->mediasize` /
  `d_ncylinders`/`d_secpertrack` and exposed to userland through the
  disk-info ioctls after open (atapi-fd.c:207-217) — a degraded
  (product-of-fields) stack-content leak, CWE-457.
* Garbage geometry feeds `afd_strategy()`'s `bio_offset / fdp->sectorsize`
  LBA math (atapi-fd.c:258) — misplaced raw I/O on a device whose actual
  geometry differs.
* Zero-valued garbage is caught by the existing `!mediasize` → ENXIO guard
  (atapi-fd.c:204), so this does not reopen the known DF-1945 div0 sink.

## Why untested, honestly

Triggering requires an ATAPI direct-access device that returns a short
data-in response — the audit guest cannot attach ANY afd device (QEMU 7.2
`-device help` has no ATAPI floppy; recorded in DF-4874/run.log:
"afd0 device_t is NULL"). This is a hardware-availability blocker, not a
refutation: every hop of the trace (uninitialized declaration → non-
zero-filling transport → unvalidated consumption) was verified in source.

## Fix validation

fix_status: not_testable — same hardware blocker. The fix (bzero of the
three structs before the commands, fix.diff) converts any short response
into zeros, which the driver already rejects via `!mediasize` ENXIO.

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