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

vid_mapping_table num_entries==0 -> entries[0xFFFFFFFF] wild read (~16 GiB) in kv_convert_vid2_to_vid7 / kv_convert_vid7_to_vid2

Summary

sumo_construct_vid_mapping_table can leave num_entries==0 (empty sAvail_SCLK or missing IntegratedSystemInfo); with vddc_dependency_on_sclk.count==0 (KB/ML boards) the else-branch evaluates entries[num_entries-1] with u32 num_entries: index 0xFFFFFFFF x 4 = +0x3FFFFFFFC (~16 GiB) past the kv_power_info heap object -> boot panic. VERIFIED: harness prints displacement 0x3fffffffc (16.00 GiB); verbatim expression faults SIGSEGV. amdgpu twin DF-3890.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-3956 Β· 11 files
FileTypeDescriptionSize
README.md β€” 2.3 KB ↓ raw
VERDICT.md β€” 3.2 KB ↓ raw
trigger_df3956.c β€” 5.8 KB view raw
build.sh β€” 92 B view raw
run.sh β€” 116 B view raw
build.log β€” 89 B view raw
run.log β€” 1.2 KB view raw
env.txt β€” 725 B view raw
fix.diff β€” 1.1 KB view raw
manifest.json β€” 1.8 KB view raw
verdict.json β€” 3.6 KB view raw

DF-3956 β€” radeon kv_dpm vid_mapping_table num_entries==0 β†’ entries[0xFFFFFFFF] wild read (~16 GiB)

File: sys/dev/drm/radeon/kv_dpm.c (pass 2, GLM 5.3) Severity: Low Β· CWE: CWE-191/CWE-125 (integer underflow β†’ OOB read) Confidence: certain (source) Β· Status: inconclusive on guest (no AMD GPU); arithmetic-simulation harness verified.

What

sumo_construct_vid_mapping_table() (sumo_dpm.c:1616-1645) ends with vid_mapping_table->num_entries = i; where i == 0 when no entry obtained a nonzero vid_7bit β€” i.e. the VBIOS IntegratedSystemInfo table's sAvail_SCLK[] list has all-zero ulSupportedSCLK values, or the IntegratedSystemInfo table is missing entirely, in which case kv_parse_sys_info_table() (kv_dpm.c:2495-2546) skips the whole body and still return 0 (success), leaving the kzalloc'd table all-zero.

Consumers in this file take the else-branch whenever vddc_dependency_on_sclk.count == 0 (Kabini/Mullins boards lacking the sclk dependency table):

kv_convert_vid2_to_vid7()  kv_dpm.c:562-566   /* loop 0 iterations */
    return vid_mapping_table->entries[vid_mapping_table->num_entries - 1].vid_7bit;
kv_convert_vid7_to_vid2()  kv_dpm.c:585-590   /* same expression */

num_entries is u32 (sumo_dpm.h:65), sizeof(entry) = 4 β†’ index 0xFFFFFFFF β†’ +0x3FFFFFFFC (~16 GiB) past the kv_power_info heap object β†’ kernel page fault β†’ panic.

Boot-time reachability: kv_dpm_enable β†’ kv_init_graphics_levels (:2344, else-branch) β†’ kv_set_vid (:2382β†’:618) / high-voltage check (:2378) β†’ kv_convert_2bit_index_to_voltage (:604) β†’ :566; also kv_parse_sys_info_table β†’ kv_construct_max_power_limits_table (:2543β†’:1973) and kv_get_high_voltage_limit (:2122).

Scope note

The usVoltageIndex OOB write inside sumo_construct_vid_mapping_table itself is DF-1437 (sumo_dpm.c, already filed) β€” not re-reported here. This finding is the kv_dpm.c consumer-side underflow. amdgpu twin: DF-3890 (Low).

Reproduce

cd findings/poc/DF-3956
./build.sh          # cc -O2 -Wall -o trigger_df3956 trigger_df3956.c
./run.sh

Expected (crash mode): entries[0xffffffff] -> +0x3fffffffc (16.00 GiB), child SIGSEGV sig=11, RESULT: WILD READ FAULTS AS PREDICTED.

Fix

Guard num_entries == 0 in both converters (fix.diff, in-file).

VERDICT.md
↓ download raw

DF-3956 VERDICT

Verdict: INCONCLUSIVE at kernel level (no AMD GPU) β€” source-certain u32 underflow wild read at +0x3FFFFFFFC (~16 GiB); the verbatim consumer expression faults in the userland simulation exactly as predicted.

Trace

  1. Producer can legitimately produce num_entries == 0. sumo_construct_vid_mapping_table (sumo_dpm.c:1616-1645): entries are only written for table[i].ulSupportedSCLK != 0; the compaction loop then breaks with i == 0 when entries[0].vid_7bit == 0 (empty table). Also, kv_parse_sys_info_table (kv_dpm.c:2495-2546) treats a missing IntegratedSystemInfo table as success (return 0 outside the atom_parse_data_header guard), leaving the whole kzalloc'd pi->sys_info.vid_mapping_table zeroed β€” num_entries == 0 without any crafted sAvail_SCLK at all.

  2. Consumer underflow (this file). kv_convert_vid2_to_vid7 (kv_dpm.c:548-568) and kv_convert_vid7_to_vid2 (:570-592) only touch vid_mapping_table when vddc_sclk_table->count == 0 (the else-branch) β€” true on KB/ML boards whose VBIOS lacks the sclk voltage-dependency table. With num_entries == 0 the match loop runs zero iterations and falls through to entries[num_entries - 1]: num_entries is u32 (sumo_dpm.h:64-67) β†’ 0xFFFFFFFF, entry size 4 β†’ displacement 0xFFFFFFFF Γ— 4 = 0x3FFFFFFFC β‰ˆ 16 GiB past the kv_power_info object.

  3. Boot-time call-in. kv_dpm_enable β†’ kv_init_graphics_levels else-branch (kv_dpm.c:2370-2386): kv_set_vid (:2382 β†’ :612-621 β†’ kv_convert_2bit_index_to_voltage :604 β†’ :566) and the high-voltage break check (:2378). Earlier still: kv_dpm_init β†’ kv_parse_sys_info_table β†’ kv_construct_max_power_limits_table (:2543 β†’ :1973) and kv_get_high_voltage_limit (:2122). All boot-time on the target APU with the crafted/empty VBIOS.

Harness

Replicates the producer's num_entries computation (0 on the all-zero sAvail_SCLK list), the consumer's verbatim entries[num_entries - 1].vid_7bit expression, and the struct layout (_Static_assert(entry==4)). Crash mode places the table against a guard page: child SIGSEGV sig=11; analysis prints entries[0xffffffff] -> +0x3fffffffc (16.00 GiB).

Why Low

Wild load (a 16-bit vid value) feeding voltage math; no write, no leak channel; trigger needs KV-family APU + VBIOS with both the sclk dependency table absent and the vid mapping empty/missing. Precedent: amdgpu twin DF-3890 (Low). (The sibling DF-1437 in sumo_dpm.c covers the OOB write inside the producer β€” different file, different primitive, already filed.)

Fix validation

fix.diff adds num_entries == 0 guards returning 0 in both converters (in-file fix; a producer-side clamp in sumo_dpm.c would also work but is that file's scope). Not built on the guest (no AMD GPU): fix_status: not_testable. Guards are trivially sufficient by inspection.

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 against the read-only sys/ tree; not built - no AMD hardware on the guest. Guards remove both sinks by construction.

findings/poc/DF-3956/fix.diff
↓ fix.diffper-fix-DF-3956

Confirmed kernel references

Detail

Exploit chain

KV/KB/ML APU with VBIOS lacking the sclk dependency table AND an empty/missing IntegratedSystemInfo vid mapping -> boot-time kv_init_graphics_levels -> kv_convert_vid2_to_vid7 -> wild read ~16 GiB out -> page fault -> panic (DoS). Load-only 16-bit value feeding voltage math; no write, no leak channel.

Evidence (decisive lines)

run.log: 'producer: sumo_construct_vid_mapping_table -> num_entries = 0', 'consumer: kv_convert_vid2_to_vid7 :566 -> entries[0xffffffff] -> +0x3fffffffc (16.00 GiB)', 'child: SIGNALLED sig=11', 'RESULT: WILD READ FAULTS AS PREDICTED'; VERDICT.md; fix.diff

PoC changes

No seed (pass-2 self-authored). Two fix cycles: missing ; and the analysis print initially used 64-bit unsigned math instead of the kernel's u32 index semantics (corrected to 0xffffffff*4 = 0x3fffffffc).

Verified recommended fix

num_entries==0 early-outs returning 0 in kv_convert_vid2_to_vid7 and kv_convert_vid7_to_vid2 (fix.diff); ideally also treat a missing IntegratedSystemInfo table as an error in kv_parse_sys_info_table.

Verdict

Source-certain u32-underflow wild read, amdgpu twin DF-3890 (Low). sumo_construct_vid_mapping_table (sumo_dpm.c:1616-1645, producer - its usVoltageIndex OOB write is already DF-1437, NOT re-reported) leaves vid_mapping_table.num_entries==0 when sAvail_SCLK has no nonzero ulSupportedSCLK, and kv_parse_sys_info_table (kv_dpm.c:2495-2546) also 'succeeds' with an all-zero table when IntegratedSystemInfo is missing entirely. With vddc_dependency_on_sclk.count==0 (KB/ML) the else-branch of kv_convert_vid2_to_vid7 (:566) / kv_convert_vid7_to_vid2 (:590) evaluates entries[num_entries - 1] with u32 num_entries (sumo_dpm.h:65): index 0xFFFFFFFF * sizeof(entry)=4 = +0x3FFFFFFFC (~16 GiB) past the kv_power_info heap object -> kernel page fault -> panic. Boot path: kv_dpm_enable -> kv_init_graphics_levels else-branch (:2382->kv_set_vid:618 / :2378) and kv_parse_sys_info_table -> kv_construct_max_power_limits_table (:2543->:1973). Harness: producer replay yields num_entries=0; verbatim consumer expression faults SIGSEGV against a guard page; displacement print 0x3fffffffc (16.00 GiB). Runtime-inconclusive: no AMD GPU on guest.