aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDmitry Monakhov <dmonakhov@openvz.org>2009-10-04 16:38:55 -0400
committerDave Jones <davej@redhat.com>2009-11-17 23:15:04 -0500
commite77b89f13a0d48aea70b69976e854f2a2444a519 (patch)
treed78288fc4386e1613713fff8c13d28f7ec480d32
parent293afe44d75abce4252db76cbb303a7de4297ce1 (diff)
[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 084f34939424161669467c19280dbcf637730314 ##TESTCASE## #!/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: Dmitry Monakhov <dmonakhov@openvz.org> Signed-off-by: Dave Jones <davej@redhat.com>
-rw-r--r--drivers/cpufreq/cpufreq.c16
1 files changed, 10 insertions, 6 deletions
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 3938c7817095..dab1410d1c0d 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -41,7 +41,7 @@ static struct cpufreq_driver *cpufreq_driver;
41static DEFINE_PER_CPU(struct cpufreq_policy *, cpufreq_cpu_data); 41static DEFINE_PER_CPU(struct cpufreq_policy *, cpufreq_cpu_data);
42#ifdef CONFIG_HOTPLUG_CPU 42#ifdef CONFIG_HOTPLUG_CPU
43/* This one keeps track of the previously set governor of a removed CPU */ 43/* This one keeps track of the previously set governor of a removed CPU */
44static DEFINE_PER_CPU(struct cpufreq_governor *, cpufreq_cpu_governor); 44static DEFINE_PER_CPU(char[CPUFREQ_NAME_LEN], cpufreq_cpu_governor);
45#endif 45#endif
46static DEFINE_SPINLOCK(cpufreq_driver_lock); 46static DEFINE_SPINLOCK(cpufreq_driver_lock);
47 47
@@ -774,10 +774,12 @@ int cpufreq_add_dev_policy(unsigned int cpu, struct cpufreq_policy *policy,
774#ifdef CONFIG_SMP 774#ifdef CONFIG_SMP
775 unsigned long flags; 775 unsigned long flags;
776 unsigned int j; 776 unsigned int j;
777
778#ifdef CONFIG_HOTPLUG_CPU 777#ifdef CONFIG_HOTPLUG_CPU
779 if (per_cpu(cpufreq_cpu_governor, cpu)) { 778 struct cpufreq_governor *gov;
780 policy->governor = per_cpu(cpufreq_cpu_governor, cpu); 779
780 gov = __find_governor(per_cpu(cpufreq_cpu_governor, cpu));
781 if (gov) {
782 policy->governor = gov;
781 dprintk("Restoring governor %s for cpu %d\n", 783 dprintk("Restoring governor %s for cpu %d\n",
782 policy->governor->name, cpu); 784 policy->governor->name, cpu);
783 } 785 }
@@ -1111,7 +1113,8 @@ static int __cpufreq_remove_dev(struct sys_device *sys_dev)
1111#ifdef CONFIG_SMP 1113#ifdef CONFIG_SMP
1112 1114
1113#ifdef CONFIG_HOTPLUG_CPU 1115#ifdef CONFIG_HOTPLUG_CPU
1114 per_cpu(cpufreq_cpu_governor, cpu) = data->governor; 1116 strncpy(per_cpu(cpufreq_cpu_governor, cpu), data->governor->name,
1117 CPUFREQ_NAME_LEN);
1115#endif 1118#endif
1116 1119
1117 /* if we have other CPUs still registered, we need to unlink them, 1120 /* 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)
1135 continue; 1138 continue;
1136 dprintk("removing link for cpu %u\n", j); 1139 dprintk("removing link for cpu %u\n", j);
1137#ifdef CONFIG_HOTPLUG_CPU 1140#ifdef CONFIG_HOTPLUG_CPU
1138 per_cpu(cpufreq_cpu_governor, j) = data->governor; 1141 strncpy(per_cpu(cpufreq_cpu_governor, j),
1142 data->governor->name, CPUFREQ_NAME_LEN);
1139#endif 1143#endif
1140 cpu_sys_dev = get_cpu_sysdev(j); 1144 cpu_sys_dev = get_cpu_sysdev(j);
1141 sysfs_remove_link(&cpu_sys_dev->kobj, "cpufreq"); 1145 sysfs_remove_link(&cpu_sys_dev->kobj, "cpufreq");