DF-2683 / verdict.json
{ "finding_id": "DF-2683", "status": "reproduced", "reproduced": 1, "impact": "panic", "confidence": "certain", "verdict": "fsetown() (kern_descrip.c:1296-1380) inserts the zeroed sigio into proc->p_sigiolst / pgrp->pg_sigiolst at lines 1351/1357 and initializes sio_pgid/sio_ucred/sio_ruid/sio_myref only afterwards (1362-1366, after the owner token is dropped). Teardown walkers -- exit1()->funsetownlst() (kern_exit.c:376) and pgdelete()->funsetownlst() (kern_proc.c:680) -- consume the half-born entry: funsetown(NULL) NULL-page fault, or with sio_pgid still 0 the wrong owner branch makes SLIST_REMOVE walk off the list (fault at NULL+8). Unprivileged harness (fork short-lived same-session children + hammer F_SETOWN(child_pid)) reproduced twice on the stock kernel: run 1 hard-wedged the machine (funsetownlst livelock, no console output); run 2 gave 'Fatal trap 12 ... fault virtual address = 0x8 ... Stopped at funsetown+0x93: movq 0x8(%rdx),%rax' attributed to the unprivileged fsetown_race process, kernel halted in DDB.", "exploit_chain": "unprivileged fork storm + fcntl(F_SETOWN, child_pid) hammer -> child's exit1() funsetownlst() walk lands inside fsetown()'s insert->init window -> NULL-deref / wrong-list SLIST_REMOVE -> fatal kernel trap (demonstrated). Impact ceiling is local DoS (panic / permanent machine wedge); no memory-disclosure or control primitive identified for this path.", "evidence": [ "panic.txt: 'Fatal trap 12 ... fault virtual address = 0x8 ... Stopped at funsetown+0x93' from unprivileged fsetown_race", "run.log: both stock runs (run 1 silent wedge, run 2 trap after 'round 0 (162 sets)')", "panic.dbg.txt: instrumented-fix crash (funsetown_free+0x95) documenting the fix-failed iteration", "VERDICT.md: root cause with exact line numbers, all three consumption variants, fix iteration history v1-v4" ], "kernel_refs": [ "sys/kern/kern_descrip.c:1347", "sys/kern/kern_descrip.c:1351", "sys/kern/kern_descrip.c:1357", "sys/kern/kern_descrip.c:1362", "sys/kern/kern_descrip.c:1366", "sys/kern/kern_exit.c:376", "sys/kern/kern_proc.c:680" ], "poc_changes": "Added <sys/socket.h> include and a per-500-round progress print vs the seed sketch; core choreography unchanged.", "attempts": 2, "guest_uname": "DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #0: Thu Jul 2 06:02:54 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64", "runtime_sec": 460, "guest_dirty": 1, "build_cmd": "cc -O2 -o fsetown_race fsetown_race.c", "run_cmd": "./fsetown_race 20000", "code_hash": "8b696e1fdc65767e7c24df8abab393f67da0df189960c1010fa6b0f865660a8e", "notes": "fix.diff v4 (init-before-insert + funsetown/funsetownlst restructure with sleep-retry) compiles and boots but the 20000-round storm still crashes the restructured replacement machinery via a recycled-chunk double teardown (funsetown_free walk-off); fix_status=fix_failed after 4 documented iterations. Guest was reset with-src after the runs.", "recommended_fix": "Initialize every sigio field (including sio_proc/sio_pgrp and sio_myref) before the owner-list insertion, publish *sigiop only after the entry is fully linked, and give funsetownlst an atomic check-and-claim of the head entry under sigio_token (ideally replace the token composition with a per-sigio refcount)." } |