# DF-5277 — VERDICT

**Status: reproduced** (impact: kernel panic / NULL-pointer dereference; confidence: certain)

## Chain of evidence

1. **The parser produces the crash state** (userspace verbatim harness,
   mode `t2`, `../DF-5276/run.t2.log`): a VPD stream of
   `90 04 00 'X' 'Y' 01 'Z'` (a *completing* VPD-R section — sets
   `vpd_rocnt = 1` at `pci.c:1223-1227`) followed by
   `90 03 00 'R' 'V' 00` (an "RV" keyword with length 0 → "bad keyword
   length" → `cksumvalid = 0; state = -1` at `pci.c:1165-1178`) drives the
   real cleanup at `pci.c:1297-1305` to free+NULL `vpd_ros` while leaving
   `vpd_rocnt == 1`:

   ```
   t2:   vpd_ros  = 0x0   (freed and NULLed by cleanup)
   t2:   vpd_rocnt= 1   (STALE -- cleanup does not reset it)
   t2: CRASH PRECONDITION REPRODUCED
   ```

2. **The real in-kernel `pci_freecfg()` panics on that state** —
   `kmod/freecfgcrash.ko` calls the *actual exported* `pci_freecfg()` on a
   devinfo carrying exactly the states the kernel itself leaves behind:

   * Variant A — VPD capability present, never parsed (all pointers NULL,
     the state of *any* VPD-capable CardBus card that no driver queried):
     `panic-A.txt`:
     ```
     DF5277(A): pci_freecfg() with all VPD pointers NULL, vpd_reg=0x40 (never parsed)
     panic: trying to free NULL pointer
     _kfree() at _kfree+0x558
     pci_freecfg() at pci_freecfg+0xdc
     freecfgcrash_load() at ...
     ```
     Root cause: DragonFly's `kfree(NULL)` panics
     (`sys/kern/kern_slaballoc.c:1406`) but `pci_freecfg()`
     (`pci.c:2146-2153`) kfrees `vpd_ident`/`vpd_ros`/`vpd_w`
     unconditionally — FreeBSD's `free(NULL)` no-op semantics were assumed.

   * Variant B — completed section then error (stale `vpd_rocnt`, NULL
     `vpd_ros`): `panic-B.txt`:
     ```
     DF5277(B): pci_freecfg() with vpd_ros=NULL, vpd_rocnt=1 (stale after error cleanup)
     Fatal trap 12: page fault while in kernel mode
     fault virtual address = 0x8
     Stopped at pci_freecfg+0xb3: movq 0x8(%rax),%rdi
     ```
     exactly the `vpd_ros[0].value` load at `*(NULL+8)`.

3. **The readonly accessor NULL-deref also fires in the real code**: the
   verbatim `pci_get_vpd_readonly_method()` SEGVs at address 0x0 when
   handed the post-cleanup state (end of `../DF-5276/run.t2.log`, stage
   2b).

Both panics are on the real, unmodified running kernel
(`DragonFly 6.5-DEVELOPMENT #0 .../X86_64_GENERIC`), captured from the
serial console.

## Reachability

`pci_freecfg()` is called from the CardBus paths
(`sys/dev/pccard/cardbus/cardbus.c:191` — `device_add_child` failure at
insertion; `:246` — detach, including `cardbus_suspend()` → system
suspend). A VPD-capable 16-bit card (common for PCMCIA NICs) with
malformed VPD — or with VPD that no driver ever queried (variant A, no
malice required, merely removal of the card) — panics the system.
CardBus is legacy hardware, hence Medium rather than High.

## Fix validation

With `fix.diff` (NULL-guarded frees + count resets + lookup guard) built
into the guest kernel, both `freecfgcrash.ko` variants load and return
cleanly — see `fix-validation.log`.

## Caveats

The QEMU guest has no CardBus bridge, so the free path was driven by
calling the real exported function with the exact states the kernel's own
parse/cleanup produce (state production itself demonstrated by the
verbatim harness in step 1).

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