⬢ DragonFlyBSD Kernel Audit
DF-5638 / verdict.json
← back to finding ↓ download raw
{
  "finding_id": "DF-5638",
  "status": "reproduced",
  "verdict": "smbus_poll (sys/bus/smbus/smbconf.c:92-94) parks SMB_WAIT|SMB_NOINTR callers in tsleep(sc, 0, \"smbreq\", 0) -- no PCATCH, no timeout (SMB_NOINTR is 0 per smbconf.h:42; in-tree plain-SMB_WAIT callers: ipmi_ssif.c:81,181 and cyapa.c:1176,1624). Reproduced on the stock kernel with the DF-5636 rig: a user process calling smbus_request_bus(devB, SMB_WAIT) while another device held the bus entered state D4 on wchan smbreq and SURVIVED kill -9; the pending SIGKILL was delivered only after the bus was released (and the wake path handed it a phantom grant besides). The check-then-sleep window in the first do-while (smbconf.c:120-124) can additionally strand a waiter on a free bus forever. fix.diff makes smbus_poll always PCATCH with an hz bound: on the rebuilt kernel the parker sits in S2 smbreq and kill -9 kills it immediately, and the timeout turns any lost wakeup into a 1-second retry. Residual: no detach drain (noted in VERDICT.md).",
  "reproduced": true,
  "impact": "dos",
  "confidence": "certain",
  "exploit_chain": "",
  "evidence": "run_baseline.log PARK section: D4 smbreq before and after kill -9, unwedge via unpark, <<< phantom grant on wake; run_fixed.log: S2 smbreq + kill -9 WORKED: parker died (PCATCH fix effective)",
  "kernel_refs": [
    "sys/bus/smbus/smbconf.c:88",
    "sys/bus/smbus/smbconf.c:92",
    "sys/bus/smbus/smbconf.c:120",
    "sys/bus/smbus/smbconf.h:42",
    "sys/dev/misc/ipmi/ipmi_ssif.c:81",
    "sys/dev/smbus/cyapa/cyapa.c:1176",
    "sys/dev/smbus/cyapa/cyapa.c:1624"
  ],
  "poc_changes": "shared rig with DF-5636; the PARK/UNPARK ioctls park a real user process (not a kthread) so unkillability is observable via ps/kill",
  "attempts": 2,
  "guest_uname": "DragonFly dfbsd 6.5-DEVELOPMENT #0 (baseline) / #3: Fri Oct 9 02:13:57 UTC 2026 (fix validation), x86_64",
  "runtime_sec": 4950,
  "guest_dirty": 0,
  "build_cmd": "sh ./build.sh; fix: patch -p1 < fix.diff && make quickkernel+installkernel KERNCONF=X86_64_GENERIC",
  "run_cmd": "./df5636ctl park & sleep 1; ps -o pid,stat,wchan -p $!; kill -9 $!; sleep 1; ps ...; ./df5636ctl unpark",
  "code_hash": "0d6a9fb46361a16b9421e6e44b59cf3ff1e8b00f4732809426d00d30d98d4fb6",
  "notes": "Low severity (DF-5563/5564 twin band). The kldunload-under-parked-waiter freed-text variant is defused practically by PCATCH+hz (waiter killable, re-checks every second) but a proper detach drain remains future family-wide work.",
  "recommended_fix": "Make smbus_poll always sleep with PCATCH and an hz-bounded timeout (and treat the timeout as a re-check, per DF-5636s loop fix); see pack fix.diff, shared with DF-5636.",
  "fix_status": "fixed",
  "fix_baseline_reproduced": true,
  "fix_patched_reproduced": false,
  "fix_verdict": "Patched kernel: parker state S2 (killable) vs D4 (unkillable) on stock; kill -9 terminates the parked process immediately; the 1s poll bound self-heals lost wakeups.",
  "fix_evidence": "run_fixed.log PARK killability section vs run_baseline.log PARK section; fix.diff sha256 346fe6893056aecf467e64d12285a0de337461aee150737964c0c3f5f06fbc2a"
}