DF-3954 / verdict.json
{ "finding_id": "DF-3954", "status": "inconclusive", "reproduced": 0, "impact": "none", "confidence": "certain", "verdict": "Source-certain u32-index underflow wild read (amdgpu twin DF-3888; amdgpus had an info-ioctl caller, radeons does not - trigger is boot/mode-set with crafted VBIOS). kv_parse_power_table (kv_dpm.c:2681-2694) leaves ps->num_levels==0 for a state with ucNumDPMLevels==0 or all clockInfoIndex >= ucNumEntries (continue); struct kv_ps (kv_dpm.h:79-87) has u32 num_levels and levels[] as FIRST member, so levels[num_levels - 1] = levels[0xFFFFFFFF] = object + 0xFFFFFFFF*12 = +0xBFFFFFFF4 (~48 GiB). Sinks: kv_set_valid_clock_range :1721/:1745-1747 (from kv_dpm_set_power_state :1866/:1895 once pick_power_state - which never checks num_levels - selects the state) and kv_dpm_get_sclk :2886 (from dce8_bandwidth_update cik.c:9287/9327). Harness executes the verbatim expression against a guard-page object: SIGSEGV sig=11, displacement 0xbfffffff4 printed. Runtime-inconclusive: no AMD GPU on guest.", "exploit_chain": "crafted-VBIOS state with zero usable clock entries -> picked by class match -> kv_set_valid_clock_range / kv_dpm_get_sclk -> wild read ~48 GiB past kv_ps heap object -> kernel page fault -> panic (DoS). Load-only primitive; value feeds clock comparisons, no leak channel, no write.", "evidence": "run.log: num_levels(u32) = 0 => index = 0xffffffff => displacement = 0xbfffffff4 (48.00 GiB), child: SIGNALLED sig=11 -> predicted wild read at +0xbfffffff4 confirmed faulting, RESULT: WILD READ FAULTS AS PREDICTED; VERDICT.md full trace; fix.diff", "kernel_refs": [ "sys/dev/drm/radeon/kv_dpm.c:1721", "sys/dev/drm/radeon/kv_dpm.c:1745", "sys/dev/drm/radeon/kv_dpm.c:2886", "sys/dev/drm/radeon/kv_dpm.c:2681", "sys/dev/drm/radeon/kv_dpm.h:82", "sys/dev/drm/radeon/cik.c:9287" ], "poc_changes": "No seed (pass-2 self-authored). One fix cycle: first analysis print used 64-bit unsigned math (0xff..f4) instead of the kernels u32 index math; corrected to (size_t)(u32)0-1 * 12 = 0xbfffffff4.", "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": 120, "guest_dirty": 0, "build_cmd": "cd /tmp/df395x && cc -O2 -Wall -o trigger_df3954 trigger_df3954.c", "run_cmd": "cd /tmp/df395x && ./trigger_df3954 && ./trigger_df3954 crash", "code_hash": "3b85f3913bc67bea76b3bbf82e8009f8591bc3c93c7dfa76a8e65196cfac689e", "notes": "Distinct from pass-1 DF-1305 (graphics_level writes), DF-1306 (nonClockInfoIndex), DF-1307 (vce clk_idx): different index, different sinks. Severity aligned with DF-1306/1307 (Medium, VBIOS-gated OOB read).", "recommended_fix": "Skip zero-clock-entry states in kv_parse_power_table and add num_levels==0 early-outs in kv_set_valid_clock_range and kv_dpm_get_sclk (fix.diff).", "fix_status": "not_testable", "fix_baseline_reproduced": 0, "fix_patched_reproduced": 0, "fix_verdict": "fix.diff authored against the read-only sys/ tree; not built - no AMD hardware on the guest. Guards eliminate both sinks by construction.", "fix_evidence": "findings/poc/DF-3954/fix.diff" } |