|
23 | 23 |
|
24 | 24 | #include <linux/earlycpio.h>
|
25 | 25 | #include <linux/firmware.h>
|
| 26 | +#include <linux/bsearch.h> |
26 | 27 | #include <linux/uaccess.h>
|
27 | 28 | #include <linux/vmalloc.h>
|
28 | 29 | #include <linux/initrd.h>
|
29 | 30 | #include <linux/kernel.h>
|
30 | 31 | #include <linux/pci.h>
|
31 | 32 |
|
| 33 | +#include <crypto/sha2.h> |
| 34 | + |
32 | 35 | #include <asm/microcode.h>
|
33 | 36 | #include <asm/processor.h>
|
| 37 | +#include <asm/cmdline.h> |
34 | 38 | #include <asm/setup.h>
|
35 | 39 | #include <asm/cpu.h>
|
36 | 40 | #include <asm/msr.h>
|
@@ -145,6 +149,98 @@ ucode_path[] __maybe_unused = "kernel/x86/microcode/AuthenticAMD.bin";
|
145 | 149 | */
|
146 | 150 | static u32 bsp_cpuid_1_eax __ro_after_init;
|
147 | 151 |
|
| 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 | + |
148 | 244 | static u32 get_patch_level(void)
|
149 | 245 | {
|
150 | 246 | u32 rev, dummy __always_unused;
|
@@ -497,6 +593,9 @@ static bool __apply_microcode_amd(struct microcode_amd *mc, u32 *cur_rev,
|
497 | 593 | {
|
498 | 594 | unsigned long p_addr = (unsigned long)&mc->hdr.data_code;
|
499 | 595 |
|
| 596 | + if (!verify_sha256_digest(mc->hdr.patch_id, *cur_rev, (const u8 *)p_addr, psize)) |
| 597 | + return -1; |
| 598 | + |
500 | 599 | native_wrmsrl(MSR_AMD64_PATCH_LOADER, p_addr);
|
501 | 600 |
|
502 | 601 | 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_
|
572 | 671 | struct cont_desc desc = { };
|
573 | 672 | struct microcode_amd *mc;
|
574 | 673 | struct cpio_data cp = { };
|
| 674 | + char buf[4]; |
575 | 675 | u32 rev;
|
576 | 676 |
|
| 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 | + |
577 | 685 | bsp_cpuid_1_eax = cpuid_1_eax;
|
578 | 686 |
|
579 | 687 | rev = get_patch_level();
|
@@ -903,8 +1011,7 @@ static int verify_and_add_patch(u8 family, u8 *fw, unsigned int leftover,
|
903 | 1011 | }
|
904 | 1012 |
|
905 | 1013 | /* 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) |
908 | 1015 | {
|
909 | 1016 | u8 *fw = (u8 *)data;
|
910 | 1017 | size_t offset;
|
|
0 commit comments