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)
PoC verification
Evidence pack
findings/poc/DF-0705 Β· 9 files| File | Type | Description | Size | |
|---|---|---|---|---|
| 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 |
DF-0705 β Three independent panics in ip_fw3_sync.c
Summary
sys/net/ipfw3_basic/ip_fw3_sync.c has three latent panic paths:
edge_start:248βsobind(fw3_sync_ctx.edge_sock,...)with no NULL check; ifedge_confwas never called,edge_sockis NULL.edge_start:262-264βpanic("...:error %d",error)onkthread_createfailure instead of returning the error.show_conf:105-116βint size = 3*sizeof(int) + count*LEN_SYNC_EDGEwith signedcount; negativecountmakessizesmall, bypassessopt_valsize < size, thenbcopy(...,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_Xrequires raw IP socket). - AND
ip_fw3_ctl_sync_ptrmust 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-checkfw3_sync_ctx.edge_sock(return EINVAL); replacepanic()onkthread_createfailure withkprintf+ return error.show_confβ reject negativefw3_sync_ctx.count; castsizetosize_tfor the sopt_valsize compare.centre_confβ validateioc_centre->countis non-negative and bounded (β€ MAX_EDGES).
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)
edge_startline 248 βsobind(fw3_sync_ctx.edge_sock, ...)with no NULL check. Ifedge_confhas not been called first,fw3_sync_ctx.edge_sockis NULL β sobind derefs NULL.edge_startline 262-264 βpanic("...:error %d",error)onkthread_createfailure instead of returning the error.show_confline 105-116 βint size = 3*sizeof(int) + count*LEN_SYNC_EDGEwherecountis signed; a negativecountmakessizesmall, bypassingif (sopt_valsize < size), thenbcopy(..., count*LEN_SYNC_EDGE)withcountcast tosize_tbecomes 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 onfw3_sync_ctx.edge_sock(return EINVAL); replacepanic()onkthread_createfailure withkprintf+ return error.show_confβ reject negativefw3_sync_ctx.countbefore computingsize; castsizetosize_tfor the sopt_valsize compare.centre_confβ validateioc_centre->countis 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 outputfix.diffβ NULL check + kthread error + count boundsVERDICT.mdβ this analysis
Fix verification
not_testablen/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.
No comments yet.