* [PATCH] cpufreq: acpi-cpufreq: add NULL check for acpi_perf_data before freeing
@ 2026-08-10 6:10 lirongqing
2026-08-10 6:10 ` [PATCH] cpufreq: acpi-cpufreq: Initialize cmd.val in drv_read() lirongqing
` (2 more replies)
0 siblings, 3 replies; 8+ messages in thread
From: lirongqing @ 2026-08-10 6:10 UTC (permalink / raw)
To: Rafael J . Wysocki, Viresh Kumar, linux-pm; +Cc: Li RongQing
From: Li RongQing <lirongqing@baidu.com>
If alloc_percpu() fails in acpi_cpufreq_early_init(), acpi_perf_data is
NULL. Calling free_acpi_perf_data() will execute per_cpu_ptr(NULL, i),
which does not return NULL but an offset pointer.
Dereferencing ->shared_cpu_map on this invalid pointer leads to a kernel
crash.
Fix these issues by adding a NULL check at the start of
free_acpi_perf_data() and setting acpi_perf_data to NULL after freeing.
Signed-off-by: Li RongQing <lirongqing@baidu.com>
---
drivers/cpufreq/acpi-cpufreq.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/drivers/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/acpi-cpufreq.c
index 87e4923..cd2ca87 100644
--- a/drivers/cpufreq/acpi-cpufreq.c
+++ b/drivers/cpufreq/acpi-cpufreq.c
@@ -517,11 +517,14 @@ static void free_acpi_perf_data(void)
{
unsigned int i;
- /* Freeing a NULL pointer is OK, and alloc_percpu zeroes. */
+ if (!acpi_perf_data)
+ return;
+
for_each_possible_cpu(i)
free_cpumask_var(per_cpu_ptr(acpi_perf_data, i)
->shared_cpu_map);
free_percpu(acpi_perf_data);
+ acpi_perf_data = NULL;
}
static int cpufreq_boost_down_prep(unsigned int cpu)
--
2.9.4
^ permalink raw reply related [flat|nested] 8+ messages in thread* [PATCH] cpufreq: acpi-cpufreq: Initialize cmd.val in drv_read() 2026-08-10 6:10 [PATCH] cpufreq: acpi-cpufreq: add NULL check for acpi_perf_data before freeing lirongqing @ 2026-08-10 6:10 ` lirongqing 2026-08-10 12:15 ` Zhongqiu Han 2026-08-10 6:10 ` [PATCH] cpufreq: acpi-cpufreq: Using cpufreq_for_each_entry() to iterate in extract_io() lirongqing 2026-08-10 11:21 ` [PATCH] cpufreq: acpi-cpufreq: add NULL check for acpi_perf_data before freeing Zhongqiu Han 2 siblings, 1 reply; 8+ messages in thread From: lirongqing @ 2026-08-10 6:10 UTC (permalink / raw) To: Rafael J . Wysocki, Viresh Kumar, linux-pm; +Cc: Li RongQing From: Li RongQing <lirongqing@baidu.com> In drv_read(), struct drv_cmd cmd is allocated on the stack with .val left uninitialized. If smp_call_function_any() fails, do_drv_read() will not run to populate cmd.val. As a result, drv_read() would return uninitialized stack data. Fix this by explicitly initializing .val to 0 when declaring cmd. Signed-off-by: Li RongQing <lirongqing@baidu.com> --- drivers/cpufreq/acpi-cpufreq.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/acpi-cpufreq.c index cd2ca87..6c7ece9 100644 --- a/drivers/cpufreq/acpi-cpufreq.c +++ b/drivers/cpufreq/acpi-cpufreq.c @@ -308,6 +308,7 @@ static u32 drv_read(struct acpi_cpufreq_data *data, const struct cpumask *mask) struct acpi_processor_performance *perf = to_perf_data(data); struct drv_cmd cmd = { .reg = &perf->control_register, + .val = 0, .func.read = data->cpu_freq_read, }; int err; -- 2.9.4 ^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH] cpufreq: acpi-cpufreq: Initialize cmd.val in drv_read() 2026-08-10 6:10 ` [PATCH] cpufreq: acpi-cpufreq: Initialize cmd.val in drv_read() lirongqing @ 2026-08-10 12:15 ` Zhongqiu Han 0 siblings, 0 replies; 8+ messages in thread From: Zhongqiu Han @ 2026-08-10 12:15 UTC (permalink / raw) To: lirongqing, Rafael J . Wysocki, Viresh Kumar, linux-pm; +Cc: zhongqiu.han On 8/10/2026 2:10 PM, lirongqing wrote: > From: Li RongQing <lirongqing@baidu.com> > > In drv_read(), struct drv_cmd cmd is allocated on the stack with .val left > uninitialized. If smp_call_function_any() fails, do_drv_read() will not > run to populate cmd.val. As a result, drv_read() would return uninitialized > stack data. > > Fix this by explicitly initializing .val to 0 when declaring cmd. > > Signed-off-by: Li RongQing <lirongqing@baidu.com> > --- > drivers/cpufreq/acpi-cpufreq.c | 1 + > 1 file changed, 1 insertion(+) > > diff --git a/drivers/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/acpi-cpufreq.c > index cd2ca87..6c7ece9 100644 > --- a/drivers/cpufreq/acpi-cpufreq.c > +++ b/drivers/cpufreq/acpi-cpufreq.c > @@ -308,6 +308,7 @@ static u32 drv_read(struct acpi_cpufreq_data *data, const struct cpumask *mask) > struct acpi_processor_performance *perf = to_perf_data(data); > struct drv_cmd cmd = { > .reg = &perf->control_register, > + .val = 0, Will the compiler handle this automatically? https://en.cppreference.com/c/language/initialization > .func.read = data->cpu_freq_read, > }; > int err; -- Thx and BRs, Zhongqiu Han ^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH] cpufreq: acpi-cpufreq: Using cpufreq_for_each_entry() to iterate in extract_io() 2026-08-10 6:10 [PATCH] cpufreq: acpi-cpufreq: add NULL check for acpi_perf_data before freeing lirongqing 2026-08-10 6:10 ` [PATCH] cpufreq: acpi-cpufreq: Initialize cmd.val in drv_read() lirongqing @ 2026-08-10 6:10 ` lirongqing 2026-08-12 13:59 ` Zhongqiu Han 2026-08-10 11:21 ` [PATCH] cpufreq: acpi-cpufreq: add NULL check for acpi_perf_data before freeing Zhongqiu Han 2 siblings, 1 reply; 8+ messages in thread From: lirongqing @ 2026-08-10 6:10 UTC (permalink / raw) To: Rafael J . Wysocki, Viresh Kumar, linux-pm; +Cc: Li RongQing From: Li RongQing <lirongqing@baidu.com> In extract_io(), the loop iterates up to perf->state_count. However, when building policy->freq_table in acpi_cpufreq_cpu_init(), duplicate frequency entries are skipped, making freq_table smaller than perf->state_count. Iterating perf->state_count times directly over policy->freq_table[i] can result in out-of-bounds array reads. Furthermore, policy->freq_table[i] does not necessarily correspond to perf->states[i], as the original P-state index is stored in freq_table[entry].driver_data. Fix this by using cpufreq_for_each_entry() to iterate over policy->freq_table, similar to extract_msr(). Signed-off-by: Li RongQing <lirongqing@baidu.com> --- drivers/cpufreq/acpi-cpufreq.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/acpi-cpufreq.c index 21639d9..87e4923 100644 --- a/drivers/cpufreq/acpi-cpufreq.c +++ b/drivers/cpufreq/acpi-cpufreq.c @@ -196,15 +196,14 @@ static int check_amd_hwpstate_cpu(unsigned int cpuid) static unsigned extract_io(struct cpufreq_policy *policy, u32 value) { struct acpi_cpufreq_data *data = policy->driver_data; + struct cpufreq_frequency_table *pos; struct acpi_processor_performance *perf; - int i; perf = to_perf_data(data); - for (i = 0; i < perf->state_count; i++) { - if (value == perf->states[i].status) - return policy->freq_table[i].frequency; - } + cpufreq_for_each_entry(pos, policy->freq_table) + if (value == perf->states[pos->driver_data].status) + return pos->frequency; return 0; } -- 2.9.4 ^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH] cpufreq: acpi-cpufreq: Using cpufreq_for_each_entry() to iterate in extract_io() 2026-08-10 6:10 ` [PATCH] cpufreq: acpi-cpufreq: Using cpufreq_for_each_entry() to iterate in extract_io() lirongqing @ 2026-08-12 13:59 ` Zhongqiu Han 0 siblings, 0 replies; 8+ messages in thread From: Zhongqiu Han @ 2026-08-12 13:59 UTC (permalink / raw) To: lirongqing, Rafael J . Wysocki, Viresh Kumar, linux-pm Cc: zhongqiu.han, linux-kernel@vger.kernel.org On 8/10/2026 2:10 PM, lirongqing wrote: > From: Li RongQing <lirongqing@baidu.com> > > In extract_io(), the loop iterates up to perf->state_count. However, > when building policy->freq_table in acpi_cpufreq_cpu_init(), duplicate > frequency entries are skipped, making freq_table smaller than > perf->state_count. > > Iterating perf->state_count times directly over policy->freq_table[i] can > result in out-of-bounds array reads. Furthermore, policy->freq_table[i] There is no out-of-bounds access. The array has "state_count + 1" elements, so every index in "[0, state_count)" is inside the allocation. right? The changelog looks like a memory-safety fix, which it is not, and that wording alone would get the patch (mis)routed to stable and to CVE bots. > does not necessarily correspond to perf->states[i], as the original P-state > index is stored in freq_table[entry].driver_data. Yes, the real defect is the index space mismatch. Might be good to note the side effects of it, AFAICT freq_table[i] is not perf->states[i] once any _PSS entry has been skipped. The function can therefore return a frequency belonging to a different P-state, or 0 (zeroed tail entries), or CPUFREQ_TABLE_END (~1u) when "i == valid_states", i.e. 0xfffffffe kHz reported as a frequency. That last one is worth spelling out. > > Fix this by using cpufreq_for_each_entry() to iterate over > policy->freq_table, similar to extract_msr(). > Please add one Fixes tag here as well. > Signed-off-by: Li RongQing <lirongqing@baidu.com> > --- > drivers/cpufreq/acpi-cpufreq.c | 9 ++++----- > 1 file changed, 4 insertions(+), 5 deletions(-) > > diff --git a/drivers/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/acpi-cpufreq.c > index 21639d9..87e4923 100644 > --- a/drivers/cpufreq/acpi-cpufreq.c > +++ b/drivers/cpufreq/acpi-cpufreq.c > @@ -196,15 +196,14 @@ static int check_amd_hwpstate_cpu(unsigned int cpuid) > static unsigned extract_io(struct cpufreq_policy *policy, u32 value) > { > struct acpi_cpufreq_data *data = policy->driver_data; > + struct cpufreq_frequency_table *pos; > struct acpi_processor_performance *perf; > - int i; > > perf = to_perf_data(data); > > - for (i = 0; i < perf->state_count; i++) { > - if (value == perf->states[i].status) > - return policy->freq_table[i].frequency; > - } > + cpufreq_for_each_entry(pos, policy->freq_table) > + if (value == perf->states[pos->driver_data].status) > + return pos->frequency; > return 0; > } One more potential same issue is in func get_cur_freq_on_cpu() cached_freq = policy->freq_table[to_perf_data(data)->state].frequency; It is better to fix it as well. For v2, please use ./scripts/get_maintainer.pl to generate the CC list so linux-kernel@vger.kernel.org doesn't get missed. Thanks > -- Thx and BRs, Zhongqiu Han ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] cpufreq: acpi-cpufreq: add NULL check for acpi_perf_data before freeing 2026-08-10 6:10 [PATCH] cpufreq: acpi-cpufreq: add NULL check for acpi_perf_data before freeing lirongqing 2026-08-10 6:10 ` [PATCH] cpufreq: acpi-cpufreq: Initialize cmd.val in drv_read() lirongqing 2026-08-10 6:10 ` [PATCH] cpufreq: acpi-cpufreq: Using cpufreq_for_each_entry() to iterate in extract_io() lirongqing @ 2026-08-10 11:21 ` Zhongqiu Han 2026-08-10 11:52 ` Zhongqiu Han 2026-08-12 12:06 ` 答复: [外部邮件] " Li,Rongqing 2 siblings, 2 replies; 8+ messages in thread From: Zhongqiu Han @ 2026-08-10 11:21 UTC (permalink / raw) To: lirongqing, Rafael J . Wysocki, Viresh Kumar, linux-pm; +Cc: zhongqiu.han On 8/10/2026 2:10 PM, lirongqing wrote: > From: Li RongQing <lirongqing@baidu.com> > > If alloc_percpu() fails in acpi_cpufreq_early_init(), acpi_perf_data is > NULL. Calling free_acpi_perf_data() will execute per_cpu_ptr(NULL, i), > which does not return NULL but an offset pointer. Hi RongQing, Could you please confirm if acpi_perf_data() can ever be executed when alloc_percpu() fails? > Dereferencing ->shared_cpu_map on this invalid pointer leads to a kernel > crash. > > Fix these issues by adding a NULL check at the start of > free_acpi_perf_data() and setting acpi_perf_data to NULL after freeing. > > Signed-off-by: Li RongQing <lirongqing@baidu.com> > --- > drivers/cpufreq/acpi-cpufreq.c | 5 ++++- > 1 file changed, 4 insertions(+), 1 deletion(-) > > diff --git a/drivers/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/acpi-cpufreq.c > index 87e4923..cd2ca87 100644 > --- a/drivers/cpufreq/acpi-cpufreq.c > +++ b/drivers/cpufreq/acpi-cpufreq.c > @@ -517,11 +517,14 @@ static void free_acpi_perf_data(void) > { > unsigned int i; > > - /* Freeing a NULL pointer is OK, and alloc_percpu zeroes. */ > + if (!acpi_perf_data) > + return; > + > for_each_possible_cpu(i) > free_cpumask_var(per_cpu_ptr(acpi_perf_data, i) > ->shared_cpu_map); > free_percpu(acpi_perf_data); > + acpi_perf_data = NULL; > } > > static int cpufreq_boost_down_prep(unsigned int cpu) -- Thx and BRs, Zhongqiu Han ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] cpufreq: acpi-cpufreq: add NULL check for acpi_perf_data before freeing 2026-08-10 11:21 ` [PATCH] cpufreq: acpi-cpufreq: add NULL check for acpi_perf_data before freeing Zhongqiu Han @ 2026-08-10 11:52 ` Zhongqiu Han 2026-08-12 12:06 ` 答复: [外部邮件] " Li,Rongqing 1 sibling, 0 replies; 8+ messages in thread From: Zhongqiu Han @ 2026-08-10 11:52 UTC (permalink / raw) To: lirongqing, Rafael J . Wysocki, Viresh Kumar, linux-pm; +Cc: zhongqiu.han On 8/10/2026 7:21 PM, Zhongqiu Han wrote: > On 8/10/2026 2:10 PM, lirongqing wrote: >> From: Li RongQing <lirongqing@baidu.com> >> >> If alloc_percpu() fails in acpi_cpufreq_early_init(), acpi_perf_data is >> NULL. Calling free_acpi_perf_data() will execute per_cpu_ptr(NULL, i), >> which does not return NULL but an offset pointer. > > Hi RongQing, > > Could you please confirm if acpi_perf_data() can ever be executed when > alloc_percpu() fails? Sorry, typo: acpi_perf_data() --> free_acpi_perf_data() > > >> Dereferencing ->shared_cpu_map on this invalid pointer leads to a kernel >> crash. >> >> Fix these issues by adding a NULL check at the start of >> free_acpi_perf_data() and setting acpi_perf_data to NULL after freeing. >> >> Signed-off-by: Li RongQing <lirongqing@baidu.com> >> --- >> drivers/cpufreq/acpi-cpufreq.c | 5 ++++- >> 1 file changed, 4 insertions(+), 1 deletion(-) >> >> diff --git a/drivers/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/acpi- >> cpufreq.c >> index 87e4923..cd2ca87 100644 >> --- a/drivers/cpufreq/acpi-cpufreq.c >> +++ b/drivers/cpufreq/acpi-cpufreq.c >> @@ -517,11 +517,14 @@ static void free_acpi_perf_data(void) >> { >> unsigned int i; >> - /* Freeing a NULL pointer is OK, and alloc_percpu zeroes. */ >> + if (!acpi_perf_data) >> + return; >> + >> for_each_possible_cpu(i) >> free_cpumask_var(per_cpu_ptr(acpi_perf_data, i) >> ->shared_cpu_map); >> free_percpu(acpi_perf_data); >> + acpi_perf_data = NULL; >> } >> static int cpufreq_boost_down_prep(unsigned int cpu) > > -- Thx and BRs, Zhongqiu Han ^ permalink raw reply [flat|nested] 8+ messages in thread
* 答复: [外部邮件] Re: [PATCH] cpufreq: acpi-cpufreq: add NULL check for acpi_perf_data before freeing 2026-08-10 11:21 ` [PATCH] cpufreq: acpi-cpufreq: add NULL check for acpi_perf_data before freeing Zhongqiu Han 2026-08-10 11:52 ` Zhongqiu Han @ 2026-08-12 12:06 ` Li,Rongqing 1 sibling, 0 replies; 8+ messages in thread From: Li,Rongqing @ 2026-08-12 12:06 UTC (permalink / raw) To: Zhongqiu Han, Rafael J . Wysocki, Viresh Kumar, linux-pm@vger.kernel.org > > > > If alloc_percpu() fails in acpi_cpufreq_early_init(), acpi_perf_data > > is NULL. Calling free_acpi_perf_data() will execute per_cpu_ptr(NULL, > > i), which does not return NULL but an offset pointer. > > Hi RongQing, > > Could you please confirm if acpi_perf_data() can ever be executed when > alloc_percpu() fails? You are right, acpi_perf_data() can not be called when alloc_percpu() fails Please drop this patch thanks [Li,Rongqing] > > > > Dereferencing ->shared_cpu_map on this invalid pointer leads to a kernel > > crash. > > > > Fix these issues by adding a NULL check at the start of > > free_acpi_perf_data() and setting acpi_perf_data to NULL after freeing. > > > > Signed-off-by: Li RongQing <lirongqing@baidu.com> > > --- > > drivers/cpufreq/acpi-cpufreq.c | 5 ++++- > > 1 file changed, 4 insertions(+), 1 deletion(-) > > > > diff --git a/drivers/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/acpi-cpufreq.c > > index 87e4923..cd2ca87 100644 > > --- a/drivers/cpufreq/acpi-cpufreq.c > > +++ b/drivers/cpufreq/acpi-cpufreq.c > > @@ -517,11 +517,14 @@ static void free_acpi_perf_data(void) > > { > > unsigned int i; > > > > - /* Freeing a NULL pointer is OK, and alloc_percpu zeroes. */ > > + if (!acpi_perf_data) > > + return; > > + > > for_each_possible_cpu(i) > > free_cpumask_var(per_cpu_ptr(acpi_perf_data, i) > > ->shared_cpu_map); > > free_percpu(acpi_perf_data); > > + acpi_perf_data = NULL; > > } > > > > static int cpufreq_boost_down_prep(unsigned int cpu) > > > -- > Thx and BRs, > Zhongqiu Han ^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2026-08-12 13:59 UTC | newest] Thread overview: 8+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-08-10 6:10 [PATCH] cpufreq: acpi-cpufreq: add NULL check for acpi_perf_data before freeing lirongqing 2026-08-10 6:10 ` [PATCH] cpufreq: acpi-cpufreq: Initialize cmd.val in drv_read() lirongqing 2026-08-10 12:15 ` Zhongqiu Han 2026-08-10 6:10 ` [PATCH] cpufreq: acpi-cpufreq: Using cpufreq_for_each_entry() to iterate in extract_io() lirongqing 2026-08-12 13:59 ` Zhongqiu Han 2026-08-10 11:21 ` [PATCH] cpufreq: acpi-cpufreq: add NULL check for acpi_perf_data before freeing Zhongqiu Han 2026-08-10 11:52 ` Zhongqiu Han 2026-08-12 12:06 ` 答复: [外部邮件] " Li,Rongqing
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox