DragonFlyBSD Kernel Audit
DF-0472 / panic.txt
← back to finding ↓ download raw
DF-0472 - OOB function-pointer call -> kernel panic (trap 9, GP fault)
=====================================================================
(excerpt from dfbsd-qemu/boot.log; guest entered DDB, ssh died)

Trigger: ./panic  (root)
  - setsockopt(IP_FW_X, IP_FW_ADD) installs a rule with cmd[0].module=0x80,
    cmd[0].opcode=0x80, cmd_len=255 (the unvalidated field).
  - sysctl net.inet.ip.fw3.enable=1 re-hooks pfil.
  - one outbound UDP packet -> ip_fw3_check_out -> ip_fw3_chk iterates the
    rule chain, hits our rule first, and at sys/net/ipfw3/ip_fw3.c:506 does
        (filter_funcs[cmd->module][cmd->opcode])(...);
    filter_funcs is [10][100]; index 0x80*100+0x80 = 12928 is ~11928 entries
    PAST the 1000-entry array => reads a wild pointer from neighbouring kernel
    memory and CALLS it.

ipfw3.ko was loaded at 0xffffffff82600000 (kldstat); the faulting RIP
0xffffffff826001a4 == ipfw3.ko+0x1a4, ddb symbolises it as ip_fw3_chk+0x1a4.
The fault is a #GP (trap 9) on a `ret` -- the wild call ran a few garbage
instructions off the corrupted pointer/stack and faulted returning. This
proves the attacker-controlled module/opcode reached the indirect call.

------------------------------------------------------------------------
Fatal trap 9: general protection fault while in kernel mode
cpuid = 5; lapic id = 5
instruction pointer     = 0x8:0xffffffff826001a4
stack pointer           = 0x10:0xfffff8008d271760
frame pointer           = 0x10:0xfffff8008d2717d0
code segment            = base 0x0, limit 0xfffff, type 0x1b
                        = DPL 0, pres 1, long 0, def32 0, gran 1
processor eflags        = interrupt enabled, resume, IOPL = 0
current process         = Idle
current thread          = pri 12
kernel: type 9 trap, code=0

CPU5 stopping CPUs: 0x0000001f
 stopped
Stopped at      ip_fw3_chk+0x1a4:       ret
db>
------------------------------------------------------------------------

IMPACT: a kernel memory-corruption primitive (attacker-influenced indirect
call). On this guest SMEP/SMAP are OFF, so the called pointer could be steered
at userspace shellcode (commit_creds(prepare_kernel_cred(0))) given a heap-
grooming chain that lands a chosen value at filter_funcs[0x80][0x80]; here it
is demonstrated at the panic (DoS) level. Root-only trigger (raw socket +
firewall enable).