# DF-0751 — MPLS explicit-NULL infinite loop — PoC & evidence pack

## TL;DR

A single MPLS Ethernet frame (EtherType 0x8847, label=0 or 2, S-bit CLEAR)
causes `mpls_input()` (`sys/netproto/mpls/mpls_input.c`) to enter an infinite
`goto again` loop because the mbuf cursor is never advanced (`m_adj` is missing).
One CPU pegs at 100% holding the mplock; the kernel freezes silently (no panic,
no dmesg). Power-cycle required. Remote unauthenticated on-link DoS.

**Verdict: REPRODUCED (live + harness). Fix VALIDATED.**

## Files

| file | purpose |
|---|---|
| `mpls_loop_harness.c` | **Primary deterministic proof.** Embeds `mpls_input`'s loop verbatim with a depth-counter escape hatch. Run as unprivileged user. Prints iteration count: 1,000,001 (capped = infinite) for label=0/S=0; 10 (terminates) when the fix is applied. |
| `mpls_trigger.c` | **Live trigger.** Injects one MPLS frame via `bpf` write with `BIOCSFEEDBACK` on `vtnet0`. Requires root (to open `/dev/bpf`); simulates an on-link attacker. |
| `Makefile` | KLD module Makefile for `mpls.ko` (MPLS is `optional mpls`, not in GENERIC). |
| `fix.diff` | Standalone `git apply`-able fix: `m_adj` before each `goto again` + depth cap (32). |
| `VERDICT.md` | Full narrative with `path:line` cites, mechanism, before/after. |
| `build.log` / `run.log` | Harness build + decisive run (full untrimmed). |
| `module_build.log` | `mpls.ko` build output. |
| `live_wedge.txt` | Live-kernel wedge evidence (vm.sh status, ssh RC, panic count). |
| `boot_wedge_live.log` | `boot.log` snapshot at wedge time (frozen, no panic). |
| `fix_build.log` | Patched `mpls.ko` build output. |
| `fix_run.log` | Patched-module trigger results (3× frame, guest stays alive). |
| `env.txt` | Guest `uname`, `cc` version, `kldstat`. |
| `manifest.json` | Machine-readable artifact catalog. |

## Reproduce

### Path A — harness (deterministic, no module load, unprivileged)

```sh
./build.sh harness     # cc -O2 -o mpls_loop_harness mpls_loop_harness.c
./run.sh   harness     # ./mpls_loop_harness
```
Expected: `*** INFINITE LOOP CONFIRMED ***` (1,000,001 iterations, cursor
never advances) for the unpatched loop; `loop TERMINATES cleanly` for the
patched loop.

### Path B — live kernel wedge (requires root on guest, needs `mpls.ko`)

```sh
./build.sh module      # builds mpls.ko from /usr/src (Makefile included)
./run.sh   module      # kldload + fire trigger; guest wedges — vm.sh reset to recover
```
**WARNING:** Path B hard-wedges the guest. Only run if you can power-cycle.
The harness (Path A) is the recommended deterministic proof.

### Fix validation

```sh
cd /usr/src && patch -p1 < fix.diff                              # apply fix
cd sys/netproto/mpls && make && cp mpls.ko /boot/kernel/          # rebuild
kldload mpls.ko                                                   # load patched
/root/mpls_trigger vtnet0                                         # re-run trigger
# guest stays alive — fix is effective
```
