# DF-4228 — cyapa: root-writable debug sysctls feed an integer divide-by-zero in cyapa_poll_thread (kernel panic)

## Where
`sys/dev/smbus/cyapa/cyapa.c`

- cyapa.c:227-235 — `cyapa_idle_freq` (1), `cyapa_slow_freq` (20),
  `cyapa_norm_freq` (100) are module globals exported RW via
  `SYSCTL_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 — `freq` is 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.c` executes 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 whenever `sc->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
```
