# DF-0473 — Out-of-bounds indirect function call in ip_fw3_chk (CWE-129/787)

`ip_fw3_chk` (`sys/net/ipfw3/ip_fw3.c:506-507`) indexes
`filter_funcs[cmd->module][cmd->opcode]` — a `[10][100]` (1000-entry) array —
with attacker-controlled `uint8_t` `module`/`opcode` that are **never
bounds-checked**. A crafted rule with `module>=10` or `opcode>=100` reads an
arbitrary kernel pointer and calls it => wild call => kernel panic (trap 9).

## Files

- `oobcall.c`     — main trigger: install OOB-index rule (cmd_len=2),
                    enable firewall, send packet -> panic.
- `add_oob.c`     — install-only test (safe on unpatched: no firewall enable).
- `add_legit.c`   — regression test (legitimate rule must still install).
- `nullcall.c`    — exercises the call-site NULL check (in-range/unregistered
                    opcode).
- `build.sh` / `run.sh` — exact build/run.
- `fix.diff`      — two-hunk fix (call-site bounds+NULL check + install-time
                    range validation).
- `VERDICT.md`    — full analysis + before/after fix validation.
- `panic.txt` / `run.log` / `fix_run.log` / `fix_build.log` / `env.txt` — evidence.

## Build

```
cc -Wall -o oobcall   oobcall.c
cc -Wall -o add_oob   add_oob.c
cc -Wall -o add_legit add_legit.c
cc -Wall -o nullcall  nullcall.c
```

## Run (ROOT only — raw socket + ipfw3 ctl path)

```
kldload ipfw3
sysctl net.inet.ip.fw3.enable=0
./oobcall            # UNPATCHED: kernel panic at ip_fw3_chk+0x1a4
```

**Expected (bug present):** `rc=0` on the rule add, then the firewall is
enabled and the guest panics on the next evaluated packet with
`Fatal trap 9 ... Stopped at ip_fw3_chk+0x1a4: ret`. (ssh dies; panic is in
`dfbsd-qemu/boot.log`.)

## Preconditions / threat model (honest)

- **Root-only trigger.** The rule-add path (`IP_FW_X`/`IP_FW_ADD`) needs a
  raw socket (root) and the `ipfw3` KLD module loaded. No unprivileged-user
  privilege boundary is crossed; the value is the **kernel memory-corruption
  primitive** (CWE-129 OOB indirect call / CWE-787 wild call), not LPE.
- **Distinct from DF-0472.** This PoC installs a *correctly-sized* rule
  (`cmd_len=2`, full data), so it survives DF-0472's `cmd_len` fix — DF-0473
  is an independent defect requiring its own call-site/install-time fix.

## Fix

`fix.diff` (two hunks):
1. **Call-site** (`ip_fw3.c:506`): bounds-check
   `module < MAX_MODULE && opcode < MAX_OPCODE_PER_MODULE` and NULL-check the
   function pointer; on failure skip the instruction (`goto next_cmd`).
2. **Install-time** (`ip_fw3_ctl_add_rule`, `:979`): walk the rule's
   instructions and `return EINVAL` if any has an out-of-range module/opcode.

After hot-swapping the patched `ipfw3.ko`: OOB rule add => `EINVAL`, no panic;
legitimate rules still accepted (`rc=0`).
