⬢ DragonFlyBSD Kernel Audit
DF-5834 / verdict.json
← back to finding ↓ download raw
{
  "finding_id": "DF-5834",
  "status": "reproduced",
  "verdict": "REPRODUCED (behavioral): pps_fetch_timeout() inverts a normalized finite sub-tick timeout (tv_sec==0, 0<tv_nsec<nstick) into an unbounded sleep \u2014 tstohz_low() returns 0 (kern_clock.c:1272) and tsleep(..., timo=0) arms no timeout (kern_synch.c:691) \u2014 verified live: PPS_IOC_FETCH with timeout {0 s, 1 ns} on /dev/ttyd0 was still asleep in wchan ppsfch at t=12 s and only kill -9 reaped it, while control runs behave normally. IMPACT: none (Info) \u2014 on the default install PPS devices are root-only (ttyd0 = 0600), the hang is confined to the callers own signal-killable thread. The suspected amplification \u2014 sioioctl() holding the global tty_token across pps_ioctl (sio.c:294/2165) making this a system-wide tty DoS \u2014 was tested and REFUTED: lwkt_switch() releases all tokens of a blocking thread (lwkt_thread.c:636-643, lwkt_relalltokens), and a concurrent PPS_IOC_GETCAP (which needs tty_token) completed in 0.000 s while the FETCH child slept in ppsfch.",
  "reproduced": true,
  "impact": "none",
  "confidence": "certain",
  "exploit_chain": "",
  "evidence": "run.log: inf section \u2014 child prints PPS_IOC_FETCH timeout=0s 1ns, ps at t=12s shows pid 971 S0 wchan=ppsfch with no FETCH returned line until kill -9; control section \u2014 timeout {0,0} returns instantly, GETCAP elapsed 0.000s; WEDGE 8s section \u2014 mid-wedge ps shows ppsfch sleeper while parent GETCAP elapsed 0.000s (token-refutation). VERDICT.md has the full path:line trace.",
  "kernel_refs": [
    "sys/kern/kern_clock.c:1616",
    "sys/kern/kern_clock.c:1618",
    "sys/kern/kern_clock.c:1626",
    "sys/kern/kern_clock.c:1272",
    "sys/kern/kern_clock.c:1672",
    "sys/kern/kern_synch.c:691",
    "sys/dev/serial/sio/sio.c:2165",
    "sys/kern/lwkt_thread.c:643"
  ],
  "poc_changes": "Original rig used two processes (wedge + victim with separate opens of /dev/ttyd0); redesigned into a single fork-based program (one fd, child wedges, parent measures GETCAP). First inf invocation hit a rig bug (atoi(\"inf\")==0 ran the control); fixed to explicit strcmp. No kernel source changes; PoC ran against the stock guest kernel.",
  "attempts": 3,
  "guest_uname": "DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #0: Thu Jul  2 06:02:54 UTC 2026     root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC  x86_64",
  "runtime_sec": 95,
  "guest_dirty": 0,
  "build_cmd": "cc -O2 -Wall -o ppslockdemo ppslockdemo.c",
  "run_cmd": "./ppslockdemo 0; ./ppslockdemo 8; ./ppslockdemo inf   (as root on a DragonFly guest with a sio serial port)",
  "code_hash": "1dbe117ddd751db96f79d3db9e54ae9c43eecfa9e3bb407ff39ea8e9b3a4e3f3",
  "notes": "PPS_SYNC is not compiled into the stock X86_64_GENERIC kernel (LINT64 only), so the PPS_IOC_KCBIND/hardpps halves of pps_ioctl are dead code on this guest; the FETCH path audited here is compiled in and reachable via sio(4), ppbus pps(4), ucom(4). Guest artifacts removed after the runs; guest still up.",
  "recommended_fix": "In pps_fetch_timeout(), clamp a computed zero tick count to 1 so any finite timeout still arms a tsleep timeout (see fix.diff).",
  "fix_status": "not_tested",
  "fix_baseline_reproduced": true,
  "fix_patched_reproduced": false,
  "fix_verdict": "fix.diff authored from line-accurate root cause (one-line clamp after to=tstohz_low()); kernel rebuild + patched retest not performed for this Info-grade, non-corruption finding.",
  "fix_evidence": "findings/poc/DF-5834/fix.diff"
}