DELAY()/DRIVERSLEEP() do not clamp negative arguments β sign-extended usec count converts to a multi-hour (i8254: multi-month) kernel spin
Summary
DODELAY consumes raw int n in unsigned 64-bit muldivu64: DELAY(-1) yields ~2.2e13 ticks (~256 days at the 1.19MHz i8254 base, ~2h at 3GHz TSC) with no escape. All in-tree callers pass constants - latent trap for future driver code. Clamp-at-entry fix.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-5331 Β· 2 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | file | 1.2 KB | β raw | |
| verdict.json | file | 1.9 KB | view raw |
DF-5331 β DELAY()/DRIVERSLEEP() do not clamp negative arguments (hardening)
File: sys/platform/pc64/isa/clock.c, pass 2 (GLM 5.3). Severity: Info.
DODELAY() (clock.c:386) computes
ticks_left = muldivu64(n, sys_cputimer->freq + 999999, 1000000);
with int n (clock.c:419). A negative n is sign-extended to u64
(0xFFFF...); muldivu64 (sys/sys/systm.h:505) then yields ~2.2e13 ticks,
so DELAY(-1) spins for hours-to-years depending on the selected cputimer
(β256 days at the 1.19 MHz i8254, β2 h at a 3 GHz TSC). There is no
if (n <= 0) return; guard.
No in-tree caller passes a user-influenced or potentially negative value (surveyed: constants and kernel-internal tables only β atkbdc, ppc, lpt, igmp's IGMP_RANDOM_DELAY, etc.), so this is defense-in-depth for future drivers, not a demonstrated DoS. Fix is one line:
--- a/sys/platform/pc64/isa/clock.c
+++ b/sys/platform/pc64/isa/clock.c
@@ DODELAY(int n, int doswitch)
{
ssysclock_t delta, ticks_left;
sysclock_t prev_tick, tick;
+ if (n <= 0)
+ return;
+
#ifdef DELAYDEBUG
PoC: not built β DELAY() is not reachable from userland; the arithmetic above is the complete demonstration (verdict status: untested).
Fix verification
not_testablenot tested (hardening finding, no runtime PoC)
Confirmed kernel references
Detail
Evidence (decisive lines)
findings/poc/DF-5331/README.md (analysis + suggested one-line guard); sys/platform/pc64/isa/clock.c:419; sys/sys/systm.h:505
PoC changes
none (no PoC; hardening finding)
Verified recommended fix
Clamp n at the top of DODELAY(): if (n <= 0) return;
Verdict
Hardening only. DODELAY() (sys/platform/pc64/isa/clock.c:386) computes ticks_left = muldivu64(n, sys_cputimer->freq + 999999, 1000000) at clock.c:419 with no clamp on the int argument n; a negative n sign-extends to u64 in muldivu64 (sys/sys/systm.h:505, 128-bit intermediate) yielding ~2.2e13 ticks, i.e. DELAY(-1) would spin ~256 days at the 1.19 MHz i8254 or ~2 h at a 3 GHz TSC with no escape. Survey of in-tree callers found only constants and kernel-internal tables (atkbdc.c, ppc.c, igmp IGMP_RANDOM_DELAY, etc.), so there is no demonstrated attacker-reachable trigger today; filed as Info hardening (one-line 'if (n <= 0) return;' guard). Not executed: DELAY() is not reachable from userland without a custom KLD, and the arithmetic is the complete demonstration.
No comments yet.