# DF-0619 — Heap OOB read in `rip6_send` via short sockaddr

| Field        | Value                                                    |
|--------------|----------------------------------------------------------|
| ID           | DF-0619                                                  |
| Status       | REPRODUCED + FIX VALIDATED                               |
| Severity     | Medium                                                   |
| Impact       | info leak (26-byte kernel-heap over-read into on-stack `tmp`); limited userspace exfiltration |
| Confidence   | certain                                                  |
| Class        | CWE-125 Out-of-bounds Read                               |
| File         | sys/netinet6/raw_ip6.c:743                               |

## Build & run

```
cc -Wall -O2 -o poc_oob poc_oob.c     # build (any user)
sudo ./poc_oob                          # run as root (SYSCAP_NONET_RAW)
```

(Or `./build.sh && sudo ./run.sh`.)

## Expected — buggy kernel (`#0`, unpatched audit-source)

```
bind(2-byte sa)     rc=-1 errno=22 (Invalid argument)    # control: rip6_bind checks sa_len
connect(2-byte sa)  rc=-1 errno=22 (Invalid argument)    # control: rip6_connect checks sa_len
sendto(2-byte sa)   rc=-1 errno=65 (No route to host)    # BUG: rip6_send does NOT check sa_len
```

`sendto` returning anything other than `EINVAL` is the proof that the call
reached `rip6_send` (`raw_ip6.c:743`) and performed `tmp = *(struct sockaddr_in6 *)nam;`
— a 28-byte struct-deref copy from a 2-byte `M_SONAME` allocation. The 26
over-read bytes populate `tmp.sin6_port/sin6_flowinfo/sin6_addr/sin6_scope_id`
and are then used as the packet destination by `rip6_output`. The most common
outcome is `EHOSTUNREACH` because the corrupted destination is unroutable.

## Expected — fixed kernel (`#1`, single-fix)

```
bind(2-byte sa)     rc=-1 errno=22 (Invalid argument)    # unchanged
connect(2-byte sa)  rc=-1 errno=22 (Invalid argument)    # unchanged
sendto(2-byte sa)   rc=-1 errno=47 (Address family not supported by protocol family)
```

The new `sa_len != sizeof(struct sockaddr_in6)` check in `rip6_send` short-circuits
**before** the OOB copy and returns `EAFNOSUPPORT`. The over-read no longer happens.

## Reproduce from a fresh `vm.sh reset with-src`

```
scp -F dfbsd-qemu/config poc_oob.c dfbsd-maxx:poc/
ssh -F dfbsd-qemu/config dfbsd-maxx 'cd poc && cc -O2 -o poc_oob poc_oob.c'
ssh -F dfbsd-qemu/config dfbsd     'cd /home/maxx/poc && ./poc_oob'
```

## Files

- `poc_oob.c`      — minimal behavioral trigger (the deliverable PoC).
- `poc_leak.c`     — stress variant (20000 iters) used to confirm determinism.
- `fix.diff`       — git-apply-able one-line guard added to `rip6_send`.
- `build.sh / run.sh` — exact reproduce commands.
- `build.log / run.baseline.log / run.fixed.log` — full untrimmed outputs.
- `fix_build.log`  — full single-fix kernel build log.
- `VERDICT.md`     — detailed narrative + before/after.
- `manifest.json`  — artifact catalog.
