# DF-1097 — VERDICT

**Verdict: NOT REPRODUCED at runtime (latent — requires FireWire OHCI
hardware not present in the audit guest).  Bug confirmed by source trace.**

## Mechanism (source-confirmed)

`fwohci_pci_add_child()` at `sys/bus/firewire/fwohci_pci.c:442-447`:

```c
err = device_probe_and_attach(child);
if (err) {
    device_printf(parent, "probe_and_attach failed with err=%d\n", err);
    fwohci_pci_detach(parent);          /* :446 */
    device_delete_child(parent, child); /* :447 */
    return NULL;
}
```

`sc->fc.bdev` is assigned to `child` at fwohci_pci.c:439 before
`device_probe_and_attach(child)` runs.  On failure, line 446 calls
`fwohci_pci_detach(parent)`, which at fwohci_pci.c:351-353 executes:

```c
if (sc->fc.bdev) {
    device_delete_child(self, sc->fc.bdev);   /* frees child */
    sc->fc.bdev = NULL;
}
```

`device_delete_child` at `sys/kern/subr_bus.c:1284-1309` ends at
subr_bus.c:1306 with `kobj_delete((kobj_t)child, M_BUS);` — **child is
kfree()'d**.  It also `TAILQ_REMOVE(&dev->children, child, link)` at
subr_bus.c:1304 and `TAILQ_REMOVE(&bus_data_devices, child, devlink)` at
subr_bus.c:1305.

Control then returns to fwohci_pci.c:447, which calls
`device_delete_child(parent, child)` on the now-freed `child`:

- `device_detach(child)` (subr_bus.c:1292) reads `child->state` — **UAF read**.
- `TAILQ_FIRST(&child->children)` (subr_bus.c:1296) dereferences freed
  memory — **UAF read**.
- `child->devclass` (subr_bus.c:1302) — **UAF read**.
- `TAILQ_REMOVE(&dev->children, child, link)` (subr_bus.c:1304) operates
  on a child already removed from `dev->children` — corrupts the parent's
  TAILQ (use-after-free with list corruption).
- `kobj_delete((kobj_t)child, M_BUS)` (subr_bus.c:1306) — **double-free**.

## Why it can't be triggered on this guest

The default audit QEMU guest is launched with `-device virtio-net-pci`
and **no FireWire PCI device**.  QEMU ships no FW-OHCI device model at
all (no `-device` option for it exists upstream).  Verified:

```
$ dmesg | grep -iE 'fwohci|firewire'
(empty)
$ pciconf -lv | grep -i 'class: 0x0c00'
(empty)
```

The `fwohci` driver IS compiled into `X86_64_GENERIC` (it's not a loadable
module), but `fwohci_pci_attach` is never called without a FireWire PCI
device, so `fwohci_pci_add_child` (its `bus_add_child` method) is never
reached.  The error path is therefore unreachable from any userspace
action on this guest.

Realistic triggers (all out of scope of an audit guest):
1. A real FireWire OHCI PCI controller on the host (rare on modern HW).
2. A malicious/buggy FW-OHCI PCI device hot-plugged via Thunderbolt /
   ExpressCard / PCIe that probes as fwohci but fails to attach its
   firewire child (e.g. due to memory pressure during newbus allocation).

## Exploit chain

**Primitive class:** UAF + double-free in newbus.  In principle a UAF on
a `device_t` object could be converted to a controlled write via
slab-grooming + re-claiming the freed `device_t` with a victim object
containing a function pointer.  BUT:

- The primitive is reachable **only from the kernel FireWire attach
  path**, which requires either a malicious PCI device on the bus or
  memory pressure during firewire attach (not reproducible on the audit
  guest).
- Even with FireWire hardware, the trigger requires
  `device_probe_and_attach(child)` to fail in a specific way that the
  normal firewire stack won't reproduce — realistic only for a malicious
  controller.

This is a **valid hard blocker** ("vulnerable code path is dead code at
runtime on this guest AND no harness can exercise it"): the path is real
in source but unreachable without hardware the audit guest lacks.
Documented as latent.  No `uid=0` achievable on this guest.

## Fix

`fix.diff` clears `sc->fc.bdev = NULL;` *before* the detach call, so the
detach's `device_delete_child(self, sc->fc.bdev)` is skipped.  The
explicit `device_delete_child(parent, child)` at line 447 then becomes
the sole delete — no UAF, no double-free.  Validated as applies + compiles
in a clean GENERIC kernel build.

## Fix validation

`not_testable` — the path is not runtime-reachable on this guest (no
FireWire hardware).  Validated `fix.diff` applies cleanly with
`patch -p1 --dry-run` and compiles with `-Werror` in a full
`make nativekernel KERNCONF=X86_64_GENERIC` (the four target files
`fwohci_pci.c`, `xhci_pci.c`, `smbacpi.c`, `acpi_sdt.c` were all rebuilt
fresh and produced no warnings/errors — see
`../DF-1096/all_fixes_build.log`).

## PoC changes

- Wrote `df1097.c` (documentation-only stub explaining the source trace).
- Wrote `fix.diff`, `build.sh`, `run.sh`.
