Commit d430a305 authored by Borislav Petkov's avatar Borislav Petkov

x86/microcode/AMD: Change verify_patch()'s return value

Have it return 0 on success, positive value when the current patch
should be skipped and negative on error.
Signed-off-by: default avatarBorislav Petkov <bp@suse.de>
Cc: x86@kernel.org
Link: https://lkml.kernel.org/r/20181107170218.7596-11-bp@alien8.de
parent c7957020
...@@ -210,24 +210,32 @@ __verify_patch_size(u8 family, u32 sh_psize, unsigned int buf_size) ...@@ -210,24 +210,32 @@ __verify_patch_size(u8 family, u32 sh_psize, unsigned int buf_size)
break; break;
} }
if (sh_psize > min_t(u32, buf_size, max_size)) { if (sh_psize > min_t(u32, buf_size, max_size))
pr_err("patch size mismatch\n");
return 0; return 0;
}
return sh_psize; return sh_psize;
} }
static unsigned int /*
verify_patch(u8 family, const u8 *buf, unsigned int buf_size, bool early) * Verify the patch in @buf.
*
* Returns:
* negative: on error
* positive: patch is not for this family, skip it
* 0: success
*/
static int
verify_patch(u8 family, const u8 *buf, size_t buf_size, u32 *patch_size, bool early)
{ {
struct microcode_header_amd *mc_hdr; struct microcode_header_amd *mc_hdr;
unsigned int ret;
u32 sh_psize; u32 sh_psize;
u16 proc_id; u16 proc_id;
u8 patch_fam; u8 patch_fam;
if (!__verify_patch_section(buf, buf_size, &sh_psize, early)) if (!__verify_patch_section(buf, buf_size, &sh_psize, early))
return 0; return -1;
/* /*
* The section header length is not included in this indicated size * The section header length is not included in this indicated size
* but is present in the leftover file length so we need to subtract * but is present in the leftover file length so we need to subtract
...@@ -243,23 +251,31 @@ verify_patch(u8 family, const u8 *buf, unsigned int buf_size, bool early) ...@@ -243,23 +251,31 @@ verify_patch(u8 family, const u8 *buf, unsigned int buf_size, bool early)
if (!early) if (!early)
pr_debug("Patch of size %u truncated.\n", sh_psize); pr_debug("Patch of size %u truncated.\n", sh_psize);
return 0; return -1;
} }
mc_hdr = (struct microcode_header_amd *)(buf + SECTION_HDR_SIZE); ret = __verify_patch_size(family, sh_psize, buf_size);
proc_id = mc_hdr->processor_rev_id; if (!ret) {
if (!early)
pr_debug("Per-family patch size mismatch.\n");
return -1;
}
*patch_size = sh_psize;
mc_hdr = (struct microcode_header_amd *)(buf + SECTION_HDR_SIZE);
if (mc_hdr->nb_dev_id || mc_hdr->sb_dev_id) { if (mc_hdr->nb_dev_id || mc_hdr->sb_dev_id) {
if (!early) if (!early)
pr_err("Patch-ID 0x%08x: chipset-specific code unsupported.\n", mc_hdr->patch_id); pr_err("Patch-ID 0x%08x: chipset-specific code unsupported.\n", mc_hdr->patch_id);
return 0; return -1;
} }
proc_id = mc_hdr->processor_rev_id;
patch_fam = 0xf + (proc_id >> 12); patch_fam = 0xf + (proc_id >> 12);
if (patch_fam != family) if (patch_fam != family)
return 0; return 1;
return __verify_patch_size(family, sh_psize, buf_size); return 0;
} }
/* /*
...@@ -729,23 +745,17 @@ static void cleanup(void) ...@@ -729,23 +745,17 @@ static void cleanup(void)
* driver cannot continue functioning normally. In such cases, we tear * driver cannot continue functioning normally. In such cases, we tear
* down everything we've used up so far and exit. * down everything we've used up so far and exit.
*/ */
static int verify_and_add_patch(u8 family, u8 *fw, unsigned int leftover) static int verify_and_add_patch(u8 family, u8 *fw, unsigned int leftover,
unsigned int *patch_size)
{ {
struct microcode_header_amd *mc_hdr; struct microcode_header_amd *mc_hdr;
unsigned int patch_size, crnt_size;
struct ucode_patch *patch; struct ucode_patch *patch;
u16 proc_id; u16 proc_id;
int ret;
patch_size = verify_patch(family, fw, leftover, false); ret = verify_patch(family, fw, leftover, patch_size, false);
if (!patch_size) { if (ret)
pr_debug("Patch size mismatch.\n"); return ret;
return 1;
}
/* If initial rough pokes pass, we can start looking at the header. */
crnt_size = patch_size + SECTION_HDR_SIZE;
mc_hdr = (struct microcode_header_amd *)(fw + SECTION_HDR_SIZE);
proc_id = mc_hdr->processor_rev_id;
patch = kzalloc(sizeof(*patch), GFP_KERNEL); patch = kzalloc(sizeof(*patch), GFP_KERNEL);
if (!patch) { if (!patch) {
...@@ -753,13 +763,16 @@ static int verify_and_add_patch(u8 family, u8 *fw, unsigned int leftover) ...@@ -753,13 +763,16 @@ static int verify_and_add_patch(u8 family, u8 *fw, unsigned int leftover)
return -EINVAL; return -EINVAL;
} }
patch->data = kmemdup(fw + SECTION_HDR_SIZE, patch_size, GFP_KERNEL); patch->data = kmemdup(fw + SECTION_HDR_SIZE, *patch_size, GFP_KERNEL);
if (!patch->data) { if (!patch->data) {
pr_err("Patch data allocation failure.\n"); pr_err("Patch data allocation failure.\n");
kfree(patch); kfree(patch);
return -EINVAL; return -EINVAL;
} }
mc_hdr = (struct microcode_header_amd *)(fw + SECTION_HDR_SIZE);
proc_id = mc_hdr->processor_rev_id;
INIT_LIST_HEAD(&patch->plist); INIT_LIST_HEAD(&patch->plist);
patch->patch_id = mc_hdr->patch_id; patch->patch_id = mc_hdr->patch_id;
patch->equiv_cpu = proc_id; patch->equiv_cpu = proc_id;
...@@ -770,39 +783,39 @@ static int verify_and_add_patch(u8 family, u8 *fw, unsigned int leftover) ...@@ -770,39 +783,39 @@ static int verify_and_add_patch(u8 family, u8 *fw, unsigned int leftover)
/* ... and add to cache. */ /* ... and add to cache. */
update_cache(patch); update_cache(patch);
return crnt_size; return 0;
} }
static enum ucode_state __load_microcode_amd(u8 family, const u8 *data, static enum ucode_state __load_microcode_amd(u8 family, const u8 *data,
size_t size) size_t size)
{ {
enum ucode_state ret = UCODE_ERROR;
unsigned int leftover;
u8 *fw = (u8 *)data; u8 *fw = (u8 *)data;
int crnt_size = 0;
int offset; int offset;
offset = install_equiv_cpu_table(data); offset = install_equiv_cpu_table(data);
if (offset < 0) { if (offset < 0) {
pr_err("failed to create equivalent cpu table\n"); pr_err("failed to create equivalent cpu table\n");
return ret; return UCODE_ERROR;
} }
fw += offset; fw += offset;
leftover = size - offset; size -= offset;
if (*(u32 *)fw != UCODE_UCODE_TYPE) { if (*(u32 *)fw != UCODE_UCODE_TYPE) {
pr_err("invalid type field in container file section header\n"); pr_err("invalid type field in container file section header\n");
free_equiv_cpu_table(); free_equiv_cpu_table();
return ret; return UCODE_ERROR;
} }
while (leftover) { while (size > 0) {
crnt_size = verify_and_add_patch(family, fw, leftover); unsigned int crnt_size = 0;
if (crnt_size < 0) int ret;
return ret;
ret = verify_and_add_patch(family, fw, size, &crnt_size);
if (ret < 0)
return UCODE_ERROR;
fw += crnt_size; fw += crnt_size + SECTION_HDR_SIZE;
leftover -= crnt_size; size -= (crnt_size + SECTION_HDR_SIZE);
} }
return UCODE_OK; return UCODE_OK;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment