β¬’ DragonFlyBSD Kernel Audit
← triage Β· dashboard
DF-3743

Spread-spectrum rate parses to zero (raw 0, v2/v3 /=100 truncation, or ppll never assigns rate) and reaches DPM SS divisions (#DE panic)

Summary

Parse side of DF-3621/3647 (si/ci sinks): radeon_atombios_get_asic_ss_info returns success with ss->rate==0 via v1 raw store, v2/v3 usSpreadRateIn10Hz<100 truncating under 'ss->rate /= 100', and radeon_atombios_get_ppll_ss_info never assigning rate at all (memset-zero remains). Sinks: si_dpm.c:4833 / ci_dpm.c:3229 divide by (reference_divider * ss.rate). HARNESS: v3 parse of rate=50 -> 0 after /=100 -> verbatim sink division -> SIGFPE on the guest. Crafted SS table -> DPM enable programs SS -> divide-by-zero panic. Fix: treat rate==0 entries as invalid in all three asic_ss paths.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-3743 Β· 13 files
FileTypeDescriptionSize
README.md β€” 1.9 KB ↓ raw
VERDICT.md β€” 2.5 KB ↓ raw
build.log β€” 744 B view raw
build.sh β€” 65 B view raw
env.txt β€” 375 B view raw
harness_ssrate.c β€” 2.9 KB view raw
run.log β€” 206 B view raw
run.sh β€” 108 B view raw
README.md β€” 1.9 KB ↓ raw
VERDICT.md β€” 2.5 KB ↓ raw
manifest.json β€” 999 B view raw
verdict.json β€” 3.0 KB view raw
fix.diff β€” 931 B view raw

DF-3743 β€” Spread-spectrum rate parsed to zero (raw 0, /=100 truncation, or never assigned) reaches DPM SS divisions (#DE panic)

Severity: Medium Β· CWE: CWE-369 Divide By Zero Β· File: sys/dev/drm/radeon/radeon_atombios.c:1546, 1564-1569, 1586-1594, 1390-1413

What this is

Parse-side root of the SS-rate divide-by-zero family (sink side already filed as DF-3621 [si] / DF-3647 [ci]). radeon_atombios_get_asic_ss_info() returns success with ss->rate==0 via three distinct paths: v1 stores usSpreadRateInKhz verbatim (:1546); v2/v3 store usSpreadRateIn10Hz then integer-divide by 100 for ENGINE/MEMORY SS (:1569, :1594) so any value <100 truncates to 0. radeon_atombios_get_ppll_ss_info() never assigns rate at all (memset at :1390 remains) yet returns true (:1400-1413). Sinks divide by ss.rate: si_dpm.c:4833 and ci_dpm.c:3229 (clk_s = reference_clock * 5 / (reference_divider * ss.rate)). Harness on guest: v3 parse of usSpreadRateIn10Hz=50 -> rate=0 -> verbatim sink expression -> SIGFPE (exit 42). Kernel path unreachable on this guest.

Reproduce

./build.sh    # cc -O1 -g -Wall -o <bin> harness_ssrate.c   (DragonFly guest, cc 8.3)
./run.sh      # expected: ss.rate=0 after parse; sink division SIGFPE at stage 1, exit_code=42

The harness replicates the kernel parse arithmetic VERBATIM (cited path:line) against a synthetic crafted-VBIOS buffer with canary-guarded destinations.

Guest / environment

Guest has NO AMD/radeon GPU (virtio-only); /boot/kernel/radeon.ko exists (code shipped in the default install) but cannot attach, so the kernel code path is unreachable at runtime on this guest. Evidence is source-level certainty (path:line traced) plus a verbatim-arithmetic userland harness compiled and executed on the guest (build.log/run.log). See env.txt (uname, cc, kldstat, /boot/kernel/radeon.ko presence).

Fix

treat rate==0 entries as invalid (return false / skip) β€” see fix.diff (authored after verification; never applied to sys/).

DF-3743 β€” Spread-spectrum rate parsed to zero (raw 0, /=100 truncation, or never assigned) reaches DPM SS divisions (#DE panic)

Severity: Medium Β· CWE: CWE-369 Divide By Zero Β· File: sys/dev/drm/radeon/radeon_atombios.c:1546, 1564-1569, 1586-1594, 1390-1413

What this is

Parse-side root of the SS-rate divide-by-zero family (sink side already filed as DF-3621 [si] / DF-3647 [ci]). radeon_atombios_get_asic_ss_info() returns success with ss->rate==0 via three distinct paths: v1 stores usSpreadRateInKhz verbatim (:1546); v2/v3 store usSpreadRateIn10Hz then integer-divide by 100 for ENGINE/MEMORY SS (:1569, :1594) so any value <100 truncates to 0. radeon_atombios_get_ppll_ss_info() never assigns rate at all (memset at :1390 remains) yet returns true (:1400-1413). Sinks divide by ss.rate: si_dpm.c:4833 and ci_dpm.c:3229 (clk_s = reference_clock * 5 / (reference_divider * ss.rate)). Harness on guest: v3 parse of usSpreadRateIn10Hz=50 -> rate=0 -> verbatim sink expression -> SIGFPE (exit 42). Kernel path unreachable on this guest.

Reproduce

./build.sh    # cc -O1 -g -Wall -o <bin> harness_ssrate.c   (DragonFly guest, cc 8.3)
./run.sh      # expected: ss.rate=0 after parse; sink division SIGFPE at stage 1, exit_code=42

The harness replicates the kernel parse arithmetic VERBATIM (cited path:line) against a synthetic crafted-VBIOS buffer with canary-guarded destinations.

Guest / environment

Guest has NO AMD/radeon GPU (virtio-only); /boot/kernel/radeon.ko exists (code shipped in the default install) but cannot attach, so the kernel code path is unreachable at runtime on this guest. Evidence is source-level certainty (path:line traced) plus a verbatim-arithmetic userland harness compiled and executed on the guest (build.log/run.log). See env.txt (uname, cc, kldstat, /boot/kernel/radeon.ko presence).

Fix

treat rate==0 entries as invalid (return false / skip) β€” see fix.diff (authored after verification; never applied to sys/).

VERDICT.md
↓ download raw

VERDICT β€” DF-3743

Status: inconclusive (source-certain; harness-reproduced arithmetic; kernel path unreachable on this guest) reproduced: 0 (in-kernel) β€” harness demonstration: YES Impact on real hardware: Medium β€” CWE-369 Divide By Zero

Finding

Parse-side root of the SS-rate divide-by-zero family (sink side already filed as DF-3621 [si] / DF-3647 [ci]). radeon_atombios_get_asic_ss_info() returns success with ss->rate==0 via three distinct paths: v1 stores usSpreadRateInKhz verbatim (:1546); v2/v3 store usSpreadRateIn10Hz then integer-divide by 100 for ENGINE/MEMORY SS (:1569, :1594) so any value <100 truncates to 0. radeon_atombios_get_ppll_ss_info() never assigns rate at all (memset at :1390 remains) yet returns true (:1400-1413). Sinks divide by ss.rate: si_dpm.c:4833 and ci_dpm.c:3229 (clk_s = reference_clock * 5 / (reference_divider * ss.rate)). Harness on guest: v3 parse of usSpreadRateIn10Hz=50 -> rate=0 -> verbatim sink expression -> SIGFPE (exit 42). Kernel path unreachable on this guest.

Why not reproduced in-kernel

The QEMU guest is virtio-only (no AMD GPU): pciconf -l shows no 1002 device; kldstat shows radeon not loaded. /boot/kernel/radeon.ko exists (the vulnerable code ships in the default install) but cannot attach, so radeon_atombios.c parse paths never execute here. All conclusions are source-level (path:line above) plus the on-guest harness (harness_ssrate.c).

Harness result

Command: ./run.sh (after ./build.sh) Expected/observed: ss.rate=0 after parse; sink division SIGFPE at stage 1, exit_code=42 Full logs: build.log, run.log.

Impact / exploit chain

crafted ASIC_InternalSS_Info (v2/v3 rate<100, or v1 rate=0) or PPLL_SS_Info table -> parse returns true with rate=0 -> DPM enable programs SS -> divide-by-zero -> #DE kernel panic

Fix

treat rate==0 entries as invalid (return false / skip) β€” fix.diff.

Honest notes

  • DF-3743 does NOT re-report pass-1 findings DF-1198/1199/1200 (power-table state_index mismatch, asic_ss_info underflow, power-table indices) β€” different functions/tables/fields.
  • fix validation not possible on this guest (no hardware); fix.diff is source-authored only.

Fix status (batch validation)

Applied with the 36 sibling fix.diffs of this batch in findings/poc/_batch41/all_fixes.patch; single in-guest make -j6 nativekernel KERNCONF=X86_64_GENERIC completed RC=0 with zero errors under -Werror (full log: findings/poc/_batch41/fix_build8.log). Behavior A/B intentionally skipped for this Info-tier item.

VERDICT.md
↓ download raw

VERDICT β€” DF-3743

Status: inconclusive (source-certain; harness-reproduced arithmetic; kernel path unreachable on this guest) reproduced: 0 (in-kernel) β€” harness demonstration: YES Impact on real hardware: Medium β€” CWE-369 Divide By Zero

Finding

Parse-side root of the SS-rate divide-by-zero family (sink side already filed as DF-3621 [si] / DF-3647 [ci]). radeon_atombios_get_asic_ss_info() returns success with ss->rate==0 via three distinct paths: v1 stores usSpreadRateInKhz verbatim (:1546); v2/v3 store usSpreadRateIn10Hz then integer-divide by 100 for ENGINE/MEMORY SS (:1569, :1594) so any value <100 truncates to 0. radeon_atombios_get_ppll_ss_info() never assigns rate at all (memset at :1390 remains) yet returns true (:1400-1413). Sinks divide by ss.rate: si_dpm.c:4833 and ci_dpm.c:3229 (clk_s = reference_clock * 5 / (reference_divider * ss.rate)). Harness on guest: v3 parse of usSpreadRateIn10Hz=50 -> rate=0 -> verbatim sink expression -> SIGFPE (exit 42). Kernel path unreachable on this guest.

Why not reproduced in-kernel

The QEMU guest is virtio-only (no AMD GPU): pciconf -l shows no 1002 device; kldstat shows radeon not loaded. /boot/kernel/radeon.ko exists (the vulnerable code ships in the default install) but cannot attach, so radeon_atombios.c parse paths never execute here. All conclusions are source-level (path:line above) plus the on-guest harness (harness_ssrate.c).

Harness result

Command: ./run.sh (after ./build.sh) Expected/observed: ss.rate=0 after parse; sink division SIGFPE at stage 1, exit_code=42 Full logs: build.log, run.log.

Impact / exploit chain

crafted ASIC_InternalSS_Info (v2/v3 rate<100, or v1 rate=0) or PPLL_SS_Info table -> parse returns true with rate=0 -> DPM enable programs SS -> divide-by-zero -> #DE kernel panic

Fix

treat rate==0 entries as invalid (return false / skip) β€” fix.diff.

Honest notes

  • DF-3743 does NOT re-report pass-1 findings DF-1198/1199/1200 (power-table state_index mismatch, asic_ss_info underflow, power-table indices) β€” different functions/tables/fields.
  • fix validation not possible on this guest (no hardware); fix.diff is source-authored only.

Fix status (batch validation)

Applied with the 36 sibling fix.diffs of this batch in findings/poc/_batch41/all_fixes.patch; single in-guest make -j6 nativekernel KERNCONF=X86_64_GENERIC completed RC=0 with zero errors under -Werror (full log: findings/poc/_batch41/fix_build8.log). Behavior A/B intentionally skipped for this Info-tier item.

Fix verification

not_testable
baseline no→ patch + rebuild →patched clean

fix.diff authored after source-level verification; cannot be validated on this guest (no AMD GPU; radeon.ko cannot attach). Compiling the module or booting a patched kernel would not exercise the path without hardware.

fix.diff (unified, against read-only sys/ tree; never applied)
↓ fix.diffper-fix-DF-3743

Confirmed kernel references

Detail

Exploit chain

crafted ASIC_InternalSS_Info (v2/v3 rate<100, or v1 rate=0) or PPLL_SS_Info table -> parse returns true with rate=0 -> DPM enable programs SS -> divide-by-zero -> #DE kernel panic

Evidence (decisive lines)

harness_ssrate.c + build.log + run.log; VERDICT.md; kernel refs sys/dev/drm/radeon/radeon_atombios.c:1540-1552

PoC changes

harness written from scratch (no seed PoC): verbatim kernel arithmetic replica with canary-guarded destination model, built and executed on the DragonFly guest (cc 8.3); fixed nested-comment, stddef/stdint includes and volatile divisors during bring-up

Verified recommended fix

treat rate==0 entries as invalid (return false / skip)

Verdict

Parse-side root of the SS-rate divide-by-zero family (sink side already filed as DF-3621 [si] / DF-3647 [ci]). radeon_atombios_get_asic_ss_info() returns success with ss->rate==0 via three distinct paths: v1 stores usSpreadRateInKhz verbatim (:1546); v2/v3 store usSpreadRateIn10Hz then integer-divide by 100 for ENGINE/MEMORY SS (:1569, :1594) so any value <100 truncates to 0. radeon_atombios_get_ppll_ss_info() never assigns rate at all (memset at :1390 remains) yet returns true (:1400-1413). Sinks divide by ss.rate: si_dpm.c:4833 and ci_dpm.c:3229 (clk_s = reference_clock * 5 / (reference_divider * ss.rate)). Harness on guest: v3 parse of usSpreadRateIn10Hz=50 -> rate=0 -> verbatim sink expression -> SIGFPE (exit 42). Kernel path unreachable on this guest.