# DF-3358 — Unprivileged permanent rtmask-table pollution via RTM_GET + RTA_GENMASK

- **File**: `sys/net/rtsock.c` (`route_output`, lines ~738-748)
- **Class**: unprivileged kernel resource exhaustion / permanent memory
  consumption (local DoS)
- **Bucket**: base:net

## Prerequisites
- local unprivileged user account (no privilege, no jail escape, nothing)
- DragonFly default kernel — verified on `DragonFly 6.5-DEVELOPMENT #0
  X86_64_GENERIC` (INVARIANTS stock)

## Build
```
cc -O2 -Wall -o rtmask_poc rtmask_poc.c        # on the guest, base gcc
```

## Run
```
# baseline (root):
vmstat -m | grep routetbl
# exploit (unprivileged):
/tmp/rtmask_poc 100000                 # unique genmask per RTM_GET
vmstat -m | grep routetbl              # +~586K allocs, +73MB, permanent
# control (unprivileged):
/tmp/rtmask_poc 20000 same             # same mask repeated -> ZERO growth
```

## Expected result
Every `RTM_GET` message carrying a previously-unseen `RTA_GENMASK`
sockaddr makes the kernel permanently allocate
`RN_MAXKEYLEN + 2*sizeof(struct radix_node)` = 128 bytes **per CPU**
(guest has 6 CPUs → 768 B/message) in the `M_RTABLE` ("routetbl") pool.
The mask trees never shrink and the key space is attacker-chosen.

Measured on the guest (uid 1001 `maxx`):

| run | routetbl Count | routetbl MemUse |
|-----|----------------|-----------------|
| baseline | 234 | 38.0K |
| after 100k unique-mask RTM_GET (9.2 s) | 586K | 73.3M |
| after 20k **same**-mask RTM_GET (control) | 586K (unchanged) | 73.3M |
| after 600k more unique (ENOBUFS at iter 532,426) | 3.05M | **390M (type limit)** |

After exhaustion the system-wide routing plane is bricked until reboot:
`route add` fails ("routing table overflow") **even for root**, getifaddrs
fails inside route(8), and the kernel logs
`arpresolve: can't allocate llinfo` for any new neighbor.

## Fix
`fix.diff` — require `SYSCAP_RESTRICTEDROOT` when an RTM_GET carries a
genmask (root semantics unchanged; plain unpriv RTM_GET unchanged).

## Files
- `rtmask_poc.c` — PoC source
- `build.sh`, `run.sh` — exact commands
- `build.log` — compiler output
- `run.log` — 100k unique run + routetbl before/after
- `run.2.log` — 600k run hitting the 390M malloc-type limit (ENOBUFS @ 532,426)
- `run.3.log` — post-exhaustion impact probe (route add fails as root,
  arpresolve failures)
- `env.baseline.txt` — guest uname + baseline vmstat
- `fix.diff` — the fix (validated: see VERDICT.md)
- `VERDICT.md`, `manifest.json`, `verdict.json`
