Re: [PATCH] cpufreq: Skip inactive policies in cpufreq_driver_target()

From: Rafael J. Wysocki (Intel)

Date: Tue Nov 10 2026 - 13:57:13 EST


On Tue, Nov 10, 2026 at 2:58 PM Zhongqiu Han
<zhongqiu.han@xxxxxxxxxxxxxxxx> wrote:
>
> 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);
> --

Applied as 7.4-rc material, thanks!