[PATCH] cpufreq: Skip inactive policies in cpufreq_driver_target()
From: Zhongqiu Han
Date: Tue Nov 10 2026 - 09:15:17 EST
A policy obtained with cpufreq_cpu_get() may become inactive before
cpufreq_driver_target() acquires its rwsem, which may lead to a NULL
pointer dereference:
CPU X CPU Y (last CPU in policy)
cpufreq_cpu_get()
cpufreq_offline()
__cpufreq_offline()
->exit() /* frees freq_table */
policy->freq_table = NULL
cpufreq_driver_target()
__cpufreq_driver_target()
__target_index()
policy->freq_table[index] /* NULL dereference */
Before commit 2372784542cb ("cpufreq: Drop 'freq_table' argument of
__target_index()"), __cpufreq_driver_target() returned an error if
policy->freq_table was NULL. Since the offline path clears it under the
policy rwsem, which cpufreq_driver_target() also holds, that check was
sufficient to prevent the crash.
The race has been reachable in-tree since commit c210063b40ac
("cpufreq: mediatek: Add opp notification support"), which added the
first caller of cpufreq_driver_target() that can run concurrently with
CPU offline.
Address this by making cpufreq_driver_target() return -EBUSY if the
policy is inactive after acquiring its rwsem, in analogy with the checks
in cpufreq_get(), refresh_frequency_limits() and the sysfs show() and
store() callbacks.
Reported-by: Sashiko <sashiko-bot@xxxxxxxxxx>
Closes: https://sashiko.dev/#/patchset/20261104153042.3987338-1-zhongqiu.han%40oss.qualcomm.com
Fixes: 2372784542cb ("cpufreq: Drop 'freq_table' argument of __target_index()")
Fixes: c210063b40ac ("cpufreq: mediatek: Add opp notification support")
Cc: stable@xxxxxxxxxxxxxxx # v5.19+
Signed-off-by: Zhongqiu Han <zhongqiu.han@xxxxxxxxxxxxxxxx>
---
Fix the issue discussed at:
https://lore.kernel.org/all/a4b320d9-ade6-4f39-9e9a-e9a82b13152e@xxxxxxxxxxxxxxxx/
drivers/cpufreq/cpufreq.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 54dde8419bdc..352ee4a1f085 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -2403,6 +2403,14 @@ int cpufreq_driver_target(struct cpufreq_policy *policy,
{
guard(cpufreq_policy_write)(policy);
+ /*
+ * The last CPU in the policy may have gone offline after the caller
+ * obtained it, in which case the policy is inactive and must not be
+ * used for changing the frequency.
+ */
+ if (unlikely(policy_is_inactive(policy)))
+ return -EBUSY;
+
return __cpufreq_driver_target(policy, target_freq, relation);
}
EXPORT_SYMBOL_GPL(cpufreq_driver_target);
--
2.43.0