# DF-2681 — VERDICT

**status: reproduced**, **impact: dos**, **confidence: certain**.

## Reproduced how

`dfrec.ko` (this pack) is a nexus bus driver that does exactly what the
exported API invites: `DEVMETHOD(bus_delete_resource,
bus_generic_delete_resource)`, then calls `bus_delete_resource()` on
one of its children from attach.

On the stock INVARIANTS kernel:

```
dfrec0 on motherboard
dfrec: attached, calling bus_delete_resource() on child
```

- `kldload` never returned (> 4 minutes observed; `date` still worked,
  `ps -ax` and `kldstat` hung, clean shutdown timed out, guest had to
  be force-killed from the host).
- The follow-up kprintf (`dfrec: returned (no bug)`) never executed.

## Mechanism confirmation (source)

`sys/kern/subr_bus.c:3144-3149`:

```c
bus_generic_delete_resource(device_t dev, device_t child, int type, int rid)
{
	if (dev->parent)
		BUS_DELETE_RESOURCE(dev, child, type, rid);
}
```

kobj dispatch (`subr_kobj.c:160-191`) resolves `bus_delete_resource`
on the first argument; passing `dev` re-selects this same method →
unbounded self-recursion. All sibling wrappers in the same file
(bus_generic_setup_intr:3025, teardown_intr:3038, config_intr:3065,
alloc_resource:3076, release_resource:3088, activate_resource:3099,
deactivate_resource:3110, set_resource:3138) pass `dev->parent`.

The observed livelock (rather than a stack-overflow trap) is explained
by the -O2 tail call: the recursive call is the last statement, so it
compiles to a `jmp` — the loop never grows the stack and never returns,
keeping the kldload thread's module lock held forever. A build with a
non-tail-call layout overflows the kernel stack instead (same root
cause, trap-flavored).

## Severity rationale

Root-gated (kldload) and latent (no in-tree driver currently installs
the wrapper) → Low. It is still a shipped, exported kernel API whose
contract is "propagate to parent"; any kmod using it as designed
livelocks the kernel permanently.

## Fix validation

Not rebuilt (Low severity, one-line fix): the diff replaces `dev` with
`dev->parent`, matching every sibling wrapper; with the fix the
dispatch terminates at the first ancestor implementing
`bus_delete_resource` or hits the kobj default (`kobj_error_method`,
returns ENXIO) — no recursion.
