DF-3853 / verdict.json
{ "finding_id": "DF-3853", "status": "inconclusive", "reproduced": 0, "impact": "none", "confidence": "certain", "verdict": "Source-certain divide-by-zero: radeon_combios_get_clock_info() loads spll->reference_freq = RBIOS16(pll_info+0x1a) with no validation (radeon_combios.c:758; p1pll:741 and mpll:773 equally unchecked - the only post-parse clamp, radeon_clocks.c:194-216, fixes reference_div only, never *_freq). calc_eng_mem_clock() then executes req_clock /= (2 * spll->reference_freq) (radeon_clocks.c:377) on every PM engine-clock change of pre-AVIVO asics (radeon_pm.c:224 -> radeon_legacy_set_engine_clock, radeon_asic.c:253+). A crafted COMBIOS with word 0 there makes this a 32-bit integer division by zero: #DE on x86 -> divide_error -> kernel panic. The harness copies the kernel statements verbatim and dies with SIGFPE (exit 136 = 128+8 on DragonFly; run.log: Floating point exception (core dumped)), the userspace image of the same fault. Kernel-side panic not observable: audit guest virtio-only, 0 radeon devices. On target hw this is a repeatable local DoS (boot/resume/PM-transition panic) under the same crafted-VBIOS precondition as DF-1250/1251/1252.", "exploit_chain": "crafted VBIOS (PLL table word +0x1a = 0, plus a powerplay table on a mobility board so >=2 power states exist) -> driver load parses clocks -> any PM clock transition (resume, profile/dynpm change, initial radeon_pm_compute_clocks) -> calc_eng_mem_clock divides by 2*0 -> divide_error trap in kernel context -> panic", "evidence": "run.log decisive lines: [combios] spll->reference_freq=0 ... then Floating point exception (core dumped), exit=136; build.log clean; VERDICT.md has the full path:line chain; fix_apply.log proves the two-file fix.diff applies to pristine /usr/src", "kernel_refs": [ "sys/dev/drm/radeon/radeon_combios.c:741", "sys/dev/drm/radeon/radeon_combios.c:758", "sys/dev/drm/radeon/radeon_combios.c:773", "sys/dev/drm/radeon/radeon_clocks.c:186-189", "sys/dev/drm/radeon/radeon_clocks.c:194-216", "sys/dev/drm/radeon/radeon_clocks.c:344-385", "sys/dev/drm/radeon/radeon_pm.c:224", "sys/dev/drm/radeon/radeon_asic.c:253" ], "poc_changes": "harness written from scratch (no seed); kernel arithmetic copied verbatim with path:line comments; only stub is RREG32_PLL returning a plausible nonzero so the single zero denominator is the BIOS-controlled reference_freq", "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": 20, "guest_dirty": 0, "build_cmd": "./build.sh (cc -O2 -Wall -o harness harness.c)", "run_cmd": "./run.sh", "code_hash": "6ddde06e7bb87fbc2cc2b04db76115a492139e3b464087d70872e825b9cfdafe", "notes": "Status inconclusive (not not_reproduced) because the kernel path cannot even be attempted on this guest: no radeon hardware. The SIGFPE harness output is the strongest possible demonstration without hardware - identical arithmetic, identical fault class. AVIVO-path divisions (radeon_compute_pll_avivo) are NOT reachable from this parser: avivo chips reject non-atom BIOSes (rv515.c et al.), which is why only the legacy calc_eng_mem_clock sink is cited.", "recommended_fix": "Sanitize zero reference frequencies to known-good defaults (2700) after the combios PLL parse, and guard !spll->reference_freq / !ref_div inside calc_eng_mem_clock() (fix.diff, two files)", "fix_status": "not_testable", "fix_baseline_reproduced": 0, "fix_patched_reproduced": 0, "fix_verdict": "fix.diff (radeon_combios.c + radeon_clocks.c defense-in-depth) applies cleanly to the guests pristine /usr/src (fix_apply.log, hunks at 784 and 356); runtime fix validation impossible on this guest (no hardware)", "fix_evidence": "fix.diff; fix_apply.log" } |