]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Universal/Disk/PartitionDxe/Gpt.c
MdeModulePkg/PartitionDxe: Ensure blocksize holds MBR (CVE-2018-12180)
[mirror_edk2.git] / MdeModulePkg / Universal / Disk / PartitionDxe / Gpt.c
index 6caec01a6cef0043eacee5a478799378de44b791..d679cc208be435ccbfeef1cc149311a2c4d0df7a 100644 (file)
@@ -2,7 +2,19 @@
   Decode a hard disk partitioned with the GPT scheme in the UEFI 2.0\r
   specification.\r
 \r
-Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>\r
+  Caution: This file requires additional review when modified.\r
+  This driver will have external input - disk partition.\r
+  This external input must be validated carefully to avoid security issue like\r
+  buffer overflow, integer overflow.\r
+\r
+  PartitionInstallGptChildHandles() routine will read disk partition content and\r
+  do basic validation before PartitionInstallChildHandle().\r
+\r
+  PartitionValidGptTable(), PartitionCheckGptEntry() routine will accept disk\r
+  partition content and validate the GPT table and GPT entry.\r
+\r
+Copyright (c) 2018 Qualcomm Datacenter Technologies, Inc.\r
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>\r
 This program and the accompanying materials\r
 are licensed and made available under the terms and conditions of the BSD License\r
 which accompanies this distribution.  The full text of the license may be found at\r
@@ -19,6 +31,10 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 /**\r
   Install child handles if the Handle supports GPT partition structure.\r
 \r
+  Caution: This function may receive untrusted input.\r
+  The GPT partition table header is external input, so this routine\r
+  will do basic validation for GPT partition table header before return.\r
+\r
   @param[in]  BlockIo     Parent BlockIo interface.\r
   @param[in]  DiskIo      Disk Io protocol.\r
   @param[in]  Lba         The starting Lba of the Partition Table\r
@@ -77,12 +93,15 @@ PartitionRestoreGptTable (
 \r
 \r
 /**\r
-  Restore Partition Table to its alternate place.\r
-  (Primary -> Backup or Backup -> Primary)\r
+  This routine will check GPT partition entry and return entry status.\r
+\r
+  Caution: This function may receive untrusted input.\r
+  The GPT partition entry is external input, so this routine\r
+  will do basic validation for GPT partition entry and report status.\r
 \r
   @param[in]    PartHeader    Partition table header structure\r
   @param[in]    PartEntry     The partition entry array\r
-  @param[out]   PEntryStatus  the partition entry status array \r
+  @param[out]   PEntryStatus  the partition entry status array\r
                               recording the status of each partition\r
 \r
 **/\r
@@ -158,9 +177,15 @@ PartitionSetCrc (
 /**\r
   Install child handles if the Handle supports GPT partition structure.\r
 \r
+  Caution: This function may receive untrusted input.\r
+  The GPT partition table is external input, so this routine\r
+  will do basic validation for GPT partition table before install\r
+  child handle for each GPT partition.\r
+\r
   @param[in]  This       Calling context.\r
   @param[in]  Handle     Parent Handle.\r
   @param[in]  DiskIo     Parent DiskIo interface.\r
+  @param[in]  DiskIo2    Parent DiskIo2 interface.\r
   @param[in]  BlockIo    Parent BlockIo interface.\r
   @param[in]  BlockIo2   Parent BlockIo2 interface.\r
   @param[in]  DevicePath Parent Device Path.\r
@@ -175,24 +200,26 @@ PartitionInstallGptChildHandles (
   IN  EFI_DRIVER_BINDING_PROTOCOL  *This,\r
   IN  EFI_HANDLE                   Handle,\r
   IN  EFI_DISK_IO_PROTOCOL         *DiskIo,\r
+  IN  EFI_DISK_IO2_PROTOCOL        *DiskIo2,\r
   IN  EFI_BLOCK_IO_PROTOCOL        *BlockIo,\r
   IN  EFI_BLOCK_IO2_PROTOCOL       *BlockIo2,\r
   IN  EFI_DEVICE_PATH_PROTOCOL     *DevicePath\r
   )\r
 {\r
-  EFI_STATUS                  Status;\r
-  UINT32                      BlockSize;\r
-  EFI_LBA                     LastBlock;\r
-  MASTER_BOOT_RECORD          *ProtectiveMbr;\r
-  EFI_PARTITION_TABLE_HEADER  *PrimaryHeader;\r
-  EFI_PARTITION_TABLE_HEADER  *BackupHeader;\r
-  EFI_PARTITION_ENTRY         *PartEntry;\r
-  EFI_PARTITION_ENTRY         *Entry;\r
-  EFI_PARTITION_ENTRY_STATUS  *PEntryStatus;\r
-  UINTN                       Index;\r
-  EFI_STATUS                  GptValidStatus;\r
-  HARDDRIVE_DEVICE_PATH       HdDev;\r
-  UINT32                      MediaId;\r
+  EFI_STATUS                   Status;\r
+  UINT32                       BlockSize;\r
+  EFI_LBA                      LastBlock;\r
+  MASTER_BOOT_RECORD           *ProtectiveMbr;\r
+  EFI_PARTITION_TABLE_HEADER   *PrimaryHeader;\r
+  EFI_PARTITION_TABLE_HEADER   *BackupHeader;\r
+  EFI_PARTITION_ENTRY          *PartEntry;\r
+  EFI_PARTITION_ENTRY          *Entry;\r
+  EFI_PARTITION_ENTRY_STATUS   *PEntryStatus;\r
+  UINTN                        Index;\r
+  EFI_STATUS                   GptValidStatus;\r
+  HARDDRIVE_DEVICE_PATH        HdDev;\r
+  UINT32                       MediaId;\r
+  EFI_PARTITION_INFO_PROTOCOL  PartitionInfo;\r
 \r
   ProtectiveMbr = NULL;\r
   PrimaryHeader = NULL;\r
@@ -209,6 +236,13 @@ PartitionInstallGptChildHandles (
 \r
   GptValidStatus = EFI_NOT_FOUND;\r
 \r
+  //\r
+  // Ensure the block size can hold the MBR\r
+  //\r
+  if (BlockSize < sizeof (MASTER_BOOT_RECORD)) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
   //\r
   // Allocate a buffer for the Protective MBR\r
   //\r
@@ -284,7 +318,7 @@ PartitionInstallGptChildHandles (
     DEBUG ((EFI_D_INFO, " Valid primary and !Valid backup partition table\n"));\r
     DEBUG ((EFI_D_INFO, " Restore backup partition table by the primary\n"));\r
     if (!PartitionRestoreGptTable (BlockIo, DiskIo, PrimaryHeader)) {\r
-      DEBUG ((EFI_D_INFO, " Restore  backup partition table error\n"));\r
+      DEBUG ((EFI_D_INFO, " Restore backup partition table error\n"));\r
     }\r
 \r
     if (PartitionValidGptTable (BlockIo, DiskIo, PrimaryHeader->AlternateLBA, BackupHeader)) {\r
@@ -355,17 +389,25 @@ PartitionInstallGptChildHandles (
     }\r
 \r
     ZeroMem (&HdDev, sizeof (HdDev));\r
-    HdDev.Header.Type     = MEDIA_DEVICE_PATH;\r
-    HdDev.Header.SubType  = MEDIA_HARDDRIVE_DP;\r
+    HdDev.Header.Type      = MEDIA_DEVICE_PATH;\r
+    HdDev.Header.SubType   = MEDIA_HARDDRIVE_DP;\r
     SetDevicePathNodeLength (&HdDev.Header, sizeof (HdDev));\r
 \r
-    HdDev.PartitionNumber = (UINT32) Index + 1;\r
-    HdDev.MBRType         = MBR_TYPE_EFI_PARTITION_TABLE_HEADER;\r
-    HdDev.SignatureType   = SIGNATURE_TYPE_GUID;\r
-    HdDev.PartitionStart  = Entry->StartingLBA;\r
-    HdDev.PartitionSize   = Entry->EndingLBA - Entry->StartingLBA + 1;\r
+    HdDev.PartitionNumber  = (UINT32) Index + 1;\r
+    HdDev.MBRType          = MBR_TYPE_EFI_PARTITION_TABLE_HEADER;\r
+    HdDev.SignatureType    = SIGNATURE_TYPE_GUID;\r
+    HdDev.PartitionStart   = Entry->StartingLBA;\r
+    HdDev.PartitionSize    = Entry->EndingLBA - Entry->StartingLBA + 1;\r
     CopyMem (HdDev.Signature, &Entry->UniquePartitionGUID, sizeof (EFI_GUID));\r
 \r
+    ZeroMem (&PartitionInfo, sizeof (EFI_PARTITION_INFO_PROTOCOL));\r
+    PartitionInfo.Revision = EFI_PARTITION_INFO_PROTOCOL_REVISION;\r
+    PartitionInfo.Type     = PARTITION_TYPE_GPT;\r
+    if (CompareGuid (&Entry->PartitionTypeGUID, &gEfiPartTypeSystemPartGuid)) {\r
+      PartitionInfo.System = 1;\r
+    }\r
+    CopyMem (&PartitionInfo.Info.Gpt, Entry, sizeof (EFI_PARTITION_ENTRY));\r
+\r
     DEBUG ((EFI_D_INFO, " Index : %d\n", (UINT32) Index));\r
     DEBUG ((EFI_D_INFO, " Start LBA : %lx\n", (UINT64) HdDev.PartitionStart));\r
     DEBUG ((EFI_D_INFO, " End LBA : %lx\n", (UINT64) Entry->EndingLBA));\r
@@ -377,14 +419,16 @@ PartitionInstallGptChildHandles (
                This,\r
                Handle,\r
                DiskIo,\r
+               DiskIo2,\r
                BlockIo,\r
                BlockIo2,\r
                DevicePath,\r
                (EFI_DEVICE_PATH_PROTOCOL *) &HdDev,\r
+               &PartitionInfo,\r
                Entry->StartingLBA,\r
                Entry->EndingLBA,\r
                BlockSize,\r
-               CompareGuid(&Entry->PartitionTypeGUID, &gEfiPartTypeSystemPartGuid)\r
+               &Entry->PartitionTypeGUID\r
                );\r
   }\r
 \r
@@ -411,7 +455,11 @@ Done:
 }\r
 \r
 /**\r
-  Install child handles if the Handle supports GPT partition structure.\r
+  This routine will read GPT partition table header and return it.\r
+\r
+  Caution: This function may receive untrusted input.\r
+  The GPT partition table header is external input, so this routine\r
+  will do basic validation for GPT partition table header before return.\r
 \r
   @param[in]  BlockIo     Parent BlockIo interface.\r
   @param[in]  DiskIo      Disk Io protocol.\r
@@ -460,13 +508,22 @@ PartitionValidGptTable (
 \r
   if ((PartHdr->Header.Signature != EFI_PTAB_HEADER_ID) ||\r
       !PartitionCheckCrc (BlockSize, &PartHdr->Header) ||\r
-      PartHdr->MyLBA != Lba\r
+      PartHdr->MyLBA != Lba ||\r
+      (PartHdr->SizeOfPartitionEntry < sizeof (EFI_PARTITION_ENTRY))\r
       ) {\r
     DEBUG ((EFI_D_INFO, "Invalid efi partition table header\n"));\r
     FreePool (PartHdr);\r
     return FALSE;\r
   }\r
 \r
+  //\r
+  // Ensure the NumberOfPartitionEntries * SizeOfPartitionEntry doesn't overflow.\r
+  //\r
+  if (PartHdr->NumberOfPartitionEntries > DivU64x32 (MAX_UINTN, PartHdr->SizeOfPartitionEntry)) {\r
+    FreePool (PartHdr);\r
+    return FALSE;\r
+  }\r
+\r
   CopyMem (PartHeader, PartHdr, sizeof (EFI_PARTITION_TABLE_HEADER));\r
   if (!PartitionCheckGptEntryArrayCRC (BlockIo, DiskIo, PartHeader)) {\r
     FreePool (PartHdr);\r
@@ -640,12 +697,15 @@ Done:
 }\r
 \r
 /**\r
-  Restore Partition Table to its alternate place.\r
-  (Primary -> Backup or Backup -> Primary)\r
+  This routine will check GPT partition entry and return entry status.\r
+\r
+  Caution: This function may receive untrusted input.\r
+  The GPT partition entry is external input, so this routine\r
+  will do basic validation for GPT partition entry and report status.\r
 \r
   @param[in]    PartHeader    Partition table header structure\r
   @param[in]    PartEntry     The partition entry array\r
-  @param[out]   PEntryStatus  the partition entry status array \r
+  @param[out]   PEntryStatus  the partition entry status array\r
                               recording the status of each partition\r
 \r
 **/\r
@@ -683,7 +743,7 @@ PartitionCheckGptEntry (
 \r
     if ((Entry->Attributes & BIT1) != 0) {\r
       //\r
-      // If Bit 1 is set, this indicate that this is an OS specific GUID partition. \r
+      // If Bit 1 is set, this indicate that this is an OS specific GUID partition.\r
       //\r
       PEntryStatus[Index1].OsSpecific = TRUE;\r
     }\r