β¬’ DragonFlyBSD Kernel Audit
← triage Β· dashboard
DF-0705

Local DoS / panic via out-of-order ioctls, kthread_create failure, and negative count in show_conf

Summary

LATENT (dead code). Three independent panics: (1) edge_start :248 sobind(edge_sock) no NULL check calling before edge_conf panics. (2) edge_start :262-264 panic() on kthread_create fail instead of return error. (3) show_conf :105-116 int size=3*sizeof(int)+count*LEN_SYNC_EDGE negative count -> size small bypasses sopt_valsize check bcopy length=(size_t)(count*8) ~4GiB -> page fault panic. Fix: NULL check+return error+count bounds.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-0705 Β· 9 files
FileTypeDescriptionSize
ipfw3_sync_probe.c trigger-source issues EDGE_START / CENTRE_CONF(-1) / SHOW_CONF 3.3 KB view raw
build.sh build-script cc -O2 -Wall 140 B view raw
run.sh run-script kldload ipfw3 + ipfw3_basic + run probe 688 B view raw
run.log run-log all 3 opcodes return rc=0; no panic 2.2 KB view raw
VERDICT.md verdict this analysis 2.9 KB ↓ raw
fix.diff suggested-fix NULL check + kthread error return + count bounds 1.9 KB view raw
README.md readme human reproduce doc 1.7 KB ↓ raw
../fix_build_combined.log build-log Combined 41-finding kernel build (rc=0, -Werror clean) 5.6 MB ↓ download
../fix_build_summary.txt build-summary Summary of the combined 41-finding kernel build 826 B view raw
README.md readme human reproduce doc
↓ download raw

DF-0705 β€” Three independent panics in ip_fw3_sync.c

Summary

sys/net/ipfw3_basic/ip_fw3_sync.c has three latent panic paths:

  1. edge_start:248 β€” sobind(fw3_sync_ctx.edge_sock,...) with no NULL check; if edge_conf was never called, edge_sock is NULL.
  2. edge_start:262-264 β€” panic("...:error %d",error) on kthread_create failure instead of returning the error.
  3. show_conf:105-116 β€” int size = 3*sizeof(int) + count*LEN_SYNC_EDGE with signed count; negative count makes size small, bypasses sopt_valsize < size, then bcopy(...,count*LEN_SYNC_EDGE) becomes a ~4 GiB write β†’ page fault.

How to reproduce

Cannot reproduce on a default kernel β€” see VERDICT.md and run.log. Same dead-code reason as DF-0704: ip_fw3_ctl_sync_ptr is never set, so the IP_FW_SYNC_* opcodes silently fall through.

./build.sh
ssh dfbsd 'sysctl net.filters_default_to_accept=1; kldload ipfw3.ko; kldload ipfw3_basic.ko'
ssh dfbsd 'cd /root/poc/DF-0705 && ./run.sh'
# expect: probe prints "All three returned without panic"

Preconditions

  • root (IP_FW_X requires raw IP socket).
  • AND ip_fw3_ctl_sync_ptr must be non-NULL (never happens in default source).

Impact

LATENT — currently zero. Would become root→kernel DoS once the sync dispatch is wired up.

Fix

fix.diff addresses all three:

  • edge_start β€” NULL-check fw3_sync_ctx.edge_sock (return EINVAL); replace panic() on kthread_create failure with kprintf + return error.
  • show_conf β€” reject negative fw3_sync_ctx.count; cast size to size_t for the sopt_valsize compare.
  • centre_conf β€” validate ioc_centre->count is non-negative and bounded (≀ MAX_EDGES).
VERDICT.md verdict this analysis
↓ download raw

DF-0705 β€” Three independent panics in ip_fw3_sync.c (edge_start / show_conf)

Verdict: NOT REPRODUCED (LATENT β€” same dead-code reason as DF-0704)

Cited panics (all in sys/net/ipfw3_basic/ip_fw3_sync.c)

  1. edge_start line 248 β€” sobind(fw3_sync_ctx.edge_sock, ...) with no NULL check. If edge_conf has not been called first, fw3_sync_ctx.edge_sock is NULL β†’ sobind derefs NULL.
  2. edge_start line 262-264 β€” panic("...:error %d",error) on kthread_create failure instead of returning the error.
  3. show_conf line 105-116 β€” int size = 3*sizeof(int) + count*LEN_SYNC_EDGE where count is signed; a negative count makes size small, bypassing if (sopt_valsize < size), then bcopy(..., count*LEN_SYNC_EDGE) with count cast to size_t becomes a ~4 GiB write β†’ page fault.

Why none of them reproduce

Same root cause as DF-0704: the dispatch pointer ip_fw3_ctl_sync_ptr (sys/net/ipfw3/ip_fw3.c:133) is initialised to NULL and never assigned anywhere in the source tree. The IP_FW_SYNC_* sockopt cases fall through the if (ip_fw3_ctl_sync_ptr != NULL) guard at line 1125 with no effect.

The probe ipfw3_sync_probe.c issues the three "panic-trigger" opcodes (IP_FW_SYNC_EDGE_START = 85, IP_FW_SYNC_CENTRE_CONF = 89 with count=-1, IP_FW_SYNC_SHOW_CONF = 82) via IP_FW_X setsockopt on a raw IP socket. After loading ipfw3.ko and ipfw3_basic.ko, all three return rc=0 with no effect β€” the dispatch pointer is still NULL:

[fire opcode=85 plen=0]  setsockopt rc=0 errno=0   # edge_start, NULL edge_sock
[fire opcode=89 plen=4]  setsockopt rc=0 errno=0   # centre_conf, count=-1
[fire opcode=82 plen=64] setsockopt rc=0 errno=0   # show_conf, negative count
[+] All three returned without panic.

Guest stays up. The cited panics are unreachable on a default kernel.

Privilege note

Even when the dispatch pointer is hooked up (a one-line source change), the IP_FW_X path requires a raw IP socket, which requires caps_priv_check(SYSCAP_NONET_RAW) (sys/netinet/raw_ip.c:473). So the cited panics are root-only triggers regardless. Root→kernel panic is a hardening gap, not an unprivileged escalation.

Fix

fix.diff addresses all three:

  • edge_start β€” NULL check on fw3_sync_ctx.edge_sock (return EINVAL); replace panic() on kthread_create failure with kprintf + return error.
  • show_conf β€” reject negative fw3_sync_ctx.count before computing size; cast size to size_t for the sopt_valsize compare.
  • centre_conf β€” validate ioc_centre->count is non-negative and bounded (≀ MAX_EDGES) before the kmalloc/bcopy.

Combined with the DF-0704 fix, this hardens the entire ipfw3_sync code path against the listed panics for whenever someone wires it up.

Files

  • ipfw3_sync_probe.c β€” same probe as DF-0704 (also confirms DF-0705 dead)
  • run.log β€” probe output
  • fix.diff β€” NULL check + kthread error + count bounds
  • VERDICT.md β€” this analysis

Fix verification

not_testable

n/a

see evidence pack

Confirmed kernel references

β€”

Detail

Exploit chain

none

Evidence (decisive lines)

β€”

Verdict

LATENT dead code. ip_fw3_sync edge_start NULL deref + panic() + show_conf underflow. ip_fw3_ctl_sync_ptr never assigned.