# DF-4229 — VERDICT

**Status: untested** (kernel-side leak requires an open `/dev/cyapa*` fd,
which requires the trackpad hardware absent from this guest; the control
flow and the uninitialized stack read are reproduced deterministically by
the exact-model harness — 3/3 poison leaks on the audit guest).

## Root cause (line-accurate)
`cyapawrite` (cyapa.c:786-1057):
```c
int error;                        /* cyapa.c:791  -- never initialized  */
...
again:
cyapa_lock(sc);
while ((n = fifo_space(&sc->wfifo)) > 0 && uio->uio_resid) {  /* :802 */
        if (n > uio->uio_resid)
                n = uio->uio_resid;
        error = uiomove(fifo_write(&sc->wfifo, 0), n, uio);   /* :805 */
        ...
}
cmd_completed = (fifo_ready(&sc->wfifo) != 0);                /* :814 */
while (fifo_ready(&sc->wfifo) && cmd_completed && error == 0) /* :815 uninit read */
...
if (error == 0 && (cmd_completed || uio->uio_resid))          /* :1054 uninit read */
        goto again;
return error;                                                 /* :1056 leak */
```
When `uio->uio_resid == 0` the copy loop at :802 is skipped and `error`
reaches :815/:1054/:1056 unassigned. The value is whatever the calling
thread's kernel stack held at that offset (prior syscall frames).

## Trigger path (cited every hop)
write(2) → dofilewrite (sys/kern/sys_generic.c:506, no resid==0
short-circuit) → vn_write (sys/kern/vfs_vnops.c) → devfs_write
(sys/vfs/devfs/devfs_vnops.c:1366) → dev_dwrite (sys/kern/kern_device.c)
→ cyapawrite with uio_resid == 0.

A second (narrower) entry — wfifo full at :802 with resid > 0 — also
skips the copy loop, but wfifo-full-on-entry is not reachable through the
driver's own state machine; the zero-length write is the clean trigger.

## Harness result (audit guest, cc 8.3, -O0)
```
write(/dev/cyapa*, buf, 0) returned: 0xabababab (-1414812757)
RESULT: UNINITIALIZED STACK VALUE LEAKED (poison 0xABABABAB observed)   x3/3
```
The model reproduces cyapawrite()'s exact branch structure; the poison
pattern placed in the stack region below the function's frame surfaces as
the function's return value — the same data flow as the kernel leak.

## Impact / severity
32 bits of stale kernel stack per call, repeatable at will by the fd
holder. Device is 0600 root:wheel → attacker must be root or hold an
inherited fd (Xorg children). Low severity, kernleak class.

## Recommended fix
`int error = 0;` — one-line fix (fix.diff, applies clean).

## Fix validation
Kernel-side validation needs the device (open fd on /dev/cyapa*); the fix
is a trivial initializer whose correctness is self-evident against the
traced path. 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.
