mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
cpufreq/amd-pstate: Fix TOCTOU when changing driver mode via sysfs
amd_pstate_update_status() evaluates mode_state_machine[cppc_state]
[mode_idx] before taking amd_pstate_driver_lock, and then re-evaluates it
again once the lock is held. cppc_state is global and only stable under
the lock, so concurrent sysfs writes race:
CPU 0 CPU 1
----- -----
// cppc_state == A, mode == B
if (mode_state_machine[A][B]) // sees non-NULL
if (mode_state_machine[A][B])
guard(&amd_pstate_driver_lock);
mode_state_machine[A][B](B);
cppc_state = B;
guard(&amd_pstate_driver_lock);
// cppc_state is now B
mode_state_machine[B][B](B); // NULL -> NULL deref
The re-read under the lock can resolve to a self-transition (NULL
pointer, immediate NULL deref) or to an unexpected transition that
redundantly runs amd_pstate_driver_cleanup(), double-freeing
current_pstate_driver->attr.
Take the lock first, then read cppc_state and resolve the transition
function exactly once into a local before calling it, so the check and
the call observe the same state.
Reported-by: Sashiko <sashiko-bot@kernel.org>
Closes: https://sashiko.dev/#/bug/linux-f86ff3a6-55df-4eef-8e4d-62ac270dba25
Fixes: 6f0b13f16f ("cpufreq/amd-pstate: Overhaul locking")
Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
Reviewed-by: K Prateek Nayak <kprateek.nayak@amd.com>
Tested-by: K Prateek Nayak <kprateek.nayak@amd.com>
Link: https://lore.kernel.org/r/20260922022347.1270746-1-mario.limonciello@amd.com
Signed-off-by: Mario Limonciello <superm1@kernel.org>
This commit is contained in:
parent
b400642c5e
commit
b667a68091
|
|
@ -1886,6 +1886,7 @@ EXPORT_SYMBOL_FOR_PSTATE_UT(amd_pstate_get_status);
|
|||
|
||||
int amd_pstate_update_status(const char *buf, size_t size)
|
||||
{
|
||||
cppc_mode_transition_fn fn;
|
||||
int mode_idx;
|
||||
|
||||
if (size > strlen("passive") || size < strlen("active"))
|
||||
|
|
@ -1895,10 +1896,12 @@ int amd_pstate_update_status(const char *buf, size_t size)
|
|||
if (mode_idx < 0)
|
||||
return mode_idx;
|
||||
|
||||
if (mode_state_machine[cppc_state][mode_idx]) {
|
||||
guard(mutex)(&amd_pstate_driver_lock);
|
||||
return mode_state_machine[cppc_state][mode_idx](mode_idx);
|
||||
}
|
||||
guard(mutex)(&amd_pstate_driver_lock);
|
||||
|
||||
/* Resolve the transition under the lock; cppc_state is only stable while held. */
|
||||
fn = mode_state_machine[cppc_state][mode_idx];
|
||||
if (fn)
|
||||
return fn(mode_idx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user