DF-3687 / verdict.json
{ "finding_id": "DF-3687", "status": "inconclusive", "reproduced": 0, "impact": "none", "confidence": "certain", "verdict": "Source-certain wild-write primitive gated behind root + non-default module config; runtime-inconclusive on this guest (no AMD GPU). amdgpu_set_pp_od_clk_voltage (amdgpu_pm.c:543-611) parses s <level> <clk> <mV> triples with kstrtol, so the level may be any signed long including negatives. smu7_odn_edit_dpm_tables guard input[i] >= podn_dpm_table_in_backend->num_of_pl (:4855) compares a 64-bit signed long against uint32_t num_of_pl -> the u32 converts to long -> SIGNED compare -> -1 passes. The value is then truncated into uint32_t input_level (:4859) and used as the array index at :4864-4868 into entries[8] of struct phm_odn_clock_levels (hardwaremanager.h:384-396): any u32 offset is selectable (e.g. -1 -> 0xFFFFFFFF -> +51,539,607,540 bytes) and the written values (clock/vddc/vddgfx) are range-checked but attacker-chosen within the golden OD ranges. Gating: root-only sysfs (0644) AND hwmgr->od_enabled, which requires the ppfeaturemask module param to set PP_OVERDRIVE_MASK (0x4000) - the default 0xfffd3fff clears that bit, so this is off by default. Same scoring philosophy as DF-1169 (root-only). Harness reproduces the C conversion semantics and the resulting byte offset on the guest toolchain.", "exploit_chain": "", "evidence": "run.log: bounds check ... (long -1 vs u32 8): PASSED (signed compare, negative passes), uint32_t input_level = 0xffffffff, write offset ... = 4294967295 * 12 = 51539607540 bytes past entries[0]; VERDICT.md; fix.diff (reject input[i] < 0)", "kernel_refs": [ "sys/dev/drm/amd/powerplay/hwmgr/smu7_hwmgr.c:4855", "sys/dev/drm/amd/powerplay/hwmgr/smu7_hwmgr.c:4859", "sys/dev/drm/amd/powerplay/hwmgr/smu7_hwmgr.c:4864", "sys/dev/drm/amd/powerplay/inc/hardwaremanager.h:384", "sys/dev/drm/amd/amdgpu/amdgpu_pm.c:585" ], "poc_changes": "No seed; wrote an arithmetic harness reproducing kstrtol(-1) -> signed compare -> u32 truncation -> byte offset, using the exact C semantics shared by userland and kernel.", "attempts": 3, "guest_uname": "DragonFly dfbsd 6.5-DEVELOPMENT #0: Thu Jul 2 06:02:54 UTC 2026 x86_64", "runtime_sec": 90, "guest_dirty": 0, "build_cmd": "cc -Wall -O0 -o t odn_negative_level.c (DragonFly 6.5 base cc, on guest)", "run_cmd": "cd /tmp/DF-3687 && ./t", "code_hash": "0f7d3b9948101b1c34072426626d329c26b617e81064e196eba6222ee18c495b", "notes": "Guest virtio-only (no AMD GPU: pciconf shows only QEMU 0x1237/0x1111; amdgpu.ko/drm.ko present in /boot/kernel but unloaded). Harness proves the primitive/arithmetic with verbatim kernel code shape and 1:1 struct layouts; the in-kernel trigger needs an SMU7 ASIC + crafted VBIOS / VFIO / root pp_table write. Compiled -O0: -O2 detects the index UB and misoptimizes the accounting.", "recommended_fix": "Reject negative levels: if (i + 3 > size || input[i] < 0 || input[i] >= num_of_pl) return -EINVAL; in smu7_odn_edit_dpm_table.", "fix_status": "not_testable", "fix_baseline_reproduced": 0, "fix_patched_reproduced": 0, "fix_verdict": "fix.diff authored against the read-only sys/ tree after source+harness verification; not built (no AMD hardware on guest).", "fix_evidence": "findings/poc/DF-3687/fix.diff" } |