# DF-5175 — VERDICT

**Status: `untested`** (hardware-gated; Low severity → Phase V skipped per
audit contract). Not a false positive: the defect is proven by complete
code-level trace below; only *runtime* demonstration is impossible in the
audit environment (QEMU guest has no PCMCIA controller / slot).

## Reproduced?

No. Neither a physical PCMCIA slot nor a pccard-bridge emulator exists in the
audit guest. Impact therefore recorded as `none (not demonstrated)`,
confidence `likely` (every link in the chain is source-provable; the only
empirical unknown is real-hardware window programming, which is dictated by
the ExCA/cbb window registers taking the exact CIS length).

## The chain, hop by hop

1. **CIS parse — window length is raw card bytes.**
   `sys/bus/pccard/pccard_cis.c:1074-1092`: for
   `PCCARD_TPCE_IO_RANGE_LENGTHSIZE_{ONE,TWO,FOUR}`,
   `cfe->iospace[i].length = pccard_tuple_read_{1,2,4}(tuple, idx)` then
   `length++`. Any length 1..2^32 is accepted; there is no 8/16-only
   constraint anywhere in the parser.

2. **Bus pre-allocates the window with exactly the CIS length.**
   `sys/bus/pccard/pccard.c:429-449` (`pccard_function_init`): for each CFE
   IO space, `len = cfe->iospace[i].length`;
   `bus_alloc_resource(bus, SYS_RES_IOPORT, &rid=i, start, end, len,
   rman_make_alignment_flags(len))`. Alignment is pow2-rounded **placement**;
   the resource size stays `len`. `resource_list_add` records the same length.
   Note `rid = i` — the first CIS window becomes the child's
   `ATA_IOADDR_RID (0)` resource.

3. **Child allocation returns the CIS-sized window, requested count ignored.**
   `sys/dev/disk/nata/ata-card.c:87-90` asks for `ATA_IOSIZE` (8) ports, but
   `pccard_alloc_resource` (`sys/bus/pccard/pccard.c:1121-1149`) finds the
   pre-existing `rle` for rid 0 (set in step 2) and returns `rle->res`
   verbatim — the requested `count` is never compared against the window.
   Hence `rman_get_size(io)` at `ata-card.c:103` is the **card-chosen CIS
   length**, not 8.

4. **Unvalidated offset wiring.**
   * `ata-card.c:93-96`: offsets 0..7 wired for ATA_DATA..ATA_COMMAND
     (OOB whenever CIS length < 8).
   * `ata-card.c:103-106`: `rman_get_size(io) > ATA_IOSIZE` (≥9) ⇒
     `ATA_CONTROL` at offset **14** (`ATA_PCCARD_CTLOFFSET`,
     `sys/dev/disk/nata/ata-all.h:95`). A 1-byte access at +14 is inside the
     allocation only for length ≥ 15. **CIS lengths 9..14 make every control
     access out-of-allocation.**
   * `ata-card.c:119` → `ata_default_registers()`
     (`sys/dev/disk/nata/ata-all.c:723-735`) aliases `ATA_ALTSTAT` onto the
     same `{res, offset}` — so the status-poll read path is OOB too.

5. **Sinks.** `ATA_IDX_OUTB/INB` expand to
   `bus_space_write_1/read_1(rman_get_bustag(res), rman_get_bushandle(res),
   offset, …)` (`sys/dev/disk/nata/ata-all.h:679-712`) — x86 `outb/inb` at
   `window_base+offset`, no bounds checks. Control writes happen in
   `ata_generic_reset()`/`ata_generic_command()` (ata-lowlevel.c) during
   `ata_attach` → `ATA_RESET` (`sys/dev/disk/nata/ata-all.c:128-131`), i.e.
   on the very first attach of the malicious card; status reads poll
   ATA_ALTSTAT.

6. **Reachability gate.** `ata_pccard_probe` returns 0 for any
   `PCCARD_FUNCTION_DISK` card (`ata-card.c:63-67`) — no product-table match
   needed. The driver registers on the pccard bus only (`ata-card.c:163`);
   CardBus cards use the PCI path (`ata-pci.c`) and are unaffected by this
   file's wiring.

## Why this is NOT DF-2173 (known, not re-reported)

DF-2173 = **resource leak** (io/ctlio orphaned when `ata_probe/ata_attach`
fail, ata-card.c:125-128, because newbus never calls detach after failed
attach). DF-5175 = **out-of-allocation port I/O on the success path** caused
by trusting the CIS window size when wiring register offsets. Different sink
(r_io offsets vs. resource lifetime), different trigger (CIS geometry vs.
attach failure), different code lines (93-106 vs 125-128).

## Impact ceiling (honest)

1-byte port writes with near-fixed values (control byte bits IDS/RESET/4BIT/
HOB) at `window+14`, or semi-controlled command/LBA bytes at `window+1..7`
for short windows, hitting whatever host device owns the adjacent ports.
No kernel memory is read or written; no privilege boundary is crossed by
software. Physical access required. → **Low**, hardening/robustness.

## Fix validation

Not runnable (same hardware gate). `fix.diff` fails the attach closed for
windows < 8 and only takes the shared-control-at-14 path for windows ≥ 15
(`ATA_PCCARD_CTLOFFSET + ATA_CTLIOSIZE`), both expressed with the existing
named constants. Authored against the read-only `sys/` tree; never applied
there.

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