x86/MCE/AMD: Cache SMCA MISC block addresses

... into a global, two-dimensional array and service subsequent reads from
that cache to avoid rdmsr_on_cpu() calls during CPU hotplug (IPIs with IRQs
disabled).

In addition, this fixes a KASAN slab-out-of-bounds read due to wrong usage
of the bank->blocks pointer.

Fixes: 27bd59502702 ("x86/mce/AMD: Get address from already initialized block")
Reported-by: Johannes Hirte <johannes.hirte@datenkhaos.de>
Tested-by: Johannes Hirte <johannes.hirte@datenkhaos.de>
Signed-off-by: Borislav Petkov <bp@suse.de>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Cc: Yazen Ghannam <yazen.ghannam@amd.com>
Link: http://lkml.kernel.org/r/20180414004230.GA2033@probook

authored by Borislav Petkov and committed by Thomas Gleixner 78ce2410 73fcb1a3

+14 -15
+14 -15
arch/x86/kernel/cpu/mcheck/mce_amd.c
··· 94 94 [SMCA_SMU] = { "smu", "System Management Unit" }, 95 95 }; 96 96 97 + static u32 smca_bank_addrs[MAX_NR_BANKS][NR_BLOCKS] __ro_after_init = 98 + { 99 + [0 ... MAX_NR_BANKS - 1] = { [0 ... NR_BLOCKS - 1] = -1 } 100 + }; 101 + 97 102 const char *smca_get_name(enum smca_bank_types t) 98 103 { 99 104 if (t >= N_SMCA_BANK_TYPES) ··· 448 443 if (!block) 449 444 return MSR_AMD64_SMCA_MCx_MISC(bank); 450 445 446 + /* Check our cache first: */ 447 + if (smca_bank_addrs[bank][block] != -1) 448 + return smca_bank_addrs[bank][block]; 449 + 451 450 /* 452 451 * For SMCA enabled processors, BLKPTR field of the first MISC register 453 452 * (MCx_MISC0) indicates presence of additional MISC regs set (MISC1-4). 454 453 */ 455 454 if (rdmsr_safe_on_cpu(cpu, MSR_AMD64_SMCA_MCx_CONFIG(bank), &low, &high)) 456 - return addr; 455 + goto out; 457 456 458 457 if (!(low & MCI_CONFIG_MCAX)) 459 - return addr; 458 + goto out; 460 459 461 460 if (!rdmsr_safe_on_cpu(cpu, MSR_AMD64_SMCA_MCx_MISC(bank), &low, &high) && 462 461 (low & MASK_BLKPTR_LO)) 463 - return MSR_AMD64_SMCA_MCx_MISCy(bank, block - 1); 462 + addr = MSR_AMD64_SMCA_MCx_MISCy(bank, block - 1); 464 463 464 + out: 465 + smca_bank_addrs[bank][block] = addr; 465 466 return addr; 466 467 } 467 468 ··· 478 467 479 468 if ((bank >= mca_cfg.banks) || (block >= NR_BLOCKS)) 480 469 return addr; 481 - 482 - /* Get address from already initialized block. */ 483 - if (per_cpu(threshold_banks, cpu)) { 484 - struct threshold_bank *bankp = per_cpu(threshold_banks, cpu)[bank]; 485 - 486 - if (bankp && bankp->blocks) { 487 - struct threshold_block *blockp = &bankp->blocks[block]; 488 - 489 - if (blockp) 490 - return blockp->address; 491 - } 492 - } 493 470 494 471 if (mce_flags.smca) 495 472 return smca_get_block_address(cpu, bank, block);