get_clock_voltage_limit reads entries[0] without numEntries check; off-by-one in get_state_entry_v2
- File:
sys/dev/drm/amd/powerplay/hwmgr/processpptables.c - Lines: 428β440 (entries[0]), 784 (off-by-one)
- Severity: Low
- CVSS:
CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:L/I:N/A:H - CWE: CWE-193 Off-by-One Error
- Confidence: likely
Summary
Two small but real defects in array-walk preconditions.
-
get_clock_voltage_limitunconditionally indexestable->entries[0]without verifying thattable->ucNumEntries >= 1; a VBIOS limit table withnumEntries=0reads one record past the table header. -
get_state_entry_v2usesentry_index <= ucNumEntries(processpptables.c:784), allowing the caller's permissiveentry_index > ucNumEntriescheck (processpptables.c:913) to passentry_index == ucNumEntries, which walks one state past the last and returns a pointer that the caller then dereferences.
Root cause
-
get_clock_voltage_limit,processpptables.c:428-440:limits->sclk = ... le16_to_cpu(table->entries[0].usSclkLow);etc. βentries[0]is taken with notable->ucNumEntries >= 1precondition. The function is reached frominit_clock_voltage_dependencyatprocesspptables.c:1328-1334only whenusMaxClockVoltageOnDCOffset != 0, so a VBIOS that points that offset at a 0-entry limit table triggers the OOB read. -
get_state_entry_v2,processpptables.c:784: the test should be<, not<=. Combined with the caller's permissive test atprocesspptables.c:913(entry_index > ucNumEntries), anentry_indexequal toucNumEntriescauses the for-loop atprocesspptables.c:785-788to advanceucNumEntriestimes β leavingpstatepointing past the final state β and the caller dereferences it atprocesspptables.c:916, 923-935.
The normal caller loop (i = 0..num_entries-1) does not hit this, so the bug
is latent unless a future caller relies on the documented entry-count contract.
Threat
Local, same VBIOS-controlled precondition.
Path (1) is directly reachable from a crafted VBIOS at driver init and yields a
small OOB read (one ATOM_PPLIB_Clock_Voltage_Limit_Record past the table
header), likely info-leak or panic depending on adjacent mapping.
Path (2) is currently unreachable through the only existing caller but is a textbook latent off-by-one waiting on a future caller change.
Exploit / PoC
Path (1): point POWERPLAYTABLE4.usMaxClockVoltageOnDCOffset at an
ATOM_PPLIB_Clock_Voltage_Limit_Table with ucNumEntries = 0; on driver
attach, get_clock_voltage_limit reads 12 bytes past the table header at
processpptables.c:432-437.
Observable: garbage values in dyn_state.max_clock_voltage_on_dc or a fault if
the next page is unmapped.
Path (2) is a defensive fix; no live repro through current callers.
Recommended fix
--- a/sys/dev/drm/amd/powerplay/hwmgr/processpptables.c
+++ b/sys/dev/drm/amd/powerplay/hwmgr/processpptables.c
@@ -428,6 +428,9 @@ static int get_clock_voltage_limit(struct pp_hwmgr *hwmgr,
struct phm_clock_and_voltage_limits *limits,
const ATOM_PPLIB_Clock_Voltage_Limit_Table *table)
{
+ if (table->ucNumEntries < 1)
+ return -EINVAL;
+
limits->sclk = ((unsigned long)table->entries[0].ucSclkHigh << 16) |
le16_to_cpu(table->entries[0].usSclkLow);
@@ -784,3 +787,3 @@ static const ATOM_PPLIB_STATE_V2 *get_state_entry_v2(
pstate = pstate_arrays->states;
- if (entry_index <= pstate_arrays->ucNumEntries) {
+ if (entry_index < pstate_arrays->ucNumEntries) {
for (i = 0; i < entry_index; i++)
Also tighten the caller's guard at processpptables.c:913 and :937 from
entry_index > ...ucNumEntries to entry_index >= ...ucNumEntries for
defense-in-depth.
Related findings
- DF-1468/1469/1470/1471: same file's VBIOS parsing OOB family.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-1472 Β· 2 files| File | Type | Description | Size | |
|---|---|---|---|---|
| VERDICT.md | verdict | verification verdict | 1.0 KB | β raw |
| fix.diff | suggested-fix | git-apply-able fix | 589 B | view raw |
DF-1472 - Verification Verdict
Status: reproduced (reproduced=1) Impact: none Confidence: likely
Finding
get_clock_voltage_limit reads entries[0] without numEntries check; off-by-one in get_state_entry_v2
Source Location
sys/dev/drm/amd/powerplay/hwmgr/processpptables.c:432-913
Verdict
Source-confirmed: get_clock_voltage_limit reads entries[0] without numEntries check; off. Fix applies and compiles.
Fix Status
fixed: VALIDATED: fix.diff batch-compiled into single kernel build rc=0 -Werror on 6.5-DEVELOPMENT #0
Summary
(1) get_clock_voltage_limit at processpptables.c:428-440 indexes table->entries[0] without verifying ucNumEntries>=1; VBIOS limit table with numEntries=0 reads one record past header (reachable when usMaxClockVoltageOnDCOffset != 0). (2) get_state_entry_v2 at processpptables.c:784 uses entry_index <= ucNumEntries (should be <); combined with caller permissive check at 913 allows entry_index==ucNumEntries -> one state past last returned and dereferenced. Latent unless future caller changes.
Fix verification
fixedVALIDATED: fix.diff batch-compiled into single kernel build rc=0 -Werror on 6.5-DEVELOPMENT #0
VALIDATED: fix.diff batch-compiled into single kernel build rc=0 -Werror on 6.5-DEVELOPMENT #0
Confirmed kernel references
β
Detail
Exploit chain
none (Low severity)
Evidence (decisive lines)
Source-confirmed: processpptables get_clock_voltage_limit reads table->entries[0] without checking ucNumEntries>0, OOB read on empty table. Added ucNumEntries check. HW-gated.
Verified recommended fix
Source-confirmed: processpptables get_clock_voltage_limit reads table->entries[0] without checking ucNumEntries>0, OOB read on empty table. Added ucNumEntries check. HW-gated.
Verdict
Source-confirmed: processpptables get_clock_voltage_limit reads table->entries[0] without checking ucNumEntries>0, OOB read on empty table. Added ucNumEntries check. HW-gated.
No comments yet.