# DF-5276 — Heap buffer overflow in `pci_read_vpd()` via zero-length VPD identifier string

## What

`sys/bus/pci/pci.c`, the PCI VPD (Vital Product Data) parser
(`pci_read_vpd()`, lines 1046-1324). A malicious PCI device (Thunderbolt
peripheral, emulated device, or a device with corrupt VPD EEPROM) that
answers VPD reads with:

```
82 00 00          long-form item, name 0x2 ("Identifier String"), length 0x0000
<payload bytes>   arbitrary attacker-controlled content
```

drives the kernel into:

```c
case 0x2:            /* String */
        cfg->vpd.vpd_ident = kmalloc(remain + 1, M_DEVBUF, M_WAITOK);  /* == kmalloc(1) */
        i = 0;
        state = 1;
        ...
case 1:              /* Identifier String */
        cfg->vpd.vpd_ident[i++] = byte;     /* unbounded */
        remain--;
        if (remain == 0) { ... }            /* never true: remain started at 0 */
```

With `remain == 0` the termination condition can never fire (remain goes
-1, -2, ...), so the parser writes **every subsequent VPD byte
sequentially past a 1-byte `kmalloc()`** — a linear kernel-heap overflow
whose *content and length are fully device-controlled*. It stops only when
the device stops completing VPD transfers (each stalled register costs the
kernel a 1,000,000-iteration `DELAY(1)` busy-wait, ~1s per 4 bytes — a
glitched-but-honest device still overflows the heap, slowly).

Attack surface: `pci_read_vpd()` runs lazily via `pci_get_vpd_ident()` /
`pci_get_vpd_readonly()` (PCI_GET_VPD_* methods) when a driver or KLD
probes a device's VPD. IOMMUs do not help: config-space-driven parsing is
initiated by the host CPU, not by device DMA.

## Reproduce (userspace, verbatim parser)

On the DragonFly guest (or any host with the same `sys/bus/pci/pci.c`):

```
cd findings/poc/DF-5276
sh build.sh        # extracts the parser VERBATIM from /usr/src and compiles
sh run.sh          # t4 t2 t2a t3 t1 (+t1 repeat)
```

Expected (vulnerable kernel source):

* `run.t1.log` — `*** SIGSEGV ... 4096 bytes were written past a 1-byte
  kmalloc allocation` (exit 77). Deterministic across runs.
* `run.t4.log` — well-formed VPD parses fine (harness fidelity check).

## Reproduce (kernel context, real kmalloc)

```
cd kmod && make
kldload ./vpdoflow.ko
dmesg | tail
```

Expected (vulnerable kernel): `DF5276: KERNEL HEAP OVERFLOW REPRODUCED:
1023 bytes written past a 1-byte M_DEVBUF allocation` (payload extent
verified in kernel memory), possible collateral panic from the smashed
neighbourhood — either outcome proves the primitive in-kernel.

Expected (kernel source patched with ../fix.diff):
`DF5276: parser rejected the item (fixed kernel) -- no overflow`.

## Fix

`fix.diff` (also fixes DF-5277 / DF-5278 / DF-5279, same function family).
Core hunk: reject `remain == 0` identifier items and make the oversize
check effective.
