⬢ DragonFlyBSD Kernel Audit
DF-5148 / verdict.json
← back to finding ↓ download raw
{
  "finding_id": "DF-5148",
  "status": "untested",
  "reproduced": false,
  "impact": "none",
  "confidence": "certain",
  "verdict": "Real, certain-from-code-shape off-by-one in the AUX completion poll of radeon_dp_aux_transfer_native(): the do-while at radeon_dp_auxch.c:152-158 executes its body with retry_count==0..1000 (1001 executions), so a hardware AUX_SW_DONE observed during the 1001st poll breaks the loop with retry_count==1000 and the counter-keyed gate at :160 then fails a COMPLETED transfer with -EIO (auxch hw never signalled completion). The control-flow arithmetic was executed and proved on the audit guest with loop_offbyone.c (run.log: shipped gate -5/EIO vs fixed gate 0 for DONE-at-rc=1000; identical classification for all other stimuli). On-hardware verification is impossible in the audit guest: no AMD/ATI PCI device exists there (env.txt: pciconf shows QEMU emulated VGA only), so the radeon driver cannot attach and the MMIO poll cannot run; per contract Info-class findings skip QEMU Phase V - hence status untested, not a refutation. No memory-safety impact: the misclassified path takes the normal goto done cleanup; callers (drm_dp_aux core) retry aux transactions, so the effect is a rare transient DP aux failure. Related known pass-1 findings DF-2146/DF-2147 cover the reply-count OOB and the aux_offset index and are not part of this finding.",
  "exploit_chain": "",
  "evidence": "run.log lines 3-6: DONE on 1001st poll (rc=1000) <-- last body -5 0 0 BUG: completed xfer misreported as -EIO and RESULT: shipped loop misclassifies a DONE-on-last-poll transfer as -EIO (radeon_dp_auxch.c:160); VERDICT.md traces the loop semantics; env.txt proves guest lacks radeon HW (no AMD/ATI PCI device)",
  "kernel_refs": [
    "sys/dev/drm/radeon/radeon_dp_auxch.c:66",
    "sys/dev/drm/radeon/radeon_dp_auxch.c:152",
    "sys/dev/drm/radeon/radeon_dp_auxch.c:158",
    "sys/dev/drm/radeon/radeon_dp_auxch.c:160",
    "sys/dev/drm/radeon/radeon_dp_auxch.c:194",
    "sys/dev/drm/include/linux/delay.h:55"
  ],
  "poc_changes": "Harness authored fresh (no seed existed for this finding); no guest kernel changes; userspace-only compile on guest cc 8.3",
  "attempts": 1,
  "guest_uname": "DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 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": 12,
  "guest_dirty": false,
  "build_cmd": "cc -O2 -Wall -o loop_offbyone loop_offbyone.c",
  "run_cmd": "./loop_offbyone",
  "code_hash": "52e7ae6386cfa387f7a3403783d3efbbd74027545308fa6978ebc0a6e179633e",
  "notes": "Info-class correctness bug; Phase V (QEMU) verification skipped per contract - guest has no radeon GPU so the loop cannot execute on HW; the arithmetic proof harness WAS executed on the guest. Aggravation noted: usleep_range(100,200) maps to DELAY(100) (delay.h:55), a ~100us busy-wait per iteration held under chan->mutex (:96), ~100ms worst case per failed transaction vs upstream Linux udelay(1) ~1ms - bounded, latency-only. Error-path goto done skips the second DONE_ACK at :194; stale DONE is re-acked at :145 of the next call before GO, so cosmetic. Known pair DF-2146 (reply byte count, :177-191) and DF-2147 (aux_offset[instance], :44-63) NOT re-reported.",
  "recommended_fix": "Gate the timeout on the observed status word, not the iteration counter: replace if (retry_count >= 1000) with if (!(tmp & AUX_SW_DONE)) (see fix.diff, git-apply --check verified against pristine sys/)",
  "fix_status": "not_testable",
  "fix_baseline_reproduced": false,
  "fix_patched_reproduced": false,
  "fix_verdict": "fix.diff not boot-tested: validating it requires radeon DisplayPort hardware timing a completion into the final poll iteration, which the audit guest cannot provide (no AMD/ATI PCI device). The harness proves the status-keyed gate classifies every stimulus correctly (fixed column of run.log), including the case the shipped gate gets wrong; the diff is a one-line, behavior-preserving-for-all-other-paths change, git-apply --check verified against the pristine sys/ tree.",
  "fix_evidence": "run.log fixed gate column: 0/0/0/0/-5 vs shipped 0/0/0/-5/-5; fix.diff hunk @@ -157,7 +157,7 @@ replacing the counter test with !(tmp & AUX_SW_DONE)"
}