DF-2785 / verdict.json
{ "finding_id": "DF-2785", "status": "reproduced", "reproduced": 1, "impact": "panic", "confidence": "certain", "verdict": "sys_semop()'s SEM_UNDO rollback panic(\"semop - can't undo undos\") (sysv_sem.c:1004-1006) is reachable by an unprivileged user with two sibling threads: the reverse-order rollback 'cannot run out of space' guarantee is single-threaded only, because undo entries (keyed semid/semnum in the process-shared p_sem_undo) are mutated by sibling threads between the victim's per-call p_token sections. Victim vector {w,+1,U}{w,-1,U}{x,+1,U}{x,-1,U} with churn keeping un_cnt==semume==25 makes rollback of sops[1] find an absent entry in a full table -> EINVAL -> panic. Stock INVARIANTS guest panicked in ~3s (panic.txt). Patched kernel (panic->kprintf+break) survived 300s+ with 170 logged race events and 306M victim iterations.", "exploit_chain": "", "evidence": [ "panic.txt: 'panic: semop - can't undo undos', sys_semop+0x65d via syscall2", "run.fixed.log: guest up, 21247 failure-path errors, dmesg x170 'semop: SEM_UNDO rollback lost a race, pid 860'", "VERDICT.md: construction, timeline, baseline vs patched" ], "kernel_refs": [ "sys/kern/sysv_sem.c:984-1006", "sys/kern/sysv_sem.c:237-268" ], "poc_changes": "Two design iterations: (1) naive +1/-1 churn left 0 persistent entries (0 errors in 21M iters - kept as negative evidence); (2) persistent 25-filler setup + dip/re-fill churn with staggered threads panicked in ~3s.", "attempts": 2, "guest_uname": "DragonFly dfbsd 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": 420, "guest_dirty": 0, "build_cmd": "cc -O2 -Wall -pthread -o undo_race_panic undo_race_panic.c", "run_cmd": "./undo_race_panic (as uid 1001; guest panics within seconds)", "code_hash": "101b840a45c26c77b2e51d5e9480473fc387ff0e4857f641d64540ee3647ca49", "notes": "Unprivileged local DoS (kernel panic), reliable within seconds once the table-full oscillation is set up. First hammer attempt (lockstep churn) is retained as evidence that the bug requires the table-full precondition. Full upstream fix should serialize undo vectors per-process; fix.diff removes the crash and logs the condition.", "recommended_fix": "Replace the rollback panic with a kprintf+break (validated in-guest: no panic across 170 race events); longer term, hold a per-process undo mutex across the adjust/rollback phase.", "fix_status": "fixed", "fix_kernel_uname": "DragonFly dfbsd 6.5-DEVELOPMENT #1: Tue Sep 1 06:03:53 UTC 2026 root:dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64", "fix_baseline_reproduced": 1, "fix_patched_reproduced": 0, "fix_verdict": "Patched kernel (fix.diff, nativekernel RC=0, installkernel RC=0) survived 300s+ of the identical race that killed the stock kernel in 3s; 170 formerly-fatal events logged, guest stayed up.", "fix_evidence": [ "run.fixed.log: 'victim : 306184192 iters, 21247 errors' + dmesg count 170 + guest 'up'", "fix.diff" ] } |