SMB_WAIT-only requesters park unkillably in smbreq: tsleep without PCATCH and without timeout (DF-5563/5564 twins at the smbus layer)
Summary
SMB_NOINTR is 0 so plain SMB_WAIT - exactly what ipmi_ssif and cyapa pass - selects tsleep(sc,0,"smbreq",0): no PCATCH, no timeout. A user process reaching this sleep sits D-state and survives kill -9 until something releases the bus; the check-then-sleep window can strand a waiter on a free bus forever, and no detach drain makes kldunload-under-a-parked-waiter the DF-5636-class freed-text resume. Reproduced (D4 smbreq before/after kill -9; unwedged only by unpark); PCATCH+hz-bound fix validated (kill -9 works immediately, self-heals lost wakeups).
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-5638 Β· 14 files| File | Type | Description | Size | |
|---|---|---|---|---|
| df5636_rig.c | β | 22.5 KB | view raw | |
| df5636ctl.c | β | 1.5 KB | view raw | |
| iicbb_reg.c | β | 491 B | view raw | |
| Makefile.rig | β | 279 B | β download | |
| Makefile.reg | β | 228 B | β download | |
| build.sh | β | 82 B | view raw | |
| run.sh | β | 204 B | view raw | |
| build.log | β | 1.1 KB | view raw | |
| run_baseline.log | β | 5.2 KB | view raw | |
| run_fixed.log | β | 2.9 KB | view raw | |
| env.txt | β | 512 B | view raw | |
| fix.diff | β | 2.2 KB | view raw | |
| VERDICT.md | β | 2.4 KB | β raw | |
| verdict.json | β | 3.1 KB | view raw |
DF-5638 VERDICT β REPRODUCED
Root cause: smbus_poll() (sys/bus/smbus/smbconf.c:82-102) sleeps
tsleep(sc, 0, "smbreq", 0) for SMB_WAIT|SMB_NOINTR (smbconf.c:92-94).
SMB_NOINTR is 0 (smbconf.h:42), so every caller passing plain
SMB_WAIT β in-tree: ipmi_ssif.c:81 and :181, cyapa.c:1176 and :1624 β
parks with no PCATCH and no timeout. If the smbus is held (by another
child, by a wedged owner β see DF-5637's permanent wedge β or via the
check-then-sleep lost-wakeup window in smbconf.c:120-124 where a release's
wakeup fires between the failed callback and the tsleep), the calling
thread sleeps indefinitely and cannot be killed.
Reproduced (stock kernel, DF-5636 rig): ./df5636ctl park holds the
bus with devA and calls smbus_request_bus(smbus, devB, SMB_WAIT=0x1) from
a user process: ps shows the process in state D4 on wchan smbreq;
kill -9 has no effect; the SIGKILL is delivered only after
./df5636ctl unpark releases the bus (and the wake path additionally
hands the parker the DF-5636 phantom grant, <<< phantom grant on wake).
Fixed kernel (fix.diff, kernel #3): smbus_poll always sleeps with
PCATCH and an hz bound (mirroring the DF-5564 iiconf fix). The parker now
shows S2 smbreq and kill -9 kills it immediately β verified in the
same session (kill -9 WORKED: parker died). The hz bound also converts
the lost-wakeup strand into a 1-second self-healing retry.
Residual (documented, not in this fix): no detach drain β kldunload of the smbus/iicsmb modules under a now bounded waiter is still not explicitly serialized; with PCATCH+hz the waiter is killable and re-checks within a second, which defuses the DF-5563-class freed-text resume practically, but a proper drain flag (cf. the DF-5563 fix's dying/waiters/spinlock) belongs to a family-wide rework of both iiconf and smbconf.
Classification: status=reproduced, reproduced=1, impact=dos, confidence certain. Severity Low (DF-5563/5564 twin band): unkillable-state local DoS reachable from root-only device entry points or kernel threads.
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.
Fix verification
fixedPatched 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.
run_fixed.log PARK killability section vs run_baseline.log PARK section; fix.diff sha256 346fe6893056aecf467e64d12285a0de337461aee150737964c0c3f5f06fbc2a
Confirmed kernel references
Detail
Evidence (decisive lines)
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)'
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
Verified recommended fix
Make smbus_poll always sleep with PCATCH and an hz-bounded timeout (and treat the timeout as a re-check, per DF-5636's loop fix); see pack fix.diff, shared with DF-5636.
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).
No comments yet.