mirror of https://gitee.com/openkylin/linux.git
x86/mce/amd: Fix kobject lifetime
Accessing the MCA thresholding controls in sysfs concurrently with CPU
hotplug can lead to a couple of KASAN-reported issues:
BUG: KASAN: use-after-free in sysfs_file_ops+0x155/0x180
Read of size 8 at addr ffff888367578940 by task grep/4019
and
BUG: KASAN: use-after-free in show_error_count+0x15c/0x180
Read of size 2 at addr ffff888368a05514 by task grep/4454
for example. Both result from the fact that the threshold block
creation/teardown code frees the descriptor memory itself instead of
defining proper ->release function and leaving it to the driver core to
take care of that, after all sysfs accesses have completed.
Do that and get rid of the custom freeing code, fixing the above UAFs in
the process.
[ bp: write commit message. ]
Fixes: 9526866439
("[PATCH] x86_64: mce_amd support for family 0x10 processors")
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Borislav Petkov <bp@suse.de>
Cc: <stable@vger.kernel.org>
Link: https://lkml.kernel.org/r/20200214082801.13836-1-bp@alien8.de
This commit is contained in:
parent
6e5cf31fbe
commit
51dede9c05
|
@ -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)
|
||||||
|
@ -1367,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;
|
||||||
|
@ -1378,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)
|
||||||
|
|
Loading…
Reference in New Issue