Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0a3aca3a authored by Borislav Petkov's avatar Borislav Petkov Committed by Greg Kroah-Hartman
Browse files

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: 019f34fc ("x86, MCE, AMD: Move shared bank to node descriptor")
Reported-by: default avatarSaar Amar <Saar.Amar@microsoft.com>
Reported-by: default avatarDan Carpenter <dan.carpenter@oracle.com>
Signed-off-by: default avatarBorislav Petkov <bp@suse.de>
Cc: <stable@vger.kernel.org>
Link: http://lkml.kernel.org/r/20200128140846.phctkvx5btiexvbx@kili.mountain


Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 4512119a
Loading
Loading
Loading
Loading
+16 −17
Original line number Diff line number Diff line
@@ -1152,8 +1152,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;
@@ -1197,16 +1198,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:
@@ -1214,7 +1211,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;

@@ -1299,8 +1296,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);

@@ -1311,9 +1306,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);