# DF-3589 — Unprivileged kernel panic: `CTLFLAG_ANYBODY` psm sysctls allow integer overflow to a zero divisor in `psmsmoother()`

## What

`hw.psm.synaptics.*` (and the `hw.psm.elantech.*` flavor) sysctls are
registered with **`CTLFLAG_ANYBODY`** — any local user may write them
(`sys/kern/kern_sysctl.c:1446` skips `SYSCAP_NOSYSCTL_WR` for ANYBODY
nodes). The write validator `synaptics_sysctl()`
(sys/dev/misc/psm/psm.c:5708-5816) only enforces `arg >= 1` for
`multiplicator`, `div_min`, `div_max`, `div_max_na`, `div_len`
(psm.c:5767-5780) — no upper bound.

The motion smoother then computes (psm.c:4307-4309):

```c
div_x = div_len * div_max_x / len;
div_x = imin(div_max_x, div_x);
div_x = imax(div_min, div_x);          /* div_min <= div_x <= div_max */
```

and divides by the 32-bit product (psm.c:4336-4344):

```c
smoother->squelch_x += smoother->avg_dx;
dxp = smoother->squelch_x / (div_x * multiplicator);
smoother->squelch_x = smoother->squelch_x % (div_x * multiplicator);
```

With `div_min = div_max = 65536` and `multiplicator = 65536` the product
`div_x * multiplicator` is `2^32`, which wraps to **0** in signed 32-bit
arithmetic (UB at the C level; on the shipped clang/gcc codegen it is a
plain `imul` followed by `idiv`). `idiv` with a zero divisor raises #DE —
in kernel context an immediate, unrecoverable panic. The `%` on line 4338
traps identically.

`psmsmoother()` runs from `proc_synaptics()` (psm.c:3639) and
`proc_elantech()` (psm.c:4804), i.e. on touchpad movement packets, for any
finger whose pressure ≥ `syninfo.min_pressure`. Setting
`hw.psm.synaptics.window_min=1` (allowed range 1..10) makes the very first
movement packet reach the division.

## Who

Any local user on any machine whose psm(4) probe found a Synaptics
touchpad, an Elantech touchpad, or a Synaptics-on-active-mux device —
i.e. the overwhelming majority of laptops. No privileges, no special
groups (the whole point of ANYBODY was letting desktop users tune
sensitivity — the same knob lets them overflow the divisor).

## Reproduce (real hardware)

```
./trigger.sh        # sysctl writes as the unprivileged user
# then move a finger on the touchpad
# -> kernel panics: divide by zero in psmsmoother
```

## Reproduce (this audit's QEMU guest) — NOT possible

The guest's emulated PS/2 device probes as "IntelliMouse Explorer"
(generic vendortype), so `enable_synaptics()`/`enable_elantech()` never
succeeded, the ANYBODY sysctl tree was never created, and the smoother
path is unreachable:

```
$ sysctl hw.psm.synaptics.multiplicator=65536
sysctl: unknown oid 'hw.psm.synaptics.multiplicator'
```

What WAS verified on the guest is the arithmetic itself, with the exact
expression compiled by the guest's own clang and executed in userland
(`divzero_expr.c`, build/run below): the product wraps to 0 and the
division traps with SIGFPE (exit 136, "Floating point exception (core
dumped)") — the userland manifestation of the same `idiv` #DE that
panics the kernel. The kernel-side control flow up to the division
(level of indirection removed: value ranges, clamps, and call ordering)
is cited line-by-line in VERDICT.md.

## Build / run (guest, unprivileged)

```
cc -O2 -Wall -o divzero_expr divzero_expr.c
./divzero_expr ; echo exit=$?
# div_x=65536 multiplicator=65536
# int32 product div_x*multiplicator = 0 (wrapped; 2^32 == 0)
# Floating point exception (core dumped)   exit=136
```

## Fix

Bound the ANYBODY-writable values that feed the divisor (see fix.diff):
cap `multiplicator`, `div_min`, `div_max`, `div_max_na`, `div_len` at
100000 and/or widen the divisor product to 64-bit in `psmsmoother()`.
