# DF-0023 — PoC

`einval_noop.c` — `read`/`write` with `nbyte > SSIZE_MAX` do not return
`EINVAL` because the guard in `sys_read`/`sys_write`/`sys_extpwrite` assigns
`error = EINVAL` but never `return`s.  The sibling `sys_extpread` does the
same check correctly (`return(EINVAL);`), so the guard is provably a no-op.

`write_only.c` — separate probe for the `sys_write` path
(`sys/kern/sys_generic.c:336-337`).

## The bug

`sys_read` (`sys/kern/sys_generic.c:130-131`), `sys_write` (`:336-337`),
`sys_extpwrite` (`:368-369`):

```c
if ((ssize_t)uap->nbyte < 0)
    error = EINVAL;          /* NO return -> overwritten by kern_preadv/pwritev */
```

The sibling `sys_extpread` (`:161-162`) does the same check correctly:
`return(EINVAL);`.  So the `nbyte > SSIZE_MAX` guard is a no-op.

## Observed impact

1. **Correctness (Info-rated):** `read(/dev/null, buf, SIZE_MAX)` returns
   `0 errno=0` instead of `-1/EINVAL`.  The POSIX `ssize_t` return contract
   is silently broken.
2. **Local DoS (stronger than rated):** `write(/dev/null, buf, SSIZE_MAX+1)`
   hangs in an **infinite, uninterruptible** kernel loop in
   `kern_memio.c:mmrw` (`u_int c` truncates the 64-bit `iov_len` to 0, so
   `uio_resid` never decreases).  `SIGKILL` cannot reap the process — it
   never leaves the kernel.  An unprivileged user can pin every CPU core
   with unkillable processes.

## Build & run (unprivileged)

```
./build.sh          # cc -o einval_noop einval_noop.c; cc -o write_only write_only.c
./run.sh            # runs einval_noop, then write_only under `timeout 12`
```

## Expected output

**Bug present (unpatched `#0`):**
```
read(fd,buf,SIZE_MAX) = 0, errno=0 (NOT EINVAL)
write child PID <n>: HUNG in kernel after 4s (DoS - uninterruptible infinite loop in mmrw)
after SIGKILL: child STILL ALIVE (unkillable in kernel loop)
PATCHED write(fd,buf,SSIZE_MAX+1) = <never returns; timed out>
```

**Fixed (patched `#1`):**
```
read(fd,buf,SIZE_MAX) = -1, errno=22 (EINVAL)
PATCHED write(fd,buf,SSIZE_MAX+1) = -1, errno=22 (EINVAL)
```

No memory corruption is produced (downstream `uiomove`/`copyout` bound any
data transfer to the user address range), so this is a correctness + local-DoS
finding, not a privilege-escalation primitive.
