lkml.org 
[lkml]   [2020]   [Feb]   [27]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 4.14 191/237] x86/mce/amd: Publish the bank pointer only after setup has succeeded
    Date
    From: Borislav Petkov <bp@suse.de>

    commit 6e5cf31fbe651bed7ba1df768f2e123531132417 upstream.

    threshold_create_bank() creates a bank descriptor per MCA error
    thresholding counter which can be controlled over sysfs. It publishes
    the pointer to that bank in a per-CPU variable and then goes on to
    create additional thresholding blocks if the bank has such.

    However, that creation of additional blocks in
    allocate_threshold_blocks() can fail, leading to a use-after-free
    through the per-CPU pointer.

    Therefore, publish that pointer only after all blocks have been setup
    successfully.

    Fixes: 019f34fccfd5 ("x86, MCE, AMD: Move shared bank to node descriptor")
    Reported-by: Saar Amar <Saar.Amar@microsoft.com>
    Reported-by: Dan Carpenter <dan.carpenter@oracle.com>
    Signed-off-by: Borislav Petkov <bp@suse.de>
    Cc: <stable@vger.kernel.org>
    Link: http://lkml.kernel.org/r/20200128140846.phctkvx5btiexvbx@kili.mountain
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

    ---
    arch/x86/kernel/cpu/mcheck/mce_amd.c | 33 ++++++++++++++++-----------------
    1 file changed, 16 insertions(+), 17 deletions(-)

    --- a/arch/x86/kernel/cpu/mcheck/mce_amd.c
    +++ b/arch/x86/kernel/cpu/mcheck/mce_amd.c
    @@ -1151,8 +1151,9 @@ static const char *get_name(unsigned int
    return buf_mcatype;
    }

    -static int allocate_threshold_blocks(unsigned int cpu, unsigned int bank,
    - unsigned int block, u32 address)
    +static int allocate_threshold_blocks(unsigned int cpu, struct threshold_bank *tb,
    + unsigned int bank, unsigned int block,
    + u32 address)
    {
    struct threshold_block *b = NULL;
    u32 low, high;
    @@ -1196,16 +1197,12 @@ static int allocate_threshold_blocks(uns

    INIT_LIST_HEAD(&b->miscj);

    - if (per_cpu(threshold_banks, cpu)[bank]->blocks) {
    - list_add(&b->miscj,
    - &per_cpu(threshold_banks, cpu)[bank]->blocks->miscj);
    - } else {
    - per_cpu(threshold_banks, cpu)[bank]->blocks = b;
    - }
    + if (tb->blocks)
    + list_add(&b->miscj, &tb->blocks->miscj);
    + else
    + tb->blocks = b;

    - err = kobject_init_and_add(&b->kobj, &threshold_ktype,
    - per_cpu(threshold_banks, cpu)[bank]->kobj,
    - get_name(bank, b));
    + err = kobject_init_and_add(&b->kobj, &threshold_ktype, tb->kobj, get_name(bank, b));
    if (err)
    goto out_free;
    recurse:
    @@ -1213,7 +1210,7 @@ recurse:
    if (!address)
    return 0;

    - err = allocate_threshold_blocks(cpu, bank, block, address);
    + err = allocate_threshold_blocks(cpu, tb, bank, block, address);
    if (err)
    goto out_free;

    @@ -1298,8 +1295,6 @@ static int threshold_create_bank(unsigne
    goto out_free;
    }

    - per_cpu(threshold_banks, cpu)[bank] = b;
    -
    if (is_shared_bank(bank)) {
    refcount_set(&b->cpus, 1);

    @@ -1310,9 +1305,13 @@ static int threshold_create_bank(unsigne
    }
    }

    - err = allocate_threshold_blocks(cpu, bank, 0, msr_ops.misc(bank));
    - if (!err)
    - goto out;
    + err = allocate_threshold_blocks(cpu, b, bank, 0, msr_ops.misc(bank));
    + if (err)
    + goto out_free;
    +
    + per_cpu(threshold_banks, cpu)[bank] = b;
    +
    + return 0;

    out_free:
    kfree(b);

    \
     
     \ /
      Last update: 2020-02-27 15:34    [W:2.713 / U:1.908 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site