All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Maciej S. Szmigiero" <mail@maciej.szmigiero.name>
To: Borislav Petkov <bp@alien8.de>
Cc: Thomas Gleixner <tglx@linutronix.de>,
	Ingo Molnar <mingo@redhat.com>, "H. Peter Anvin" <hpa@zytor.com>,
	x86@kernel.org, linux-kernel@vger.kernel.org
Subject: [PATCH v7 2/9] x86/microcode/AMD: Add microcode container data checking functions
Date: Tue, 19 Jun 2018 20:47:32 +0200	[thread overview]
Message-ID: <3014e96c82cd90761b4601bd2cfe59c4119e46a7.1529424596.git.mail@maciej.szmigiero.name> (raw)
In-Reply-To: <cover.1529424596.git.mail@maciej.szmigiero.name>

Add verify_container(), verify_equivalence_table(), verify_patch_section()
and verify_patch() functions to the AMD microcode update driver.

These functions check whether a passed buffer contains the relevant
structure, whether it isn't truncated and (for actual microcode patches)
whether the size of a patch is not too large for a particular CPU family.
By adding these checks as separate functions the actual microcode loading
code won't get interspersed with a lot of checks and so will be more
readable.

Signed-off-by: Maciej S. Szmigiero <mail@maciej.szmigiero.name>
---
 arch/x86/kernel/cpu/microcode/amd.c | 180 +++++++++++++++++++++++++++-
 1 file changed, 177 insertions(+), 3 deletions(-)

diff --git a/arch/x86/kernel/cpu/microcode/amd.c b/arch/x86/kernel/cpu/microcode/amd.c
index dc8ea9a9d962..120778771909 100644
--- a/arch/x86/kernel/cpu/microcode/amd.c
+++ b/arch/x86/kernel/cpu/microcode/amd.c
@@ -73,6 +73,182 @@ static u16 find_equiv_id(struct equiv_cpu_entry *equiv_table, u32 sig)
 	return 0;
 }
 
+/*
+ * Check whether there is a valid microcode container file at the beginning
+ * of a passed buffer @buf of size @buf_size.
+ * If @early is set do not print errors so this function is usable by the
+ * early microcode loader.
+ */
+static bool verify_container(const u8 *buf, size_t buf_size, bool early)
+{
+	u32 cont_magic;
+
+	if (buf_size <= CONTAINER_HDR_SZ) {
+		if (!early)
+			pr_err("Truncated microcode container header.\n");
+
+		return false;
+	}
+
+	cont_magic = *(const u32 *)buf;
+	if (cont_magic != UCODE_MAGIC) {
+		if (!early)
+			pr_err("Invalid magic value (0x%08x).\n", cont_magic);
+
+		return false;
+	}
+
+	return true;
+}
+
+/*
+ * Check whether there is a valid, non-truncated CPU equivalence table
+ * at the beginning of a passed buffer @buf of size @buf_size.
+ * If @early is set do not print errors so this function is usable by the
+ * early microcode loader.
+ */
+static bool verify_equivalence_table(const u8 *buf, size_t buf_size, bool early)
+{
+	const u32 *hdr = (const u32 *)buf;
+	u32 cont_type, equiv_tbl_len;
+
+	if (!verify_container(buf, buf_size, early))
+		return false;
+
+	cont_type = hdr[1];
+	if (cont_type != UCODE_EQUIV_CPU_TABLE_TYPE) {
+		if (!early)
+			pr_err("Wrong microcode container equivalence table type: %u.\n",
+			       cont_type);
+
+		return false;
+	}
+
+	equiv_tbl_len = hdr[2];
+	if (equiv_tbl_len < sizeof(struct equiv_cpu_entry) ||
+	    buf_size - CONTAINER_HDR_SZ < equiv_tbl_len) {
+		if (!early)
+			pr_err("Truncated equivalence table.\n");
+
+		return false;
+	}
+
+	return true;
+}
+
+/*
+ * Check whether there is a valid, non-truncated microcode patch section
+ * at the beginning of a passed buffer @buf of size @buf_size.
+ * If @early is set do not print errors so this function is usable by the
+ * early microcode loader.
+ */
+static bool verify_patch_section(const u8 *buf, size_t buf_size, bool early)
+{
+	const u32 *hdr;
+	u32 patch_type, patch_size;
+
+	if (buf_size < SECTION_HDR_SIZE) {
+		if (!early)
+			pr_err("Truncated patch section.\n");
+
+		return false;
+	}
+
+	hdr = (const u32 *)buf;
+	patch_type = hdr[0];
+	patch_size = hdr[1];
+
+	if (patch_type != UCODE_UCODE_TYPE) {
+		if (!early)
+			pr_err("Invalid type field (%u) in container file section header.\n",
+				patch_type);
+
+		return false;
+	}
+
+	if (patch_size < sizeof(struct microcode_header_amd)) {
+		if (!early)
+			pr_err("Patch of size %u too short.\n", patch_size);
+
+		return false;
+	}
+
+	return true;
+}
+
+static unsigned int verify_patch_size(u8 family, u32 patch_size,
+				      unsigned int size);
+
+/*
+ * Check whether there is a valid, non-truncated microcode patch of the
+ * right size for a particular family @family at the beginning of a passed
+ * buffer @buf, buffer that is of size @buf_size.
+ * Will return the length of current patch data in @crnt_size (even on
+ * failure), so the caller knows how many bytes it should skip.
+ * If @early is set do not print errors so this function is usable by the
+ * early microcode loader.
+ */
+static bool verify_patch(u8 family, const u8 *buf, size_t buf_size,
+			 unsigned int *crnt_size, bool early)
+{
+	const u32 *hdr;
+	u32 patch_size;
+	const struct microcode_header_amd *mc_hdr;
+	u8 patch_fam;
+
+	if (!verify_patch_section(buf, buf_size, early)) {
+		*crnt_size = min_t(unsigned int, 1, buf_size);
+		return false;
+	}
+
+	hdr = (const u32 *)buf;
+	patch_size = hdr[1];
+
+	if (buf_size - SECTION_HDR_SIZE < patch_size) {
+		if (!early)
+			pr_err("Patch of size %u truncated.\n", patch_size);
+
+		*crnt_size = buf_size;
+		return false;
+	}
+
+	/*
+	 * Set a patch length limit of slightly less than U32_MAX to
+	 * prevent overflowing 32-bit variables holding the whole
+	 * patch section size.
+	 */
+	if (patch_size > U32_MAX - SECTION_HDR_SIZE) {
+		if (!early)
+			pr_err("Patch of size %u too large.\n", patch_size);
+
+		*crnt_size = SECTION_HDR_SIZE + PATCH_MAX_SIZE;
+		return false;
+	}
+
+	*crnt_size = SECTION_HDR_SIZE + patch_size;
+
+	mc_hdr = (const struct microcode_header_amd *)(buf + SECTION_HDR_SIZE);
+	patch_fam = 0xf + (mc_hdr->processor_rev_id >> 12);
+
+	/* Is the patch for the proper CPU family? */
+	if (family != patch_fam)
+		return false;
+
+	/*
+	 * 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.
+	 */
+	if (!verify_patch_size(family, patch_size, buf_size - SECTION_HDR_SIZE)) {
+		if (!early)
+			pr_err("Patch of size %u too large.\n", patch_size);
+
+		return false;
+	}
+
+	return true;
+}
+
 /*
  * This scans the ucode blob for the proper container as we can have multiple
  * containers glued together. Returns the equivalence ID from the equivalence
@@ -494,10 +670,8 @@ static unsigned int verify_patch_size(u8 family, u32 patch_size, unsigned int si
 		break;
 	}
 
-	if (patch_size > min_t(u32, size, max_size)) {
-		pr_err("patch size mismatch\n");
+	if (patch_size > min_t(u32, size, max_size))
 		return 0;
-	}
 
 	return patch_size;
 }

  parent reply	other threads:[~2018-06-19 18:48 UTC|newest]

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-06-19 18:47 [PATCH v7 0/9] x86/microcode/AMD: Check microcode file sanity before loading it Maciej S. Szmigiero
2018-06-19 18:47 ` [PATCH v7 1/9] x86/microcode/AMD: Subtract SECTION_HDR_SIZE from file leftover length Maciej S. Szmigiero
2018-11-19 10:12   ` [tip:x86/microcode] " tip-bot for Maciej S. Szmigiero
2018-06-19 18:47 ` Maciej S. Szmigiero [this message]
2018-11-19 10:13   ` [tip:x86/microcode] x86/microcode/AMD: Add microcode container verification tip-bot for Maciej S. Szmigiero
2018-06-19 18:47 ` [PATCH v7 3/9] x86/microcode/AMD: Integrate verify_patch_size() into verify_patch() Maciej S. Szmigiero
2018-06-21  8:36   ` Borislav Petkov
2018-06-22 22:32     ` [PATCH 1/2] " Maciej S. Szmigiero
2018-06-22 22:33     ` [PATCH 2/2] x86/microcode/AMD: Check patch size for all known CPU families Maciej S. Szmigiero
2018-06-25 18:37       ` Borislav Petkov
2018-06-25 22:18         ` Maciej S. Szmigiero
2018-06-19 18:47 ` [PATCH v7 4/9] x86/microcode/AMD: Check microcode container data in the early loader Maciej S. Szmigiero
2018-06-19 18:47 ` [PATCH v7 5/9] x86/microcode/AMD: Split status from data to skip in verify_and_add_patch() Maciej S. Szmigiero
2018-06-19 18:47 ` [PATCH v7 6/9] x86/microcode/AMD: Check microcode container data in the late loader Maciej S. Szmigiero
2018-06-19 18:47 ` [PATCH v7 7/9] x86/microcode/AMD: Add a reminder about PATCH_MAX_SIZE macro Maciej S. Szmigiero
2018-06-19 18:47 ` [PATCH v7 8/9] x86/microcode/AMD: Convert CPU equivalence table variable into a struct Maciej S. Szmigiero
2018-06-19 18:47 ` [PATCH v7 9/9] x86/microcode/AMD: Check the equivalence table size when scanning it Maciej S. Szmigiero

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=3014e96c82cd90761b4601bd2cfe59c4119e46a7.1529424596.git.mail@maciej.szmigiero.name \
    --to=mail@maciej.szmigiero.name \
    --cc=bp@alien8.de \
    --cc=hpa@zytor.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mingo@redhat.com \
    --cc=tglx@linutronix.de \
    --cc=x86@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.