# DF-5044 — VERDICT

**Verdict:** REPRODUCED (runtime, stock-kernel sili functions, no hardware)
**Class:** unbounded wait / DoS amplifier (CWE-835)
**Impact ceiling:** dos (permanent hang of kldunload/shutdown path with the
module/controller resources pinned; requires a wedged port helper thread —
hardware-misbehaviour-conditioned, root-triggered)
**Confidence:** certain

## Reproduction

The guest has no SiI 3124/3132 card, but `sili` is compiled into
X86_64_GENERIC, so the OS glue under test is the running kernel's own code.
The module (DF-4964 technique) constructs a softc whose BAR windows point at
a real `pmap_mapdev_uncacheable` RAM mapping and calls the kernel's own
`sili_port_alloc()` twice — REAL helper threads (`sili_port_thread`) start,
run their probe against the fake MMIO ("No device detected") and park.

* **E1 (control)** — `sili_os_stop_port(port0)` signals STOP and returns
  promptly (`run.log`).
* **E2** — module holds `ap->ap_lock`, signals `AP_SIGF_TIMEOUT`; the helper
  thread wakes and blocks inside `sili_port_thread_core() →
  sili_os_lock_port()` (sili.c:1601).  A stopper kthread calls
  `sili_os_stop_port(port1)`: the driver prints its own
  `pci0.1: Waiting for thread to terminate` (sili_dragonfly.c:215-216) and
  spins in `while (ap->ap_thread) sili_os_sleep(100)`
  (sili_dragonfly.c:217-218) — watchdog observes 5/10/15 s of continuous
  spinning; only the module's wedge release lets it finish (`run.log`).
* **norelease (baseline kernel)** — wedge held forever by a sacrificial
  kthread: stopper still spinning after 90 s (18×5 s observations,
  `run.2.log`) — i.e. forever: nothing in the kernel will ever release it.
  In the real kldunload/shutdown scenario the waiter is the unload path
  itself (linker/module locks held) → permanent system-level hang.

## Mechanism (source-confirmed)

`sili_os_stop_port()` (sili_dragonfly.c:208-224) has **no bound, no
escalation and no force-kill**: once the helper thread is wedged anywhere
inside the driver core (a port stuck in reset loops against dead silicon, a
CAM-completion path holding `ap_lock`, a stuck `sili_pwait` retry), the
detach path (`sili_port_free` → `sili_os_stop_port`, sili.c:674) can never
complete and `kldunload sili`/shutdown hangs forever.  The identical pattern
exists in the ahci sibling (`ahci_os_stop_port`) this file was derived from.

## Fix validation (full runtime A/B, patched kernel)

`fix.diff` bounds the wait at 60 s and converts the hang into a
leak-not-hang: `sili_os_stop_port()` returns `ETIMEDOUT`,
`sili_port_free()` skips freeing that port (keeps the memory the thread
references valid), and `sili_pci_detach()` keeps the controller resources
and returns `EBUSY` so kldunload fails cleanly instead of hanging.

Patched kernel `6.5-DEVELOPMENT #1 Sat Sep 26 10:36:11 2026`
(`fix_build.log`: quickkernel rc=0, `-Werror`):

* norelease mode (`run.3.log`): stopper spins exactly 60 s (12×5 s
  observations), then the **fixed kernel code itself** prints
  `pci0.1: thread did not terminate; leaking port to avoid unload hang`
  and `sili_os_stop_port` RETURNS; guest stays up, module unloads.
* normal mode (`run.4.log`): E1/E2/E3 all behave as before — the fix does
  not slow or break the normal stop path (E2's stopper returns promptly
  after the wedge release, as on baseline).

Baseline (`run.2.log`) vs patched (`run.3.log`) on otherwise identical
guests is the A/B pair.

## Post-observation incident (harness artifact, not the finding)

After the first patched norelease observation completed, the runner
mistakenly `kldunload`ed the module while the intentionally-leaked wedge
kthread still referenced module memory; that thread later executed unmapped
module text (IP 0xffffffff826000da, module range) and panicked the guest
(Fatal trap 12, serial console).  All decisive evidence had already been
written; the guest was reset to the clean-source snapshot afterwards.  The
incident is unrelated to the finding's mechanism (it demonstrates only that
one must not unload a module that deliberately leaks threads — which is
exactly the situation the *fixed* driver leaves the real kernel in, minus
the unload, since the real module refuses unload via EBUSY).

## Gating precondition

sili(4) controller present + a port helper thread wedged in the driver core
(dead/misbehaving silicon, stuck CAM path), triggered by `kldunload sili` or
system shutdown.  Root-triggered DoS (availability), no escalation path —
hence Low severity.

## Exploit chain

Not applicable (hang class; the trigger requires privileged unload/shutdown
plus a wedged device).

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