Root-writable debug.cyapa_*_freq sysctls feed an integer divide-by-zero in cyapa_poll_thread β deterministic kernel panic
Summary
The three freq sysctls are exported RW via SYSCTL_INT with no bounds. The poll thread recomputes its sleep tick every iteration as (hz + freq - 1) / freq with freq reloaded from those globals. sysctl =0 makes the next poll iteration divide by zero in kernel-thread context - #DE panic. The idle frequency is selected whenever no fd is open, so no open fd is even required. SIGFPE harness on the guest (identical expression/types); the sysctl write path itself exercised live (accepted 100->0, no panic only because the poll thread is hardware-gated). Clamp + sysctl-validation fix.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-4228 Β· 12 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 1.9 KB | β raw | |
| VERDICT.md | β | 2.3 KB | β raw | |
| model_div0.c | β | 1.5 KB | view raw | |
| build.sh | β | 94 B | view raw | |
| run.sh | β | 193 B | view raw | |
| build.log | β | 165 B | view raw | |
| run.log | β | 574 B | view raw | |
| run.2.log | β | 943 B | view raw | |
| env.txt | β | 576 B | view raw | |
| fix.diff | β | 405 B | view raw | |
| manifest.json | β | 1.1 KB | view raw | |
| verdict.json | β | 2.1 KB | view raw |
DF-4228 β cyapa: root-writable debug sysctls feed an integer divide-by-zero in cyapa_poll_thread (kernel panic)
Where
- cyapa.c:227-235 β
cyapa_idle_freq(1),cyapa_slow_freq(20),cyapa_norm_freq(100) are module globals exported RW viaSYSCTL_INT(_debug, OID_AUTO, β¦, CTLFLAG_RW, β¦)with no bounds. - cyapa.c:1200 β the poll thread computes its sleep interval:
tsleep(&sc->poll_flags, 0, "cyapw", (hz + freq - 1) / freq); - cyapa.c:1202-1210 β
freqis re-assigned from one of the three sysctls every iteration (idle/slow/norm depending on open+activity state).
Bug
sysctl debug.cyapa_idle_freq=0 (or slow/norm) β root-writable, no
validation β makes the next poll iteration execute (hz + 0 - 1) / 0:
integer division by zero inside a kernel thread β #DE trap β kernel
panic. Negative values make tsleep take a negative timeout (separate
misbehavior).
PoC
model_div0.cexecutes the identical arithmetic in the identical integer types: raises SIGFPE in userspace (in kernel context: #DE β panic). Observed on the audit guest:RESULT: SIGFPE - integer division by zero raised(run.log).- On real hardware the one-liner is:
sysctl debug.cyapa_idle_freq=0(any state with the device attached; the idle frequency is selected wheneversc->count == 0, i.e. even with no process holding the device open).
Guest evidence (this run)
The sysctls register at module load (kldload cyapa.ko β see run.log) and
accept a write of 0 without panicking because the poll thread only
exists once the driver attaches to hardware β no SMBus controller/trackpad
exists in QEMU, so the division never executes here. The fault itself is
source-certain and demonstrated by the harness.
Fix
Clamp: if (freq < 1) freq = 1; before use (or use imax(freq,1)), plus
sysctl validation. See fix.diff.
Build / run
cc -O0 -Wall -o model_div0 model_div0.c ./model_div0
DF-4228 β VERDICT
Status: untested (kernel-side panic not exercisable on this guest β the poll thread exists only after the driver attaches to hardware, which requires a Cypress APA trackpad on SMBus addr 0x67; the arithmetic fault itself is demonstrated by harness and is source-certain).
Root cause (line-accurate)
cyapa_idle_freq/cyapa_slow_freq/cyapa_norm_freqare static ints exported read-write at cyapa.c:227-235 (SYSCTL_INT(..., CTLFLAG_RW, ...)) with no range enforcement βdebug.*sysctls are root-writable.cyapa_poll_thread(cyapa.c:1161) unconditionally computes(hz + freq - 1) / freqat cyapa.c:1200 each iteration.freqis refreshed from the sysctl globals at cyapa.c:1202-1210 (idle freq chosen wheneversc->count == 0β i.e. with no open fd, slow when idle, norm otherwise).- freq = 0 β integer division by zero in kernel thread context β x86-64 #DE exception in CPL0 β kernel panic.
What ran on the guest
model_div0.cβ identical expression(hz + freq - 1) / freqwith the identical types (int hz,int freq), freq=0: SIGFPE on the division (run.log: "RESULT: SIGFPE - integer division by zero raised").- Module lifecycle (run.log, shared with DF-4227 pack):
-
kldload cyapa.koβdebug.cyapa_*sysctls appear (registered at module load, device or not). -sysctl debug.cyapa_norm_freq=0accepted β guest stayed up, becausecyapa_poll_threadwas never started (no attach). This confirms the write path works and only the hardware-gated thread is missing.
Impact
Root-only trigger (debug.* sysctl write), but it is a one-syscall
deterministic kernel panic on any machine with the trackpad (Acer C720
class laptops). Low severity, DoS class.
Recommended fix
Clamp before the division (and ideally validate on sysctl write):
if (freq < 1)
freq = 1;
See fix.diff (applies clean against sys/).
Fix validation
Not possible on this guest (poll thread unreachable). fix_status = not_testable.
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
not_testableFix requires the attached device to validate on hardware; the one-line clamp is line-accurate against the verified arithmetic and applies cleanly to sys/.
findings/poc/DF-4228/fix.diff (git apply --check clean)
Confirmed kernel references
Detail
Exploit chain
root: sysctl debug.cyapa_idle_freq=0 -> next cyapa_poll_thread iteration executes (hz+0-1)/0 -> #DE in kernel thread -> panic
Evidence (decisive lines)
build.log + run.log (harness SIGFPE, deterministic), VERDICT.md, fix.diff (applies clean)
PoC changes
n/a - pack authored fresh
Verified recommended fix
clamp freq to >= 1 before the division (fix.diff) and validate the sysctls
Verdict
Source-certain divide-by-zero panic: (hz + freq - 1) / freq at cyapa.c:1200 with freq reloaded from unbounded root-writable RW sysctls (cyapa.c:227-235) at cyapa.c:1202-1210. Harness executing the identical expression with identical types raises SIGFPE on the guest (build.log/run.log). Kernel-side panic not exercisable on this guest because cyapa_poll_thread only starts after hardware attach (no SMBus controller/trackpad in QEMU; module loads and sysctl write of 0 was accepted without effect - see ../DF-4227/run.log). On trackpad hardware the trigger is one sysctl write.
No comments yet.