Received: by 10.192.165.148 with SMTP id m20csp3899571imm; Mon, 23 Apr 2018 14:38:10 -0700 (PDT) X-Google-Smtp-Source: AIpwx48XzN1Q/e5FghM29Qac6FlGdInJoikmMZvb6YaeMLkYl10lPM36YCbnpHAqL9kEoJjeBkV8 X-Received: by 2002:a17:902:8481:: with SMTP id c1-v6mr22047661plo.310.1524519490402; Mon, 23 Apr 2018 14:38:10 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1524519490; cv=none; d=google.com; s=arc-20160816; b=BpgxKLZ5DHtOGN2w3Vbo2YRVJmHl8x/I+7GIBivNho3K2Hz108LMpRDBQVNoiCd/Cq cQlN3kEw2muQsZKypClfTcbGor8nJzBUBvJ6CEHY0W0KdlE/JfMM/B08x7eNsGQwMFWD lZdcuipFNqUxAZ0xrBXaXCLE+tlonaA2Irk95GbuXeS9jc8katSzeI4Laxqmsa1Z1RwP HjFwAV10OkkcCXJ/ivLxzXFlZTrZjaAFqe7+7xdfM1nYQ/bMjcqzLb03bes2F8HL1cUu 5GlK2LLWBosWZRRs4m6ebtYYV8wnmUFXlrK7R/N3wtHtRHxjneY43pW/j42cmb6US8h3 5sYw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:arc-authentication-results; bh=sJjCG4b/y+pXXXUe3EzAhCMWBqA4OGOWG/jS3ZI58i0=; b=cIBsT/QzA8kc8AQgpNjLnuEvVD0NE3pv5e1JWl8Z6DyiLyEXQqfpV9fnFk90mHRKSq 4Vq5Zfe/gNgh/psW67wWJcwxdKd8Nu3++oq12x5Q/EjIIIzO+TyXJgPNYsIvcbj0PpNu 55pkxOwrIgxmB5dG9Qo695vx9z71wHjKx4fAFJRUJwwrfuFM67tFOCXrT0dERb6ZKNne 0NembS8+aqdqxCM22LjK45NoVwRN+vOTwbQWjpJnM0fpT+IERcNFgMKqpHSjMhuiUSgq dh8vXfr2xOa1JcrS7mywalgUpFBQu01+N/TyYK2hkYew/C9n9XtQVh07ECD7HgZA0A3h C0fQ== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id u71si5615551pgb.332.2018.04.23.14.37.55; Mon, 23 Apr 2018 14:38:10 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932525AbeDWVgW (ORCPT + 99 others); Mon, 23 Apr 2018 17:36:22 -0400 Received: from vps-vb.mhejs.net ([37.28.154.113]:40998 "EHLO vps-vb.mhejs.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S932485AbeDWVel (ORCPT ); Mon, 23 Apr 2018 17:34:41 -0400 Received: by vps-vb.mhejs.net with esmtps (TLSv1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.90_1) (envelope-from ) id 1fAj6D-0004wO-84; Mon, 23 Apr 2018 23:34:13 +0200 From: "Maciej S. Szmigiero" To: Borislav Petkov Cc: Thomas Gleixner , Ingo Molnar , "H. Peter Anvin" , x86@kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v5 4/6] x86/microcode/AMD: Check microcode container data in the late loader Date: Mon, 23 Apr 2018 23:34:09 +0200 Message-Id: <8f204a953dc4b46477e214ebd291021d7ab6fa6c.1524515406.git.mail@maciej.szmigiero.name> X-Mailer: git-send-email 2.17.0 In-Reply-To: References: Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org This commit converts the late loader in the AMD microcode update driver to use newly introduced microcode container data checking functions as the previous commit did for the early loader. Signed-off-by: Maciej S. Szmigiero --- arch/x86/kernel/cpu/microcode/amd.c | 87 +++++++++++++++++-------------------- 1 file changed, 40 insertions(+), 47 deletions(-) diff --git a/arch/x86/kernel/cpu/microcode/amd.c b/arch/x86/kernel/cpu/microcode/amd.c index 94fcd702a67a..b429d3f554b9 100644 --- a/arch/x86/kernel/cpu/microcode/amd.c +++ b/arch/x86/kernel/cpu/microcode/amd.c @@ -677,28 +677,24 @@ static enum ucode_state apply_microcode_amd(int cpu) return UCODE_UPDATED; } -static int install_equiv_cpu_table(const u8 *buf) +static unsigned int install_equiv_cpu_table(const u8 *buf, size_t buf_size) { - unsigned int *ibuf = (unsigned int *)buf; - unsigned int type = ibuf[1]; - unsigned int size = ibuf[2]; + const u32 *hdr = (const u32 *)buf; + u32 equiv_tbl_len; - if (type != UCODE_EQUIV_CPU_TABLE_TYPE || !size) { - pr_err("empty section/" - "invalid type field in container file section header\n"); - return -EINVAL; - } + if (!verify_equivalence_table(buf, buf_size, false)) + return 0; - equiv_cpu_table = vmalloc(size); + equiv_tbl_len = hdr[2]; + equiv_cpu_table = vmalloc(equiv_tbl_len); if (!equiv_cpu_table) { pr_err("failed to allocate equivalent CPU table\n"); - return -ENOMEM; + return 0; } - memcpy(equiv_cpu_table, buf + CONTAINER_HDR_SZ, size); + memcpy(equiv_cpu_table, buf + CONTAINER_HDR_SZ, equiv_tbl_len); - /* add header length */ - return size + CONTAINER_HDR_SZ; + return equiv_tbl_len; } static void free_equiv_cpu_table(void) @@ -715,20 +711,26 @@ static void cleanup(void) /* * We return the current size even if some of the checks failed so that - * we can skip over the next patch. If we return a negative value, we - * signal a grave error like a memory allocation has failed and the - * driver cannot continue functioning normally. In such cases, we tear - * down everything we've used up so far and exit. + * we can skip over the next patch. If we return zero, we signal a + * grave error like a memory allocation has failed and the driver cannot + * continue functioning normally. In such cases, we tear down everything + * we've used up so far and exit. */ -static int verify_and_add_patch(u8 family, u8 *fw, unsigned int leftover) +static unsigned int verify_and_add_patch(u8 family, u8 *fw, + unsigned int leftover) { + u32 *hdr = (u32 *)fw; struct microcode_header_amd *mc_hdr; struct ucode_patch *patch; - unsigned int patch_size, crnt_size, ret; + u32 patch_size; + unsigned int crnt_size; u32 proc_fam; u16 proc_id; - patch_size = *(u32 *)(fw + 4); + if (!verify_patch_section(fw, leftover, false)) + return leftover; + + patch_size = hdr[1]; crnt_size = patch_size + SECTION_HDR_SIZE; mc_hdr = (struct microcode_header_amd *)(fw + SECTION_HDR_SIZE); proc_id = mc_hdr->processor_rev_id; @@ -750,28 +752,20 @@ static int verify_and_add_patch(u8 family, u8 *fw, unsigned int leftover) return crnt_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 - * it before passing this value to the function below. - */ - ret = verify_patch_size(family, patch_size, leftover - SECTION_HDR_SIZE); - if (!ret) { - pr_err("Patch-ID 0x%08x: size mismatch.\n", mc_hdr->patch_id); + if (!verify_patch(family, fw, leftover, false)) return crnt_size; - } patch = kzalloc(sizeof(*patch), GFP_KERNEL); if (!patch) { pr_err("Patch allocation failure.\n"); - return -EINVAL; + return 0; } patch->data = kmemdup(fw + SECTION_HDR_SIZE, patch_size, GFP_KERNEL); if (!patch->data) { pr_err("Patch data allocation failure.\n"); kfree(patch); - return -EINVAL; + return 0; } INIT_LIST_HEAD(&patch->plist); @@ -793,26 +787,27 @@ static enum ucode_state __load_microcode_amd(u8 family, const u8 *data, enum ucode_state ret = UCODE_ERROR; unsigned int leftover; u8 *fw = (u8 *)data; - int crnt_size = 0; - int offset; + unsigned int offset; - offset = install_equiv_cpu_table(data); - if (offset < 0) { + offset = install_equiv_cpu_table(data, size); + if (!offset) { pr_err("failed to create equivalent cpu table\n"); return ret; } - fw += offset; - leftover = size - offset; - if (*(u32 *)fw != UCODE_UCODE_TYPE) { - pr_err("invalid type field in container file section header\n"); - free_equiv_cpu_table(); - return ret; - } + /* + * Skip also the container header, since install_equiv_cpu_table() + * returns just the raw equivalence table size without the header. + */ + fw += CONTAINER_HDR_SZ; + fw += offset; + leftover = size - CONTAINER_HDR_SZ - offset; while (leftover) { + unsigned int crnt_size; + crnt_size = verify_and_add_patch(family, fw, leftover); - if (crnt_size < 0) + if (!crnt_size) return ret; fw += crnt_size; @@ -895,10 +890,8 @@ static enum ucode_state request_microcode_amd(int cpu, struct device *device, } ret = UCODE_ERROR; - if (*(u32 *)fw->data != UCODE_MAGIC) { - pr_err("invalid magic value (0x%08x)\n", *(u32 *)fw->data); + if (!verify_container(fw->data, fw->size, false)) goto fw_release; - } ret = load_microcode_amd(bsp, c->x86, fw->data, fw->size);