# DF-0729 — NULL mbuf dereference in P2P (point-to-point) routing-loop detector

## Summary

`sys/netinet6/ip6_forward.c:259` — the IFF_POINTOPOINT routing-loop detector in
the IPv6 forwarding path — calls `icmp6_error(mcopy, ...)` without checking if
`mcopy == NULL`. The `mcopy` comes from `m_copym(m, 0, ..., M_NOWAIT)` at line
138, which returns NULL under memory pressure (mbuf objcache exhaustion). All
four sibling callers in the same function (lines 159, 181, 215, 224) guard NULL;
this one does not. `icmp6_error()` (`icmp6.c:264`) immediately dereferences
`m->m_flags` (offset 0x1c) — a NULL-page fault → kernel panic.

## Severity: Medium (DoS — requires memory pressure precondition)

## How to reproduce

### Prerequisites
- DragonFlyBSD guest with the unpatched audit-source kernel (#0).
- Root access to load the harness module (for the deterministic proof).

### Build
```sh
./build.sh    # builds df729_harness.ko + userspace triggers
```

### Run (deterministic harness — PRIMARY PROOF)
```sh
./run.sh      # loads module, drains mbufs, triggers icmp6_error(NULL)
```

**Expected on unpatched kernel (#0):** kernel panic
```
Fatal trap 12: page fault while in kernel mode
fault virtual address = 0x1c
Stopped at icmp6_error+0x54: movl 0x1c(%rbx),%eax
```

**Expected on patched kernel (#1):** returns normally, system stays alive.

### Live network path (attempted, documented)
See `setup.sh` for the gif self-tunnel + IPv6 forwarding configuration that
exercises the real `ip6_forward` code path. Under mbuf exhaustion, the
network-stack chicken-and-egg problem (the exhaustion prevents the trigger
packet from arriving) makes the live trigger probabilistic. The harness
provides the deterministic proof.

## Files

| File | Purpose |
|------|---------|
| `df729_harness.c` | Kernel module: deterministic mbuf drain + icmp6_error(NULL) trigger |
| `Makefile` | Module build |
| `df729_trigger.c` | Userspace mbuf-exhaustion flood (proves objcache exhaustion) |
| `df729_udp_trigger.c` | Network-path UDP trigger (for gif routing loop) |
| `setup.sh` | gif self-tunnel + forwarding + route setup (root) |
| `build.sh` | Build all components |
| `run.sh` | Run the deterministic harness |
| `fix.diff` | The fix (git apply-able) |
| `VERDICT.md` | Full analysis |
| `panic.txt` | Baseline panic signature (unpatched) |
| `fix_run.log` | Patched-kernel survival proof |
| `fix_build.log` | Single-fix kernel build log |
| `manifest.json` | Machine-readable catalog |

## Fix

1. `ip6_forward.c:259`: add `if (mcopy)` guard (matching siblings)
2. `icmp6.c:262`: add `if (m == NULL) return;` (defense-in-depth)
