⬢ DragonFlyBSD Kernel Audit
DF-5285 / verdict.json
← back to finding ↓ download raw
{
 "finding_id": "DF-5285",
 "status": "reproduced",
 "reproduced": 1,
 "impact": "dos",
 "confidence": "certain",
 "verdict": "Kernel divide-by-zero panic (fatal trap 18, `divl` in sastrategy+0x279/+0x289) reproduced twice from a clean vm.sh reset and on the no-INVARIANTS test kernel: a malicious/quirky sequential-access device reports READ BLOCK LIMITS minimum=0 (or omits RBL, code path sets min_blk=0), the ordinary MTSETBSIZ ioctl for a non-power-of-2 size flips the driver into fixed mode with blk_mask=~0 while min_blk stays 0, and the very next read(2)/write(2) executes `b_bcount % min_blk` in sastrategy() scsi_sa.c:756 -> integer divide fault -> all CPUs stopped, system dead. Fix validated: with fix.diff (clamp min_blk>=1 in samount + guard the modulo) the same PoC completes the read normally with no panic.",
 "exploit_chain": "evil/compromised tape device (evil SIM KLD) -> READ BLOCK LIMITS {minimum=0} -> open(/dev/nsa0) mounts variable, min_blk=0 -> MTSETBSIZ 3 (non-pow2): FIXED + blk_mask=~0, min_blk untouched -> read(512) -> sastrategy: 512 % 0 -> fatal trap 18 -> kernel panic (local DoS; no memory-corruption primitive, division fault only)",
 "evidence": "panic.txt (Fatal trap 18 ... Stopped at sastrategy+0x289: divl %ecx,%eax, stock INVARIANTS kernel); panic.noinv.txt + run.noinv.log (same on no-INVARIANTS kernel, sastrategy+0x279); run.log (poc output); evilsa.c (READ BLOCK LIMITS minimum=0 choreography); run.patched.log (post-fix: read returns, no panic)",
 "kernel_refs": [
  "sys/bus/cam/scsi/scsi_sa.c:756",
  "sys/bus/cam/scsi/scsi_sa.c:2005",
  "sys/bus/cam/scsi/scsi_sa.c:2019",
  "sys/bus/cam/scsi/scsi_sa.c:1215"
 ],
 "poc_changes": "seed sketch replaced by evilsa KLD (fake T_SEQUENTIAL CAM SIM adapted from the DF-5271 evilcd rig) + a 30-line userland trigger (open, MTIOCTOP MTSETBSIZ 3, read). Mode-select policy accepts blocksize selects (density 0x7f) and rejects the 15 samount() density probes so the mount settles in variable mode with min_blk=0.",
 "attempts": 3,
 "guest_uname": "DragonFly dfbsd 6.5-DEVELOPMENT #0: Thu Jul 2 06:02:54 UTC 2026 / X86_64_GENERIC (baseline) and #0: Fri Oct 2 02:12:33 UTC 2026 X86_64_NOINV + same-source fix kernel",
 "runtime_sec": 1450,
 "guest_dirty": 1,
 "build_cmd": "cd /root/df5285 && cc -O -o poc_setblk poc_setblk.c (evilsa.ko per DF-5284 pack: touch opt_cam.h && make)",
 "run_cmd": "kldload /root/df5285/evilsa.ko; /root/df5285/poc_setblk /dev/nsa0",
 "code_hash": "poc_setblk.c: 6d39174cb1638d786eaba4a2c84b1145ae18a54164123fc1edb51ac87bbcbfb3",
 "notes": "Rig bug fixed during verification: an int aidx[4096] in the evilsa sysctl handler overflowed the kernel stack (double fault) - moved to .bss. Trigger requires the sa node to be openable (SYSCAP_RESTRICTEDROOT), so the local trigger is privileged/operator; the state that makes it fatal (min_blk==0) is fully device-controlled and explicitly expected by the driver (RBL failure path). DF-5286 (uninit rblim) shares the fix.diff M_ZERO hunk.",
 "recommended_fix": "Clamp softc->min_blk to >= 1 after READ BLOCK LIMITS parsing in samount() and guard the modulo in sastrategy() (see fix.diff).",
 "fix_status": "fixed",
 "fix_baseline_reproduced": 1,
 "fix_patched_reproduced": 0,
 "fix_verdict": "Rebuilt same-source X86_64_NOINV kernel with fix.diff (incremental nativekernel, log fix_build.log); exact same PoC re-run: MTSETBSIZ 3 accepted, read(512) returns normally, no trap, guest stays up (run.patched.log). Baseline on the identical unpatched kernel panicked.",
 "fix_evidence": "run.patched.log; fix_build.log; diff hunks at scsi_sa.c:752-756 (guard), :2021-2029 (clamp), :1961 (rblim M_ZERO), :2765 (ccomp M_ZERO)"
}