DragonFlyBSD Kernel Audit
DF-2785 / verdict.json
← back to finding ↓ download raw
{
  "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"
  ]
}