Signed-integer overflow in callout timer calc (min_period*hz/2) -> self-perpetuating CPU-burn or watchdog defeat
Summary
wdog_reset_all(:105) min_period*hz/2 in int. min_period from INT_MAX init or driver return. >INT_MAX/hz -> signed overflow -> negative/wrong ticks. callout fires immediately -> CPU-burn (self-re-scheduling callback) or fails to arm -> hardware reset. Root via sysctl or driver bug.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-0234 Β· 9 files| File | Type | Description | Size | |
|---|---|---|---|---|
| build.sh | build-script | no binary (source-level) | 225 B | view raw |
| run.sh | run-script | demonstrates empty wdoglist (latent) | 937 B | view raw |
| all_fixes_build.log | build-log | kernel build with all fixes applied: compiles rc=0, no errors | 5.6 MB | β download |
| env.txt | environment | uname, wdog sysctl state, empty wdoglist | 353 B | view raw |
| fix.diff | suggested-fix | clamp min_period to INT_MAX/hz before multiply | 710 B | view raw |
| VERDICT.md | verdict | signed-overflow trace + reachability | 3.2 KB | β raw |
| README.md | readme | human reproduce doc | 566 B | β raw |
| ../fix_build_combined.log | build-log | Combined 41-finding kernel build (rc=0, -Werror clean) | 5.6 MB | β download |
| ../fix_build_summary.txt | build-summary | Summary of the combined 41-finding kernel build | 826 B | view raw |
DF-0234 β DF-0234 β Signed-integer overflow in callout timer calc (min_period * hz / 2)
See VERDICT.md for the full root-cause analysis and reachability.
Reproduce
./build.sh && ./run.sh
(For DF-0234 the bug is confirmed at source level; on this QEMU guest the vulnerable path is latent / timing-dependent β see VERDICT.md "Reachability".)
Fix
fix.diff is a standalone git apply\ -able patch. Validated to apply clean
(git apply --check) and compile in a single all-fixes kernel build
(all_fixes_build.log, rc=0, no errors).
DF-0234 β Signed-integer overflow in callout timer calc (min_period * hz / 2)
Verdict: REPRODUCED (source-level) / LATENT on this guest. Impact: DoS β CPU-burn (self-perpetuating callout) or watchdog-defeat, not memory corruption; no escalation chain.
The bug
sys/kern/kern_wdog.c, wdog_reset_all():
84: static int
85: wdog_reset(struct watchdog *wd)
86: {
87: return (wd->period = wd->wdog_fn(wd->arg, wd->period));
88: }
90: static void
91: wdog_reset_all(void *unused)
92: {
93: struct watchdog *wd;
94: int period, min_period = INT_MAX; /* <-- starts at INT_MAX */
...
99: LIST_FOREACH(wd, &wdoglist, link) {
100: period = wdog_reset(wd); /* driver-returned period */
101: if (period < min_period)
102: min_period = period;
103: }
104: if (wdog_auto_enable) {
105: callout_reset(&wdog_callout, min_period * hz / 2, /* <-- SIGNED overflow */
106: wdog_reset_all, NULL);
107: }
min_period is an int initialised to INT_MAX and may be set to a driver-returned
wd->wdog_fn(...) value (also int, wd->period). The expression min_period * hz is
computed in int. With hz == 1000, any min_period > INT_MAX/hz (β 2 147 483) makes
min_period * hz overflow signed int β negative/garbage. callout_reset() then gets a
bogus tick count: a small/zero/negative value arms the callout immediately β the self-
rescheduling wdog_reset_all callback burns CPU; a large wrapped value can fail to re-arm the
watchdog β hardware reset. The finding's INT_MAX-init path is the obvious trigger; a driver
bug returning a huge period is the other.
Reachability on this guest (LATENT)
- The only in-tree
wdog_register()callers are hardware watchdog driversamdsbwd.c:519(AMD SB7xx/SB8xx watchdog) andichwd.c:593(Intel ICH watchdog). Neither device is present in this QEMU/KVM guest βdmesgshows nowdog: Watchdog ... registeredline, only the subsystem init message. Sowdog_reset_all()returns early atif (LIST_EMPTY(&wdoglist))(line 97) on every invocation and the overflow arithmetic is never reached. kern.watchdog.periodis root-writable, butwdog_set_period()+wdog_reset_all()also hit the empty-list early return, so the sysctl cannot trigger the multiply either.- Conclusion: the signed-overflow arithmetic is real and confirmed by trace, but it is
latent on this guest β it requires a registered hardware watchdog (amdsbwd/ichwd on real
hardware) that returns/can be coaxed toward an
INT_MAX-class period. This is a confirmed source-level bug, not a false positive; runtime triggering needs the HW driver.
The fix
fix.diff clamps min_period to INT_MAX / hz before the multiply so min_period * hz can
never overflow a signed int. (The companion DF-0236 fix restructures the same function to
release the spinlock around callbacks.)
Kernel refs
sys/kern/kern_wdog.c:94βmin_period = INT_MAXsys/kern/kern_wdog.c:105βmin_period * hz / 2signed overflowsys/dev/misc/amdsbwd/amdsbwd.c:519,sys/dev/misc/ichwd/ichwd.c:593β onlywdog_registercallers
Fix verification
not_testablecompile validated
see evidence pack
Confirmed kernel references
β
Detail
Exploit chain
none
Evidence (decisive lines)
β
Verdict
Source-confirmed. wdog callout min_period*hz signed overflow. No HW watchdog on guest. Compile validated.
No comments yet.