DF-4278 / verdict.json
{ "finding_id": "DF-4278", "status": "untested", "reproduced": 0, "impact": "none", "confidence": "likely", "verdict": "Certain code defect, hardware-gated runtime: r300_packet0_checks R300_ZB_ZPASS_ADDR case (r300.c:1073-1082) patches the occlusion-counter GPU address as ib[idx] = idx_value + reloc->gpu_offset without storing offset/robj in the track state and without any bo-size validation \u2014 unlike every sibling address register (COLOROFFSET/DEPTHOFFSET/AARESOLVE_OFFSET/TX_OFFSET), which are all later enforced against radeon_bo_size() in r100_cs_track_check (r100.c:2264/2283/2303). An unprivileged DRM user therefore selects an arbitrary u32 offset past a GTT BO base where the GPU SC unit increments a 4-byte counter per passing pixel \u2014 a repeatable GPU-side OOB write into neighboring GTT/VRAM allocations (other users BOs, the GTT-resident radeon IB pool, scanout). The QEMU audit guest has no ATI/radeon device (env.txt), so the trigger could not be executed: status untested, impact not demonstrated locally. The r100 twin (r100.c:1778) shares the gap.", "exploit_chain": "open /dev/dri/card0 -> DRM_IOCTL_RADEON_CS with IB [PACKET0(0x4f5c,0), 0xF0000000, NOP+reloc] -> checker accepts (no bound) -> CP programs ZB_ZPASS_ADDR = bo_gpu_offset + 0xF0000000 -> draw with occlusion counting enabled -> GPU increments 4 bytes at attacker-chosen GPU VA -> cross-BO corruption; theoretical ceiling: corrupt an IB in the GTT pool after validation => unvalidated GPU command stream.", "evidence": "VERDICT.md (sibling-case comparison table); zpass_oob.c (exact 4-dword CS recipe); env.txt (no 0x1002 device on guest); fix.diff (validated-bound check mirroring sibling cases).", "kernel_refs": [ "sys/dev/drm/radeon/r300.c:1073-1082", "sys/dev/drm/radeon/r100.c:2264", "sys/dev/drm/radeon/r100.c:2283", "sys/dev/drm/radeon/r100.c:2303", "sys/dev/drm/radeon/r100.c:1375" ], "poc_changes": "no seed present; authored from scratch as a pure-ioctl trigger (no libdrm dependency)", "attempts": 0, "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": 0, "guest_dirty": 0, "fix_status": "not_testable", "fix_baseline_reproduced": 0, "fix_patched_reproduced": 0, "fix_verdict": "fix.diff adds the missing idx_value+8 <= radeon_bo_size(reloc->robj) check; cannot be kernel-built and exercised on the audit guest because the radeon device (and thus the CS path) does not exist there \u2014 hardware-gated validation", "fix_evidence": "findings/poc/DF-4278/fix.diff (sha256 19516d00787c2a2eaafe1d8d902ce382f694fa6e99461cac68d1036ae63d9f67)", "build_cmd": "cc -O2 -o zpass_oob zpass_oob.c", "run_cmd": "./run.sh /dev/dri/card0", "code_hash": "a7b0dc039dea1e050766711237d67094f93a7489c6ce19c679d782dfe109a321", "notes": "Hardware-gated (r300..rv570 asics; guest has only QEMU virtual VGA). Same gap exists at r100.c:1778 (RADEON_RB3D_ZPASS_ADDR) - filed for r300.c which is this batchs audited file. Status untested per orchestrator status set; hardware absence documented in env.txt.", "recommended_fix": "Validate the ZB_ZPASS_ADDR immediate against the relocation BO size before patching (idx_value + 8 <= radeon_bo_size(reloc->robj)) as in fix.diff." } |