DF-2575 / panic.txt
Fatal trap 9: general protection fault while in kernel mode
cpuid = 0; lapic id = 0
instruction pointer = 0x8:0xffffffff82600100
stack pointer = 0x10:0xfffff8008d1f88b0
frame pointer = 0x10:0xfffff8008d1f8910
code segment = base 0x0, limit 0xfffff, type 0x1b
= DPL 0, pres 1, long 1, def32 0, gran 1
processor eflags = interrupt enabled, resume, IOPL = 0
current process = Idle
current thread = pri 12
kernel: type 9 trap, code=0
CPU0 stopping CPUs: 0x0000003e
stopped
Stopped at ip_fw3_chk+0x100: movzbl 0x16(%rax),%ecx
db>
---
Context (from dfbsd-qemu/boot.log, lines 254-273):
+++ ipfw: ouch!, skip past end of rules, denying packet <- silent UAF (stale rule data read)
+++ ipfw: ouch!, skip past end of rules, denying packet [... many lines ...]
Fatal trap 9: general protection fault while in kernel mode
[...see above...]
Stopped at ip_fw3_chk+0x100: movzbl 0x16(%rax),%ecx
db>
Analysis:
ip_fw3_chk+0x100 is in the rule-scan loop. After dummynet re-injects a
queued packet, ip_fw3_check_in() loads args.rule = dn_priv (the dangling
pointer to the freed rule). With one_pass=0, ip_fw3_chk() does:
f = args->rule->next_rule; // reads freed M_IPFW3 slab
Under debug.use_weird_array=1, the freed slab is poisoned with
0xdeadc0de. next_rule becomes 0xdeadc0dedeadc0de (non-NULL, non-canonical).
The scan loop then tries to read f->rulenum at offset 0x16 from the
poisoned pointer rax -> general protection fault (trap 9).
The instruction movzbl 0x16(%rax),%ecx reads the byte at offset 0x16
(=22) from rax. In struct ip_fw, offset 22 is 'set' (uint8_t), just
before 'flags' at 23. The scan loop reads rule fields to check matches.
Note: even WITHOUT use_weird_array (default=0), the UAF is still present —
it silently reads stale-but-plausible freed rule data (the "ouch" messages
prove this). The poisoning just makes it crash deterministically.