# DF-4877 — afd_strategy(): no media-bounds check + 32-bit LBA truncation

`sys/dev/disk/nata/atapi-fd.c:258, 277-280`:

```c
u_int32_t lba;
...
lba = bp->bio_offset / fdp->sectorsize;      /* u64 offset -> u32 lba */
...
ccb[2] = lba >> 24;  ccb[3] = lba >> 16;     /* 32-bit LBA in the CDB */
ccb[4] = lba >> 8;   ccb[5] = lba;
```

* **No bounds check**: `afd_strategy()` never compares `bio_offset` (or
  the transfer end) against `fdp->mediasize`. The raw-cdev path does not
  do it either: `bounds_check_with_mediasize()` (sys/kern/subr_disk.c:1458)
  is only used by device-mapper; a raw read/write on `/dev/afd0` goes
  physio → `afd_strategy` with whatever offset the caller passes.
* **32-bit truncation**: unlike `ad_strategy()` which keeps the LBA in a
  u_int64 (`request->u.ata.lba`, ata-disk.c), the afd driver narrows the
  block number to `u_int32_t`, and ATAPI_READ_BIG/WRITE_BIG carry only 32
  LBA bits.

Net effect: any I/O at `bio_offset ≥ 2^32 * sectorsize` (2 TiB at 512B) —
which must fail as out-of-range — silently wraps onto low LBAs. A write
the caller intended for beyond-the-end (expecting EINVAL) instead lands at
`(offset/sectorsize) mod 2^32` — e.g. LBA 0..N, clobbering the start of
the medium. Floppy-class media can never legitimately reach 2 TiB, so on
an honest device every wrapped access is out-of-bounds by construction.

## Threat model

The raw device already grants full-media read/write to its opener
(typically root/operator), so this is not a privilege boundary crossing by
itself; the security-relevant delta is silent misplacement of I/O that the
kernel contractually must reject (correctness → data-integrity), matching
the "geometry lie" class of DF-4798.

## Status: untested (in situ) — requires an afd device

The audit guest has no ATAPI direct-access device (see DF-4874 pack,
`run.log`), so the wrap cannot be demonstrated on-target. The trace is
complete in source: no clamp before atapi-fd.c:258, and the CDB fields
hold at most 32 bits (atapi-fd.c:277-280).

## Fix

`fix.diff`: reject any bio that starts at/after `mediasize` or whose end
passes it (`EINVAL`) before building the CDB — mirroring
`bounds_check_with_mediasize()` semantics for the raw path.
