Commit e77b89f1 authored by Dmitry Monakhov's avatar Dmitry Monakhov Committed by Dave Jones
Browse files

[CPUFREQ] Fix use after free on governor restore

Currently on governer backup/restore path we storing governor's pointer.
This is wrong because one may unload governor's module after cpu goes
offline. As result use-after-free will take place on restored cpu.
It is not easy to exploit this bug, but still we have to close this
issue ASAP. Issue was introduced by following commit

#!/bin/sh -x
modprobe acpi_cpufreq
# Any non default governor, in may case it is "ondemand"
modprobe cpufreq_ondemand
echo ondemand > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
rmmod acpi_cpufreq
rmmod cpufreq_ondemand
modprobe acpi_cpufreq  # << use-after-free here.
Signed-off-by: default avatarDmitry Monakhov <>
Signed-off-by: default avatarDave Jones <>
parent 293afe44
......@@ -41,7 +41,7 @@ static struct cpufreq_driver *cpufreq_driver;
static DEFINE_PER_CPU(struct cpufreq_policy *, cpufreq_cpu_data);
/* This one keeps track of the previously set governor of a removed CPU */
static DEFINE_PER_CPU(struct cpufreq_governor *, cpufreq_cpu_governor);
static DEFINE_PER_CPU(char[CPUFREQ_NAME_LEN], cpufreq_cpu_governor);
static DEFINE_SPINLOCK(cpufreq_driver_lock);
......@@ -774,10 +774,12 @@ int cpufreq_add_dev_policy(unsigned int cpu, struct cpufreq_policy *policy,
unsigned long flags;
unsigned int j;
if (per_cpu(cpufreq_cpu_governor, cpu)) {
policy->governor = per_cpu(cpufreq_cpu_governor, cpu);
struct cpufreq_governor *gov;
gov = __find_governor(per_cpu(cpufreq_cpu_governor, cpu));
if (gov) {
policy->governor = gov;
dprintk("Restoring governor %s for cpu %d\n",
policy->governor->name, cpu);
......@@ -1111,7 +1113,8 @@ static int __cpufreq_remove_dev(struct sys_device *sys_dev)
per_cpu(cpufreq_cpu_governor, cpu) = data->governor;
strncpy(per_cpu(cpufreq_cpu_governor, cpu), data->governor->name,
/* if we have other CPUs still registered, we need to unlink them,
......@@ -1135,7 +1138,8 @@ static int __cpufreq_remove_dev(struct sys_device *sys_dev)
dprintk("removing link for cpu %u\n", j);
per_cpu(cpufreq_cpu_governor, j) = data->governor;
strncpy(per_cpu(cpufreq_cpu_governor, j),
data->governor->name, CPUFREQ_NAME_LEN);
cpu_sys_dev = get_cpu_sysdev(j);
sysfs_remove_link(&cpu_sys_dev->kobj, "cpufreq");
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment