| From 3ffbb2e3c0cba7e91f8eb9d1ac03b4b7deda8793 Mon Sep 17 00:00:00 2001 |
| From: Borislav Petkov <bp@suse.de> |
| Date: Tue, 4 Feb 2020 13:28:41 +0100 |
| Subject: [PATCH] x86/mce/amd: Publish the bank pointer only after setup has |
| succeeded |
| |
| 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: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/arch/x86/kernel/cpu/mce/amd.c b/arch/x86/kernel/cpu/mce/amd.c |
| index 303b8c58845e..740d95ea05d2 100644 |
| --- a/arch/x86/kernel/cpu/mce/amd.c |
| +++ b/arch/x86/kernel/cpu/mce/amd.c |
| @@ -1194,8 +1194,9 @@ static const char *get_name(unsigned int bank, struct threshold_block *b) |
| 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; |
| @@ -1239,16 +1240,12 @@ static int allocate_threshold_blocks(unsigned int cpu, unsigned int bank, |
| |
| 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: |
| @@ -1256,7 +1253,7 @@ static int allocate_threshold_blocks(unsigned int cpu, unsigned int bank, |
| 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; |
| |
| @@ -1341,8 +1338,6 @@ static int threshold_create_bank(unsigned int cpu, unsigned int bank) |
| goto out_free; |
| } |
| |
| - per_cpu(threshold_banks, cpu)[bank] = b; |
| - |
| if (is_shared_bank(bank)) { |
| refcount_set(&b->cpus, 1); |
| |
| @@ -1353,9 +1348,13 @@ static int threshold_create_bank(unsigned int cpu, unsigned int bank) |
| } |
| } |
| |
| - 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); |
| -- |
| 2.7.4 |
| |