# DF-2223 — `pcie_capability_read_dword()` leaves `*dst` uninitialized on the not-implemented path

**Status: REPRODUCED (verbatim-code, kernel-compiled rig, REAL PCI devices)** —
impact class: uninitialized-stack word consumed by return-value-ignoring
consumers → driver misbehavior / possible hw mis-programming (DoS class).
**Fix: A/B-validated in the same harness kernel** (`fix.diff`, `*dst = 0`).

Part of the DF-22X batch (DF-2216 / DF-2220 / DF-2223 / DF-2224) verified in ONE
harness kernel; this pack documents the DF-2223 section.

## What this pack contains

Same layout as the DF-2216 pack; finding-specific: `fix.diff` (against
`sys/dev/drm/linux_pci.c`), `run_section.log` (DF-2223 lines).

## How to reproduce

Identical to the DF-2216 pack (same batch build + run).

## Provenance — what is REAL here

1. guest tree `linux_pci.c` sha256 `314205e0...` == audited tree;
   `pcie_capability_read_dword` compiled into the kernel **verbatim**.
2. The predicate chain is entirely real: `pcie_capability_reg_implemented`
   (`linux/pci.h:473`) → `pci_is_pcie(dev->dev.bsddev)` (real inline over the
   real `pci_get_pciecap_ptr` ivar read) and, on the implemented path,
   `pcie_flags_reg` → `pci_find_capability` → real `pci_find_extcap` +
   `pci_read_config` config-space reads.
3. The only fabricated object is a zeroed `struct pci_dev` whose `dev.bsddev`
   points at each **real guest PCI device_t** (all 7 children of pci0:
   hostb0, isab1, atapci0, none0, vgapci0, virtio_pci0/1).
4. `pcie_capability_read_dword_fixed` = same bytes + `fix.diff`, def renamed
   (`fixed_pci.c` sha256 `c0de4487...`).

## Expected output (baseline = unmodified production code)

```
DF2223 BASELINE hostb0      LNKCAP rc=-22 dst=0xa5a5a5a5 UNTOUCHED-CANARY (dst left uninitialized)
DF2223 BASELINE hostb0      pcie_get_width_cap-style consumer: lnkcap=0xa5a5a5a5 -> width=0x1a (derived from UNINITIALIZED stack)
DF2223 BASELINE hostb0      CONTROL FLAGS_TYPE rc=-22 dst=0xa5a5a5a5 (non-PCIe guest: predicate false for every reg)
DF2223 FIXED    hostb0      LNKCAP rc=-22 dst=0x00000000 WRITTEN-0 (upstream contract)
DF2223 FIXED    hostb0      pcie_get_width_cap-style consumer: lnkcap=0x00000000 -> width=0xff (deterministic UNKNOWN)
DF2223 VERDICT: 7 devices exercised; baseline left *dst untouched (canary intact) on every not-implemented read while FIXED zeroes it (upstream Linux contract: *val = 0)
```

- `dst` is canary-loaded (`0xA5A5A5A5`) before every call; baseline leaves it
  bit-identical → the caller (which per `pcie_get_width_cap`, `linux/pci.h:608-617`,
  ignores the return value) consumes the uninitialized stack word
  (`width = 0x1a` from the canary pattern — deterministic proof of consumption).
- The FIXED variant writes `*dst = 0` on the same path → deterministic
  `PCIE_LNK_WIDTH_UNKNOWN`, exactly the upstream Linux contract.
- Honest limitation, visible in the log: this i440fx guest has **no PCIe
  devices**, so `pci_is_pcie()` is false everywhere and even the
  `PCI_EXP_FLAGS_TYPE` control hits the early-out; the *implemented* path
  (line 38, real config read) is not exercisable on this hardware. The finding
  is exclusively about the not-implemented path, which IS exercised.

## Attacker input / reachability

The predicate is false for every register on non-PCIe devices, and for
LNKCAP/LNKCTL/LNKSTA on PCIe v1 devices whose type is not ROOT_PORT / ENDPOINT /
LEG_END (`pcie_cap_has_lnkctl`, `linux/pci.h:445-453`) — e.g. a discrete GPU
behind a v1 switch port. Live consumers per the finding: `pcie_get_width_cap()`
(`linux/pci.h:612`) feeding `amdgpu_device.c:3550` (`adev->pm.pcie_mlw_mask`)
and `amdgpu/cik.c:1634` (`clk_req_support` gating). The uninitialized bits are
masked before use and never reach userspace → no direct info leak; ceiling is
incorrect driver behavior / wrong register programming (DoS class). No write
primitive → no privesc route.
