lkml.org 
[lkml]   [2022]   [Jun]   [7]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 5.18 335/879] cpufreq: Fix possible race in cpufreq online error path
    Date
    From: Schspa Shi <schspa@gmail.com>

    [ Upstream commit f346e96267cd76175d6c201b40f770c0116a8a04 ]

    When cpufreq online fails, the policy->cpus mask is not cleared and
    policy->rwsem is released too early, so the driver can be invoked
    via the cpuinfo_cur_freq sysfs attribute while its ->offline() or
    ->exit() callbacks are being run.

    Take policy->clk as an example:

    static int cpufreq_online(unsigned int cpu)
    {
    ...
    // policy->cpus != 0 at this time
    down_write(&policy->rwsem);
    ret = cpufreq_add_dev_interface(policy);
    up_write(&policy->rwsem);

    return 0;

    out_destroy_policy:
    for_each_cpu(j, policy->real_cpus)
    remove_cpu_dev_symlink(policy, get_cpu_device(j));
    up_write(&policy->rwsem);
    ...
    out_exit_policy:
    if (cpufreq_driver->exit)
    cpufreq_driver->exit(policy);
    clk_put(policy->clk);
    // policy->clk is a wild pointer
    ...
    ^
    |
    Another process access
    __cpufreq_get
    cpufreq_verify_current_freq
    cpufreq_generic_get
    // acces wild pointer of policy->clk;
    |
    |
    out_offline_policy: |
    cpufreq_policy_free(policy); |
    // deleted here, and will wait for no body reference
    cpufreq_policy_put_kobj(policy);
    }

    Address this by modifying cpufreq_online() to release policy->rwsem
    in the error path after the driver callbacks have run and to clear
    policy->cpus before releasing the semaphore.

    Fixes: 7106e02baed4 ("cpufreq: release policy->rwsem on error")
    Signed-off-by: Schspa Shi <schspa@gmail.com>
    [ rjw: Subject and changelog edits ]
    Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
    Signed-off-by: Sasha Levin <sashal@kernel.org>
    ---
    drivers/cpufreq/cpufreq.c | 5 +++--
    1 file changed, 3 insertions(+), 2 deletions(-)

    diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
    index fbaa8e6c7d23..233e8af48848 100644
    --- a/drivers/cpufreq/cpufreq.c
    +++ b/drivers/cpufreq/cpufreq.c
    @@ -1534,8 +1534,6 @@ static int cpufreq_online(unsigned int cpu)
    for_each_cpu(j, policy->real_cpus)
    remove_cpu_dev_symlink(policy, get_cpu_device(j));

    - up_write(&policy->rwsem);
    -
    out_offline_policy:
    if (cpufreq_driver->offline)
    cpufreq_driver->offline(policy);
    @@ -1544,6 +1542,9 @@ static int cpufreq_online(unsigned int cpu)
    if (cpufreq_driver->exit)
    cpufreq_driver->exit(policy);

    + cpumask_clear(policy->cpus);
    + up_write(&policy->rwsem);
    +
    out_free_policy:
    cpufreq_policy_free(policy);
    return ret;
    --
    2.35.1


    \
     
     \ /
      Last update: 2022-06-08 00:37    [W:4.173 / U:0.024 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site