⬢ DragonFlyBSD Kernel Audit
DF-5374 / verdict.json
← back to finding ↓ download raw
{
  "finding_id": "DF-5374",
  "status": "reproduced",
  "reproduced": true,
  "impact": "dos",
  "confidence": "certain",
  "verdict": "REPRODUCED: deterministic NULL-deref kernel panic from one 8-byte write(2) (or one read(2)) on /dev/targ before any TARGIOCENABLE. targwrite (sys/bus/cam/scsi/scsi_target.c:566-602) and targread (:874) call cam_periph_lock(softc->periph) with softc->periph == NULL (only targctor :522 sets it); cam_periph_lock is CAM_SIM_LOCK(periph->sim) (cam_periph.h:186-190). Guest proof: Fatal trap 12, fault virtual address 0x40 (= offsetof(struct cam_periph, sim)), Stopped at targwrite+0x130: movq 0x40(%rax),%rax, guest dead in DDB. Unprivileged users cannot reach it on the stock guest (clone node 0600 root:wheel + SYSCAP_RESTRICTEDROOT; verified live: EACCES/EPERM for non-root), so the attacker is the privileged/compromised target daemon or an operator granted the node via devfs rules. Fix validated on a patched kernel: both write() and read() now return ENXIO with no panic.",
  "exploit_chain": "open(\"/dev/targ\", O_RDWR) -> write(fd, &ptr, 8) with ptr to any user CCB -> targwrite -> cam_periph_lock(NULL) -> read at NULL+0x40 -> Fatal trap 12 -> kernel panic (local DoS; no escalation potential from this primitive itself).",
  "evidence": "panic.txt (Fatal trap 12, fault va 0x40, Stopped at targwrite+0x130 movq 0x40(%rax),%rax); run.log (write-mode + unpriv EACCES); env.txt (uname, /dev/targ 0600 root:wheel); run.patched.log (write/read return ENXIO=6, guest alive).",
  "kernel_refs": [
    "sys/bus/cam/scsi/scsi_target.c:566",
    "sys/bus/cam/scsi/scsi_target.c:588",
    "sys/bus/cam/scsi/scsi_target.c:602",
    "sys/bus/cam/scsi/scsi_target.c:874",
    "sys/bus/cam/scsi/scsi_target.c:880",
    "sys/bus/cam/scsi/scsi_target.c:522",
    "sys/bus/cam/cam_periph.h:186"
  ],
  "poc_changes": "No seed existed (pass-2 finding). PoC is minimal: open + 8-byte write of a pointer to a zeroed union ccb with func_code=XPT_NOOP; read-mode variant included.",
  "attempts": 2,
  "guest_uname": "DragonFly dfbsd 6.5-DEVELOPMENT #0: Sat Oct 3 17:18:54 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64 (baseline) / #3: Sat Oct 3 18:32:37 UTC 2026 (patched)",
  "runtime_sec": 300,
  "guest_dirty": 0,
  "build_cmd": "cd /root/targpwn && cc -O0 -g -o poc5374 poc5374.c",
  "run_cmd": "cd /root/targpwn && ./poc5374 w   (as root; guest panics)",
  "code_hash": "5abba336a272f5bbb46068f8e2215baeee272abe441def70e532ab00b00c4e75",
  "notes": "Kernel built in-guest with option targ (conf/files optional-gated; conf/options needs a targ line for config(8) -- documented in env). Guest reset (with-src) after the run.",
  "recommended_fix": "Reject I/O on unenabled softc: in targwrite()/targread() return ENXIO when softc->periph == NULL or !(softc->state & TARG_STATE_LUN_ENABLED).",
  "fix_status": "fixed",
  "fix_baseline_reproduced": 1,
  "fix_patched_reproduced": 0,
  "fix_verdict": "Baseline kernel: write()/read() before enable -> Fatal trap 12 in targwrite+0x130 (fault va 0x40), guest dies. Patched kernel (fix.diff state checks): write returned -1 errno=6 (ENXIO), read returned errno=6, no panic, guest healthy. Bad behavior gone.",
  "fix_evidence": "run.patched.log; panic.txt (baseline).",
  "fix_kernel_uname": "DragonFly dfbsd 6.5-DEVELOPMENT #3: Sat Oct 3 18:32:37 UTC 2026 x86_64"
}