DF-4492 / verdict.json
{ "finding_id": "DF-4492", "status": "reproduced", "reproduced": 1, "impact": "leak", "confidence": "certain", "verdict": "Reproduced at logic level with the verbatim replica (harness modes 4492/4492g): rs780_parse_power_table walks the VBIOS PowerPlayInfo using only attacker-supplied usStateArrayOffset+i*ucStateEntrySize (:812-816), ucNonClockStateIndex*ucNonClockSize (:817-821) and ucClockStateIndices[0]*ucClockInfoSize (:822-827) with no bounds checks anywhere (atom_parse_data_header does none); nonClockInfo[250] with a crafted u16 array offset lands 16 bytes past the 16 KB BIOS replica into the canary redzone and its poison is ingested verbatim into rps->class/caps/vclk (0xa5a5/0xa5a5a5a5) which print to console/debugfs via rs780_dpm_print_power_state (:944-948); the far variant (clockInfoIndex 66 x ucClockInfoSize 255) SIGSEGVs exactly in a guard page 638 bytes past the image (kernel: page-fault panic). Max reach ~65 KB past the kmallocd BIOS image per index walk, ~130 KB on the state walk. RS780 twin of DF-4190 (sumo) / DF-4146 (trinity). Kernel-level repro hardware-gated (no RS780 IGP in the QEMU guest). Fix proven: harness_fixed rejects the crafted indices; fix.diff builds radeon.ko under -Werror (MAKE_RC=0).", "exploit_chain": "crafted VBIOS PowerPlayInfo (flashed ROM / replaced card / passed-through GPU) -> OOB read past BIOS allocation -> adjacent kernel-heap bytes ingested into rps->class/caps/vclk/sclk -> printed via rs780_dpm_print_power_state to console/debugfs (info leak); far indices -> kernel page fault (DoS); leaked BOOT-bit in class additionally steers boot_ps selection", "evidence": "run.log ===== mode 4492 =====: three CANARY heap-OOB reports + rps[0].class = 0xa5a5 (== canary poison: OOB READ CONFIRMED), exit=98; ===== mode 4492g =====: SIGNAL 11 at address 0x8004c4280 inside the guard page, exit=99; fixed sections print DRM_ERROR: ... walks past the table, exit=0; radeon_module_build.log MAKE_RC=0 under -Werror", "kernel_refs": [ "sys/dev/drm/radeon/rs780_dpm.c:812", "sys/dev/drm/radeon/rs780_dpm.c:817", "sys/dev/drm/radeon/rs780_dpm.c:822", "sys/dev/drm/radeon/rs780_dpm.c:826", "sys/dev/drm/radeon/rs780_dpm.c:944", "sys/dev/drm/radeon/atom.c:1366", "sys/dev/drm/radeon/radeon_bios.c:98" ], "poc_changes": "wrote harness from scratch (no seed): crafted bios image + verbatim parse replica; -fno-delete-null-pointer-checks used so NULL/wild derefs trap like the kernel instead of being optimized away", "attempts": 2, "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": 260, "guest_dirty": 0, "build_cmd": "./build.sh (on audit guest, cc 8.3, -fno-delete-null-pointer-checks)", "run_cmd": "./run.sh (modes 4492 4492g; full matrix in run.log)", "code_hash": "3b7698d1a8d20944dd3c2ea4c0010146536ed001ff5cf1034c4c4ac650591741", "notes": "known finding DF-1650 (vrefresh div0) not re-tested (pass-1, already verified). Family-consistent bucket: kernleak. The poisoned class bit0 also demonstrates OOB influence on boot_ps selection. Impact leak per family precedent (DF-4190/DF-4146); crash variant demonstrated deterministically in mode 4492g.", "recommended_fix": "request the table size from atom_parse_data_header and bounds-check every pplib walk (state array extent, nonClockInfoIndex*ucNonClockSize+entry, clockInfoIndex*ucClockInfoSize+entry) with consistent cleanup, as in fix.diff", "fix_status": "fixed", "fix_baseline_reproduced": 1, "fix_patched_reproduced": 0, "fix_verdict": "harness_fixed 4492/4492g reject the crafted indices (DRM_ERROR, -EINVAL, exit 0); combined fix builds radeon.ko under -Werror (MAKE_RC=0, radeon_module_build.log)", "fix_evidence": "run.log fixed sections DRM_ERROR: nonClockInfoIndex 250 walks past the table / clockInfoIndex 66 walks past the table, exit=0; radeon_fix_apply.log hunks 1-7; radeon_module_build.log MAKE_RC=0" } |