Commit dca132a6 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'ras-urgent-2020-02-22' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull RAS fixes from Thomas Gleixner:
 "Two fixes for the AMD MCE driver:

   - Populate the per CPU MCA bank descriptor pointer only after it has
     been completely set up to prevent a use-after-free in case that one
     of the subsequent initialization step fails

   - Implement a proper release function for the sysfs entries of MCA
     threshold controls instead of freeing the memory right in the CPU
     teardown code, which leads to another use-after-free when the
     associated sysfs file is opened and accessed"

* tag 'ras-urgent-2020-02-22' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  x86/mce/amd: Fix kobject lifetime
  x86/mce/amd: Publish the bank pointer only after setup has succeeded
parents f3cc2494 51dede9c
...@@ -1163,9 +1163,12 @@ static const struct sysfs_ops threshold_ops = { ...@@ -1163,9 +1163,12 @@ static const struct sysfs_ops threshold_ops = {
.store = store, .store = store,
}; };
static void threshold_block_release(struct kobject *kobj);
static struct kobj_type threshold_ktype = { static struct kobj_type threshold_ktype = {
.sysfs_ops = &threshold_ops, .sysfs_ops = &threshold_ops,
.default_attrs = default_attrs, .default_attrs = default_attrs,
.release = threshold_block_release,
}; };
static const char *get_name(unsigned int bank, struct threshold_block *b) static const char *get_name(unsigned int bank, struct threshold_block *b)
...@@ -1198,8 +1201,9 @@ static const char *get_name(unsigned int bank, struct threshold_block *b) ...@@ -1198,8 +1201,9 @@ static const char *get_name(unsigned int bank, struct threshold_block *b)
return buf_mcatype; return buf_mcatype;
} }
static int allocate_threshold_blocks(unsigned int cpu, unsigned int bank, static int allocate_threshold_blocks(unsigned int cpu, struct threshold_bank *tb,
unsigned int block, u32 address) unsigned int bank, unsigned int block,
u32 address)
{ {
struct threshold_block *b = NULL; struct threshold_block *b = NULL;
u32 low, high; u32 low, high;
...@@ -1243,16 +1247,12 @@ static int allocate_threshold_blocks(unsigned int cpu, unsigned int bank, ...@@ -1243,16 +1247,12 @@ static int allocate_threshold_blocks(unsigned int cpu, unsigned int bank,
INIT_LIST_HEAD(&b->miscj); INIT_LIST_HEAD(&b->miscj);
if (per_cpu(threshold_banks, cpu)[bank]->blocks) { if (tb->blocks)
list_add(&b->miscj, list_add(&b->miscj, &tb->blocks->miscj);
&per_cpu(threshold_banks, cpu)[bank]->blocks->miscj); else
} else { tb->blocks = b;
per_cpu(threshold_banks, cpu)[bank]->blocks = b;
}
err = kobject_init_and_add(&b->kobj, &threshold_ktype, err = kobject_init_and_add(&b->kobj, &threshold_ktype, tb->kobj, get_name(bank, b));
per_cpu(threshold_banks, cpu)[bank]->kobj,
get_name(bank, b));
if (err) if (err)
goto out_free; goto out_free;
recurse: recurse:
...@@ -1260,7 +1260,7 @@ static int allocate_threshold_blocks(unsigned int cpu, unsigned int bank, ...@@ -1260,7 +1260,7 @@ static int allocate_threshold_blocks(unsigned int cpu, unsigned int bank,
if (!address) if (!address)
return 0; return 0;
err = allocate_threshold_blocks(cpu, bank, block, address); err = allocate_threshold_blocks(cpu, tb, bank, block, address);
if (err) if (err)
goto out_free; goto out_free;
...@@ -1345,8 +1345,6 @@ static int threshold_create_bank(unsigned int cpu, unsigned int bank) ...@@ -1345,8 +1345,6 @@ static int threshold_create_bank(unsigned int cpu, unsigned int bank)
goto out_free; goto out_free;
} }
per_cpu(threshold_banks, cpu)[bank] = b;
if (is_shared_bank(bank)) { if (is_shared_bank(bank)) {
refcount_set(&b->cpus, 1); refcount_set(&b->cpus, 1);
...@@ -1357,9 +1355,13 @@ static int threshold_create_bank(unsigned int cpu, unsigned int bank) ...@@ -1357,9 +1355,13 @@ static int threshold_create_bank(unsigned int cpu, unsigned int bank)
} }
} }
err = allocate_threshold_blocks(cpu, bank, 0, msr_ops.misc(bank)); err = allocate_threshold_blocks(cpu, b, bank, 0, msr_ops.misc(bank));
if (!err) if (err)
goto out; goto out_free;
per_cpu(threshold_banks, cpu)[bank] = b;
return 0;
out_free: out_free:
kfree(b); kfree(b);
...@@ -1368,8 +1370,12 @@ static int threshold_create_bank(unsigned int cpu, unsigned int bank) ...@@ -1368,8 +1370,12 @@ static int threshold_create_bank(unsigned int cpu, unsigned int bank)
return err; return err;
} }
static void deallocate_threshold_block(unsigned int cpu, static void threshold_block_release(struct kobject *kobj)
unsigned int bank) {
kfree(to_block(kobj));
}
static void deallocate_threshold_block(unsigned int cpu, unsigned int bank)
{ {
struct threshold_block *pos = NULL; struct threshold_block *pos = NULL;
struct threshold_block *tmp = NULL; struct threshold_block *tmp = NULL;
...@@ -1379,13 +1385,11 @@ static void deallocate_threshold_block(unsigned int cpu, ...@@ -1379,13 +1385,11 @@ static void deallocate_threshold_block(unsigned int cpu,
return; return;
list_for_each_entry_safe(pos, tmp, &head->blocks->miscj, miscj) { list_for_each_entry_safe(pos, tmp, &head->blocks->miscj, miscj) {
kobject_put(&pos->kobj);
list_del(&pos->miscj); list_del(&pos->miscj);
kfree(pos); kobject_put(&pos->kobj);
} }
kfree(per_cpu(threshold_banks, cpu)[bank]->blocks); kobject_put(&head->blocks->kobj);
per_cpu(threshold_banks, cpu)[bank]->blocks = NULL;
} }
static void __threshold_remove_blocks(struct threshold_bank *b) static void __threshold_remove_blocks(struct threshold_bank *b)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment