Skip to content

Commit 3e8653e

Browse files
bp3tk0vgregkh
authored andcommitted
x86/microcode/AMD: Load only SHA256-checksummed patches
commit 50cef76 upstream. Load patches for which the driver carries a SHA256 checksum of the patch blob. This can be disabled by adding "microcode.amd_sha_check=off" on the kernel cmdline. But it is highly NOT recommended. Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 0c110da commit 3e8653e

File tree

3 files changed

+554
-2
lines changed

3 files changed

+554
-2
lines changed

arch/x86/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1333,6 +1333,7 @@ config X86_REBOOTFIXUPS
13331333
config MICROCODE
13341334
def_bool y
13351335
depends on CPU_SUP_AMD || CPU_SUP_INTEL
1336+
select CRYPTO_LIB_SHA256 if CPU_SUP_AMD
13361337

13371338
config MICROCODE_INITRD32
13381339
def_bool y

arch/x86/kernel/cpu/microcode/amd.c

Lines changed: 109 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,18 @@
2323

2424
#include <linux/earlycpio.h>
2525
#include <linux/firmware.h>
26+
#include <linux/bsearch.h>
2627
#include <linux/uaccess.h>
2728
#include <linux/vmalloc.h>
2829
#include <linux/initrd.h>
2930
#include <linux/kernel.h>
3031
#include <linux/pci.h>
3132

33+
#include <crypto/sha2.h>
34+
3235
#include <asm/microcode.h>
3336
#include <asm/processor.h>
37+
#include <asm/cmdline.h>
3438
#include <asm/setup.h>
3539
#include <asm/cpu.h>
3640
#include <asm/msr.h>
@@ -145,6 +149,98 @@ ucode_path[] __maybe_unused = "kernel/x86/microcode/AuthenticAMD.bin";
145149
*/
146150
static u32 bsp_cpuid_1_eax __ro_after_init;
147151

152+
static bool sha_check = true;
153+
154+
struct patch_digest {
155+
u32 patch_id;
156+
u8 sha256[SHA256_DIGEST_SIZE];
157+
};
158+
159+
#include "amd_shas.c"
160+
161+
static int cmp_id(const void *key, const void *elem)
162+
{
163+
struct patch_digest *pd = (struct patch_digest *)elem;
164+
u32 patch_id = *(u32 *)key;
165+
166+
if (patch_id == pd->patch_id)
167+
return 0;
168+
else if (patch_id < pd->patch_id)
169+
return -1;
170+
else
171+
return 1;
172+
}
173+
174+
static bool need_sha_check(u32 cur_rev)
175+
{
176+
switch (cur_rev >> 8) {
177+
case 0x80012: return cur_rev <= 0x800126f; break;
178+
case 0x83010: return cur_rev <= 0x830107c; break;
179+
case 0x86001: return cur_rev <= 0x860010e; break;
180+
case 0x86081: return cur_rev <= 0x8608108; break;
181+
case 0x87010: return cur_rev <= 0x8701034; break;
182+
case 0x8a000: return cur_rev <= 0x8a0000a; break;
183+
case 0xa0011: return cur_rev <= 0xa0011da; break;
184+
case 0xa0012: return cur_rev <= 0xa001243; break;
185+
case 0xa1011: return cur_rev <= 0xa101153; break;
186+
case 0xa1012: return cur_rev <= 0xa10124e; break;
187+
case 0xa1081: return cur_rev <= 0xa108109; break;
188+
case 0xa2010: return cur_rev <= 0xa20102f; break;
189+
case 0xa2012: return cur_rev <= 0xa201212; break;
190+
case 0xa6012: return cur_rev <= 0xa60120a; break;
191+
case 0xa7041: return cur_rev <= 0xa704109; break;
192+
case 0xa7052: return cur_rev <= 0xa705208; break;
193+
case 0xa7080: return cur_rev <= 0xa708009; break;
194+
case 0xa70c0: return cur_rev <= 0xa70C009; break;
195+
case 0xaa002: return cur_rev <= 0xaa00218; break;
196+
default: break;
197+
}
198+
199+
pr_info("You should not be seeing this. Please send the following couple of lines to x86-<at>-kernel.org\n");
200+
pr_info("CPUID(1).EAX: 0x%x, current revision: 0x%x\n", bsp_cpuid_1_eax, cur_rev);
201+
return true;
202+
}
203+
204+
static bool verify_sha256_digest(u32 patch_id, u32 cur_rev, const u8 *data, unsigned int len)
205+
{
206+
struct patch_digest *pd = NULL;
207+
u8 digest[SHA256_DIGEST_SIZE];
208+
struct sha256_state s;
209+
int i;
210+
211+
if (x86_family(bsp_cpuid_1_eax) < 0x17 ||
212+
x86_family(bsp_cpuid_1_eax) > 0x19)
213+
return true;
214+
215+
if (!need_sha_check(cur_rev))
216+
return true;
217+
218+
if (!sha_check)
219+
return true;
220+
221+
pd = bsearch(&patch_id, phashes, ARRAY_SIZE(phashes), sizeof(struct patch_digest), cmp_id);
222+
if (!pd) {
223+
pr_err("No sha256 digest for patch ID: 0x%x found\n", patch_id);
224+
return false;
225+
}
226+
227+
sha256_init(&s);
228+
sha256_update(&s, data, len);
229+
sha256_final(&s, digest);
230+
231+
if (memcmp(digest, pd->sha256, sizeof(digest))) {
232+
pr_err("Patch 0x%x SHA256 digest mismatch!\n", patch_id);
233+
234+
for (i = 0; i < SHA256_DIGEST_SIZE; i++)
235+
pr_cont("0x%x ", digest[i]);
236+
pr_info("\n");
237+
238+
return false;
239+
}
240+
241+
return true;
242+
}
243+
148244
static u32 get_patch_level(void)
149245
{
150246
u32 rev, dummy __always_unused;
@@ -497,6 +593,9 @@ static bool __apply_microcode_amd(struct microcode_amd *mc, u32 *cur_rev,
497593
{
498594
unsigned long p_addr = (unsigned long)&mc->hdr.data_code;
499595

596+
if (!verify_sha256_digest(mc->hdr.patch_id, *cur_rev, (const u8 *)p_addr, psize))
597+
return -1;
598+
500599
native_wrmsrl(MSR_AMD64_PATCH_LOADER, p_addr);
501600

502601
if (x86_family(bsp_cpuid_1_eax) == 0x17) {
@@ -572,8 +671,17 @@ void __init load_ucode_amd_bsp(struct early_load_data *ed, unsigned int cpuid_1_
572671
struct cont_desc desc = { };
573672
struct microcode_amd *mc;
574673
struct cpio_data cp = { };
674+
char buf[4];
575675
u32 rev;
576676

677+
if (cmdline_find_option(boot_command_line, "microcode.amd_sha_check", buf, 4)) {
678+
if (!strncmp(buf, "off", 3)) {
679+
sha_check = false;
680+
pr_warn_once("It is a very very bad idea to disable the blobs SHA check!\n");
681+
add_taint(TAINT_CPU_OUT_OF_SPEC, LOCKDEP_STILL_OK);
682+
}
683+
}
684+
577685
bsp_cpuid_1_eax = cpuid_1_eax;
578686

579687
rev = get_patch_level();
@@ -903,8 +1011,7 @@ static int verify_and_add_patch(u8 family, u8 *fw, unsigned int leftover,
9031011
}
9041012

9051013
/* Scan the blob in @data and add microcode patches to the cache. */
906-
static enum ucode_state __load_microcode_amd(u8 family, const u8 *data,
907-
size_t size)
1014+
static enum ucode_state __load_microcode_amd(u8 family, const u8 *data, size_t size)
9081015
{
9091016
u8 *fw = (u8 *)data;
9101017
size_t offset;

0 commit comments

Comments
 (0)