thermal: cpu_cooling: Avoid accessing potentially freed structures
authorViresh Kumar <viresh.kumar@linaro.org>
Tue, 25 Apr 2017 10:27:08 +0000 (15:57 +0530)
committerChungwoo Park <cww.park@samsung.com>
Mon, 21 May 2018 08:22:04 +0000 (17:22 +0900)
commit 289d72afddf83440117c35d864bf0c6309c1d011 upstream.

After the lock is dropped, it is possible that the cpufreq_dev gets
freed before we call get_level() and that can cause kernel to crash.

Drop the lock after we are done using the structure.

Resolved migration conflicts from kernel 4.9 to 4.14.
- allowed_cpus -> policy->related_cpus

Change-Id: Ib7f00f738b761e291d01abbd2bf9b5745ad404e8
Signed-off-by: Eunseok Choi <es10.choi@samsung.com>
drivers/thermal/cpu_cooling.c

index 1082738973bb3a75fa7215d3aa0ffa57c1e98e42..70fe51e2d9802956432feadae99b78b85591ab5d 100644 (file)
@@ -116,6 +116,37 @@ static unsigned long get_level(struct cpufreq_cooling_device *cpufreq_cdev,
        return level - 1;
 }
 
+/**
+ * cpufreq_cooling_get_level - for a given cpu, return the cooling level.
+ * @cpu: cpu for which the level is required
+ * @freq: the frequency of interest
+ *
+ * This function will match the cooling level corresponding to the
+ * requested @freq and return it.
+ *
+ * Return: The matched cooling level on success or THERMAL_CSTATE_INVALID
+ * otherwise.
+ */
+unsigned long cpufreq_cooling_get_level(unsigned int cpu, unsigned int freq)
+{
+       struct cpufreq_cooling_device *cpufreq_cdev;
+
+       mutex_lock(&cooling_list_lock);
+       list_for_each_entry(cpufreq_cdev, &cpufreq_cdev_list, node) {
+               if (cpumask_test_cpu(cpu, cpufreq_cdev->policy->related_cpus)) {
+                       unsigned long level = get_level(cpufreq_cdev, freq);
+
+                       mutex_unlock(&cooling_list_lock);
+                       return level;
+               }
+       }
+       mutex_unlock(&cooling_list_lock);
+
+       pr_err("%s: cpu:%d not part of any cooling device\n", __func__, cpu);
+       return THERMAL_CSTATE_INVALID;
+}
+EXPORT_SYMBOL_GPL(cpufreq_cooling_get_level);
+
 /**
  * cpufreq_thermal_notifier - notifier callback for cpufreq policy change.
  * @nb:        struct notifier_block * with callback info.