[PATCH] cpufreq: Fix race between suspend/resume and CPU hotplug

From: Tianxiang Chen

Date: Tue Apr 07 2026 - 05:36:30 EST


CPU hotplug operations can race with cpufreq_suspend()
and cpufreq_resume(), leading to null pointer dereferences
when accessing governor data. This occurs because there is
no synchronization between suspend/resume operations and
CPU hotplug, allowing concurrent access to
policy->governor_data while it is being freed or initialized.

Detailed race condition scenario:

1. Thread A (cpufreq_suspend) starts execution:
- Iterates through active policies
- Calls cpufreq_stop_governor(policy) for each policy
- Sets cpufreq_suspended = true

2. Thread B (CPU hotplug) executes concurrently:
- Calls cpu_down(cpu)
- Calls cpuhp_cpufreq_offline(cpu)
- Calls cpufreq_offline(cpu)
- Inside cpufreq_offline():
* Stops governor: policy->governor->stop(policy)
* Exits governor: policy->governor->exit(policy)
* Frees governor_data: kfree(policy->governor_data)
* Sets policy->governor_data = NULL

3. Race window between step 1 and step 2:
- Thread A is iterating policies and stopping governors
- Thread B is concurrently executing CPU offline
- Both threads may access the same policy->governor_data
- Thread B frees governor_data while Thread A is still using it
- Thread A accesses freed governor_data → null pointer dereference

Similarly, cpufreq_resume() can race with CPU hotplug where governor_data
is being initialized while hotplug is trying to access it, leading to
accessing uninitialized data.

Signed-off-by: Tianxiang Chen <nanmu@xxxxxxxxxx>
---
drivers/cpufreq/cpufreq.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 1f794524a1d9..8b03785764fa 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -1979,6 +1979,7 @@ void cpufreq_suspend(void)
if (!cpufreq_driver)
return;

+ cpus_read_lock();
if (!has_target() && !cpufreq_driver->suspend)
goto suspend;

@@ -1998,6 +1999,7 @@ void cpufreq_suspend(void)

suspend:
cpufreq_suspended = true;
+ cpus_read_unlock();
}

/**
@@ -2017,10 +2019,11 @@ void cpufreq_resume(void)
if (unlikely(!cpufreq_suspended))
return;

+ cpus_read_lock();
cpufreq_suspended = false;

if (!has_target() && !cpufreq_driver->resume)
- return;
+ goto out;

pr_debug("%s: Resuming Governors\n", __func__);

@@ -2038,6 +2041,9 @@ void cpufreq_resume(void)
__func__, policy->cpu);
}
}
+
+out:
+ cpus_read_unlock();
}

/**
--
2.34.1

#/******本邮件及其附件含有小米公司的保密信息,仅限于发送给上面地址中列出的个人或群组。禁止任何其他人以任何形式使用(包括但不限于全部或部分地泄露、复制、或散发)本邮件中的信息。如果您错收了本邮件,请您立即电话或邮件通知发件人并删除本邮件! This e-mail and its attachments contain confidential information from XIAOMI, which is intended only for the person or entity whose address is listed above. Any use of the information contained herein in any way (including, but not limited to, total or partial disclosure, reproduction, or dissemination) by persons other than the intended recipient(s) is prohibited. If you receive this e-mail in error, please notify the sender by phone or email immediately and delete it!******/#