⬢ DragonFlyBSD Kernel Audit
DF-3824 / verdict.json
← back to finding ↓ download raw
{
  "finding_id": "DF-3824",
  "status": "inconclusive",
  "reproduced": 0,
  "impact": "none",
  "confidence": "certain",
  "verdict": "ASR_init_message()s SGL loop is bounded by compile-time SG_SIZE=58 (asr.c:1812) which fills bytes [48,512) of asr_action()s 512-byte stack buffer exactly; the mandatory sense element written unconditionally after the loop (asr.c:1844-1845) then lands at bytes [512,520) - an 8-byte kernel stack OOB write (flags dword + low-32-bit physical address) whenever a single XPT_SCSI_IO spans >=58 physically-discontiguous runs (~>=232KiB). Normal disk I/O is capped by MAXPHYS=128KiB (~33 runs) and cannot trigger it; CAM pass-through (root-only /dev/passN) with a large scattered buffer can. The adapter-derived ha_SgSize (asr.c:2459-2465) is computed and never used, so the posted SGL also ignores the adapters inbound frame size. Arithmetic verified on the guest by compiling and running sg_layout_proof.c (struct replicas; output: sense element at [512,520), overflow 8 bytes). The kernel write itself is unexercisable: guest has no asr HBA (no /dev/asr0, zero vendor-0x1044 PCI devices) so asr_action never runs.",
  "exploit_chain": "root on host with asr card: camcontrol pass-through with dxfer_len >= ~256KiB over fragmented buffer -> 58+ physical runs -> sense SGL element overwrites 8 bytes past struct Message on asr_actions stack (adjacent locals/saved state, compiler-dependent) -> corruption/panic; exploitability beyond DoS depends on stack layout.",
  "evidence": "run.log (sg_layout_proof output on guest: offsets 48/8/512, sense at [512,520)); build.log; VERDICT.md (full derivation); fix.diff (reserve one SGL slot for the sense element)",
  "kernel_refs": [
    "sys/dev/raid/asr/asr.c:1812",
    "sys/dev/raid/asr/asr.c:1844",
    "sys/dev/raid/asr/asr.c:2680",
    "sys/dev/raid/asr/asr.c:2459",
    "sys/dev/raid/asr/asr.c:258",
    "sys/cpu/x86_64/include/param.h:122"
  ],
  "poc_changes": "Layout prover written fresh from the i2omsg.h/i2odpt.h struct definitions; no seed PoC existed.",
  "attempts": 2,
  "guest_uname": "DragonFly dfbsd 6.5-DEVELOPMENT #0: Thu Jul  2 06:02:54 UTC 2026 X86_64_GENERIC x86_64",
  "runtime_sec": 60,
  "guest_dirty": 0,
  "build_cmd": "cc -O2 -Wall -o sg_layout_proof sg_layout_proof.c",
  "run_cmd": "./sg_layout_proof",
  "code_hash": "33e62c9581bad0a0b10766bf58ad37fb36437aa3b8842318eb0e7d1fdda48bc9",
  "notes": "ccb scatter/gather hunt item (c). Severity Low: needs root + rare hardware; the OOB itself is certain. ha_SgSize dead-store confirms the bound was meant to be dynamic.",
  "recommended_fix": "Bound the SGL loop by SG_SIZE-1 (reserve the last slot for the sense element) and honor sc->ha_SgSize (asr.c:1812).",
  "fix_status": "not_testable",
  "fix_baseline_reproduced": 0,
  "fix_patched_reproduced": 0,
  "fix_verdict": "Baseline overflow cannot be triggered without an asr controller; the layout proof validates the geometry only. fix.diff reserves the sense slot so the maximum write is [48,512) in-bounds.",
  "fix_evidence": "fix.diff"
}