From 47779c331906ce4635eb1da9b45b36b0d0c3e37f Mon Sep 17 00:00:00 2001 From: Schspa Shi Date: Tue, 7 Nov 2023 08:15:42 +0000 Subject: [PATCH 1/2] cpufreq: Abort show()/store() for half-initialized policies mainline inclusion from mainline-v5.19-rc1 commit d4627a287e251efed59f2b4bda82c5950768c963 category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I8EI9L?from=project-issue CVE: NA Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=d4627a287e251efed59f2b4bda82c5950768c963 -------------------------------- If policy initialization fails after the sysfs files are created, there is a possibility to end up running show()/store() callbacks for half-initialized policies, which may have unpredictable outcomes. Abort show()/store() in such a case by making sure the policy is active. Also dectivate the policy on such failures. Signed-off-by: Schspa Shi Acked-by: Viresh Kumar [ rjw: Subject and changelog edits ] Signed-off-by: Rafael J. Wysocki Conflicts: drivers/cpufreq/cpufreq.c Signed-off-by: Jinjie Ruan --- drivers/cpufreq/cpufreq.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 58342390966b..9897d842c8a4 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -946,13 +946,14 @@ static ssize_t show(struct kobject *kobj, struct attribute *attr, char *buf) { struct cpufreq_policy *policy = to_policy(kobj); struct freq_attr *fattr = to_attr(attr); - ssize_t ret; + ssize_t ret = -EBUSY; if (!fattr->show) return -EIO; down_read(&policy->rwsem); - ret = fattr->show(policy, buf); + if (likely(!policy_is_inactive(policy))) + ret = fattr->show(policy, buf); up_read(&policy->rwsem); return ret; @@ -963,7 +964,7 @@ static ssize_t store(struct kobject *kobj, struct attribute *attr, { struct cpufreq_policy *policy = to_policy(kobj); struct freq_attr *fattr = to_attr(attr); - ssize_t ret = -EINVAL; + ssize_t ret = -EBUSY; if (!fattr->store) return -EIO; @@ -977,7 +978,8 @@ static ssize_t store(struct kobject *kobj, struct attribute *attr, if (cpu_online(policy->cpu)) { down_write(&policy->rwsem); - ret = fattr->store(policy, buf, count); + if (likely(!policy_is_inactive(policy))) + ret = fattr->store(policy, buf, count); up_write(&policy->rwsem); } @@ -1515,6 +1517,7 @@ static int cpufreq_online(unsigned int cpu) for_each_cpu(j, policy->real_cpus) remove_cpu_dev_symlink(policy, get_cpu_device(j)); + cpumask_clear(policy->cpus); up_write(&policy->rwsem); out_offline_policy: -- Gitee From 86c575c47465e7e4dadd6368dd82e3c023859434 Mon Sep 17 00:00:00 2001 From: Schspa Shi Date: Tue, 7 Nov 2023 08:15:43 +0000 Subject: [PATCH 2/2] cpufreq: make interface functions and lock holding state clear mainline inclusion from mainline-v5.19-rc1 commit 514ff1bcd98d7f57361025e2200b803d3ddde6c8 category: cleanup bugzilla: https://gitee.com/openeuler/kernel/issues/I8EI9L?from=project-issue CVE: NA Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=514ff1bcd98d7f57361025e2200b803d3ddde6c8 -------------------------------- cpufreq_offline() calls offline() and exit() under the policy rwsem But they are called outside the rwsem in cpufreq_online(). Make cpufreq_online() call offline() and exit() as well as online() and init() under the policy rwsem to achieve a clear lock relationship. All of the init() and online() implementations in the tree only initialize the policy object without attempting to acquire the policy rwsem and they won't call cpufreq APIs attempting to acquire it. Signed-off-by: Schspa Shi Acked-by: Viresh Kumar [ rjw: Changelog edits ] Signed-off-by: Rafael J. Wysocki Conflicts: drivers/cpufreq/cpufreq.c Signed-off-by: Jinjie Ruan --- drivers/cpufreq/cpufreq.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 9897d842c8a4..70f7a638b6db 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -1337,12 +1337,12 @@ static int cpufreq_online(unsigned int cpu) down_write(&policy->rwsem); policy->cpu = cpu; policy->governor = NULL; - up_write(&policy->rwsem); } else { new_policy = true; policy = cpufreq_policy_alloc(cpu); if (!policy) return -ENOMEM; + down_write(&policy->rwsem); } if (!new_policy && cpufreq_driver->online) { @@ -1382,7 +1382,6 @@ static int cpufreq_online(unsigned int cpu) cpumask_copy(policy->related_cpus, policy->cpus); } - down_write(&policy->rwsem); /* * affected cpus must always be the one, which are online. We aren't * managing offline cpus here. @@ -1518,7 +1517,6 @@ static int cpufreq_online(unsigned int cpu) remove_cpu_dev_symlink(policy, get_cpu_device(j)); cpumask_clear(policy->cpus); - up_write(&policy->rwsem); out_offline_policy: if (cpufreq_driver->offline) @@ -1529,6 +1527,8 @@ static int cpufreq_online(unsigned int cpu) cpufreq_driver->exit(policy); out_free_policy: + up_write(&policy->rwsem); + cpufreq_policy_free(policy); return ret; } -- Gitee