public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: Chen A Chen <chen.a.chen@intel.com>
To: edk2-devel@lists.01.org
Cc: Chen A Chen <chen.a.chen@intel.com>, Ray Ni <ray.ni@intel.com>,
	Eric Dong <eric.dong@intel.com>
Subject: [PATCH 2/2] UefiCpuPkg/Microcode: Add verification logic before parsing payload
Date: Thu, 28 Feb 2019 14:02:52 +0800	[thread overview]
Message-ID: <20190228060252.23944-3-chen.a.chen@intel.com> (raw)
In-Reply-To: <20190228060252.23944-1-chen.a.chen@intel.com>

REF: https://bugzilla.tianocore.org/show_bug.cgi?id=1020

The function MicrocodeDetect may receive untrusted input. Add verification
logic to check Microcode Payload Header.

Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Chen A Chen <chen.a.chen@intel.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Eric Dong <eric.dong@intel.com>
---
 UefiCpuPkg/Library/MpInitLib/Microcode.c | 190 +++++++++++++++++++++----------
 1 file changed, 127 insertions(+), 63 deletions(-)

diff --git a/UefiCpuPkg/Library/MpInitLib/Microcode.c b/UefiCpuPkg/Library/MpInitLib/Microcode.c
index 5f9ae22794..1d5e964791 100644
--- a/UefiCpuPkg/Library/MpInitLib/Microcode.c
+++ b/UefiCpuPkg/Library/MpInitLib/Microcode.c
@@ -32,6 +32,69 @@ GetCurrentMicrocodeSignature (
   return BiosSignIdMsr.Bits.MicrocodeUpdateSignature;
 }
 
+/**
+  Verify Microcode.
+
+  @param[in]  MicrocodeHeader       Point to the Microcode payload buffer.
+
+  @retval     TRUE                  Valid payload
+  @retval     FALSE                 Invalid payload
+**/
+BOOLEAN
+VerifyMicrocodeHeader (
+  IN CPU_MICROCODE_HEADER *MicrocodeHeader
+  )
+{
+  UINTN                   TotalSize;
+  UINTN                   DataSize;
+
+  if (MicrocodeHeader == NULL) {
+    return FALSE;
+  }
+
+  ///
+  /// Verify Version
+  ///
+  if (MicrocodeHeader->HeaderVersion != 0x1) {
+    return FALSE;
+  }
+  if (MicrocodeHeader->LoaderRevision != 0x1) {
+    return FALSE;
+  }
+
+  ///
+  /// Verify TotalSize
+  ///
+  if (MicrocodeHeader->DataSize == 0) {
+    TotalSize = 2048;
+  } else {
+    TotalSize = MicrocodeHeader->TotalSize;
+  }
+  if (TotalSize <= sizeof (CPU_MICROCODE_HEADER)) {
+    return FALSE;
+  }
+  if ((TotalSize & (SIZE_1KB - 1)) != 0) {
+    return FALSE;
+  }
+
+  ///
+  /// Verify DataSize
+  ///
+  if (MicrocodeHeader->DataSize == 0) {
+    DataSize = 2048 - sizeof (CPU_MICROCODE_HEADER);
+  } else {
+    DataSize = MicrocodeHeader->DataSize;
+  }
+  if (DataSize > TotalSize - sizeof (CPU_MICROCODE_HEADER)) {
+    return FALSE;
+  }
+  if ((DataSize & 0x3) != 0) {
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
 /**
   Detect whether specified processor can find matching microcode patch and load it.
 
@@ -166,6 +229,18 @@ MicrocodeDetect (
     //
     CorrectMicrocode = FALSE;
 
+    if (!VerifyMicrocodeHeader (MicrocodeEntryPoint)) {
+      //
+      // It is the padding data between the microcode patches for microcode patches alignment.
+      // Because the microcode patch is the multiple of 1-KByte, the padding data should not
+      // exist if the microcode patch alignment value is not larger than 1-KByte. So, the microcode
+      // alignment value should be larger than 1-KByte. We could skip SIZE_1KB padding data to
+      // find the next possible microcode patch header.
+      //
+      MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + SIZE_1KB);
+      continue;
+    }
+
     //
     // Save an in-complete CheckSum32 from CheckSum Part1 for common parts.
     //
@@ -184,90 +259,79 @@ MicrocodeDetect (
     InCompleteCheckSum32 -= MicrocodeEntryPoint->ProcessorFlags;
     InCompleteCheckSum32 -= MicrocodeEntryPoint->Checksum;
 
-    if (MicrocodeEntryPoint->HeaderVersion == 0x1) {
+    //
+    // It is the microcode header. It is not the padding data between microcode patches
+    // because the padding data should not include 0x00000001 and it should be the repeated
+    // byte format (like 0xXYXYXYXY....).
+    //
+    if (MicrocodeEntryPoint->ProcessorSignature.Uint32 == Eax.Uint32 &&
+        MicrocodeEntryPoint->UpdateRevision > LatestRevision &&
+        (MicrocodeEntryPoint->ProcessorFlags & (1 << PlatformId))
+        ) {
       //
-      // It is the microcode header. It is not the padding data between microcode patches
-      // because the padding data should not include 0x00000001 and it should be the repeated
-      // byte format (like 0xXYXYXYXY....).
+      // Calculate CheckSum Part1.
       //
-      if (MicrocodeEntryPoint->ProcessorSignature.Uint32 == Eax.Uint32 &&
-          MicrocodeEntryPoint->UpdateRevision > LatestRevision &&
-          (MicrocodeEntryPoint->ProcessorFlags & (1 << PlatformId))
-          ) {
+      CheckSum32 = InCompleteCheckSum32;
+      CheckSum32 += MicrocodeEntryPoint->ProcessorSignature.Uint32;
+      CheckSum32 += MicrocodeEntryPoint->ProcessorFlags;
+      CheckSum32 += MicrocodeEntryPoint->Checksum;
+      if (CheckSum32 == 0) {
+        CorrectMicrocode = TRUE;
+        ProcessorFlags = MicrocodeEntryPoint->ProcessorFlags;
+      }
+    } else if ((MicrocodeEntryPoint->DataSize != 0) &&
+               (MicrocodeEntryPoint->UpdateRevision > LatestRevision)) {
+      ExtendedTableLength = MicrocodeEntryPoint->TotalSize - (MicrocodeEntryPoint->DataSize +
+                              sizeof (CPU_MICROCODE_HEADER));
+      if (ExtendedTableLength != 0) {
         //
-        // Calculate CheckSum Part1.
+        // Extended Table exist, check if the CPU in support list
         //
-        CheckSum32 = InCompleteCheckSum32;
-        CheckSum32 += MicrocodeEntryPoint->ProcessorSignature.Uint32;
-        CheckSum32 += MicrocodeEntryPoint->ProcessorFlags;
-        CheckSum32 += MicrocodeEntryPoint->Checksum;
-        if (CheckSum32 == 0) {
-          CorrectMicrocode = TRUE;
-          ProcessorFlags = MicrocodeEntryPoint->ProcessorFlags;
-        }
-      } else if ((MicrocodeEntryPoint->DataSize != 0) &&
-                 (MicrocodeEntryPoint->UpdateRevision > LatestRevision)) {
-        ExtendedTableLength = MicrocodeEntryPoint->TotalSize - (MicrocodeEntryPoint->DataSize +
-                                sizeof (CPU_MICROCODE_HEADER));
-        if (ExtendedTableLength != 0) {
-          //
-          // Extended Table exist, check if the CPU in support list
-          //
-          ExtendedTableHeader = (CPU_MICROCODE_EXTENDED_TABLE_HEADER *) ((UINT8 *) (MicrocodeEntryPoint)
-                                  + MicrocodeEntryPoint->DataSize + sizeof (CPU_MICROCODE_HEADER));
+        ExtendedTableHeader = (CPU_MICROCODE_EXTENDED_TABLE_HEADER *) ((UINT8 *) (MicrocodeEntryPoint)
+                                + MicrocodeEntryPoint->DataSize + sizeof (CPU_MICROCODE_HEADER));
+        //
+        // Calculate Extended Checksum
+        //
+        if ((ExtendedTableLength % 4) == 0) {
           //
-          // Calculate Extended Checksum
+          // Calculate CheckSum Part2.
           //
-          if ((ExtendedTableLength % 4) == 0) {
+          CheckSum32 = CalculateSum32 ((UINT32 *) ExtendedTableHeader, ExtendedTableLength);
+          if (CheckSum32 == 0) {
             //
-            // Calculate CheckSum Part2.
+            // Checksum correct
             //
-            CheckSum32 = CalculateSum32 ((UINT32 *) ExtendedTableHeader, ExtendedTableLength);
-            if (CheckSum32 == 0) {
+            ExtendedTableCount = ExtendedTableHeader->ExtendedSignatureCount;
+            ExtendedTable      = (CPU_MICROCODE_EXTENDED_TABLE *) (ExtendedTableHeader + 1);
+            for (Index = 0; Index < ExtendedTableCount; Index ++) {
               //
-              // Checksum correct
+              // Calculate CheckSum Part3.
               //
-              ExtendedTableCount = ExtendedTableHeader->ExtendedSignatureCount;
-              ExtendedTable      = (CPU_MICROCODE_EXTENDED_TABLE *) (ExtendedTableHeader + 1);
-              for (Index = 0; Index < ExtendedTableCount; Index ++) {
+              CheckSum32 = InCompleteCheckSum32;
+              CheckSum32 += ExtendedTable->ProcessorSignature.Uint32;
+              CheckSum32 += ExtendedTable->ProcessorFlag;
+              CheckSum32 += ExtendedTable->Checksum;
+              if (CheckSum32 == 0) {
                 //
-                // Calculate CheckSum Part3.
+                // Verify Header
                 //
-                CheckSum32 = InCompleteCheckSum32;
-                CheckSum32 += ExtendedTable->ProcessorSignature.Uint32;
-                CheckSum32 += ExtendedTable->ProcessorFlag;
-                CheckSum32 += ExtendedTable->Checksum;
-                if (CheckSum32 == 0) {
+                if ((ExtendedTable->ProcessorSignature.Uint32 == Eax.Uint32) &&
+                    (ExtendedTable->ProcessorFlag & (1 << PlatformId)) ) {
                   //
-                  // Verify Header
+                  // Find one
                   //
-                  if ((ExtendedTable->ProcessorSignature.Uint32 == Eax.Uint32) &&
-                      (ExtendedTable->ProcessorFlag & (1 << PlatformId)) ) {
-                    //
-                    // Find one
-                    //
-                    CorrectMicrocode = TRUE;
-                    ProcessorFlags = ExtendedTable->ProcessorFlag;
-                    break;
-                  }
+                  CorrectMicrocode = TRUE;
+                  ProcessorFlags = ExtendedTable->ProcessorFlag;
+                  break;
                 }
-                ExtendedTable ++;
               }
+              ExtendedTable ++;
             }
           }
         }
       }
-    } else {
-      //
-      // It is the padding data between the microcode patches for microcode patches alignment.
-      // Because the microcode patch is the multiple of 1-KByte, the padding data should not
-      // exist if the microcode patch alignment value is not larger than 1-KByte. So, the microcode
-      // alignment value should be larger than 1-KByte. We could skip SIZE_1KB padding data to
-      // find the next possible microcode patch header.
-      //
-      MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + SIZE_1KB);
-      continue;
     }
+
     //
     // Get the next patch.
     //
-- 
2.16.2.windows.1



  parent reply	other threads:[~2019-02-28  6:03 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-02-28  6:02 [PATCH 0/2] Fix Microcode failure issue Chen A Chen
2019-02-28  6:02 ` [PATCH 1/2] UefiCpuPkg/Microcode: Fix InComplete CheckSum32 issue Chen A Chen
2019-02-28  6:14   ` Ni, Ray
2019-02-28  6:02 ` Chen A Chen [this message]
2019-02-28  6:54   ` [PATCH 2/2] UefiCpuPkg/Microcode: Add verification logic before parsing payload Ni, Ray

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-list 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=20190228060252.23944-3-chen.a.chen@intel.com \
    --to=devel@edk2.groups.io \
    /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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox