]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Universal/Disk/PartitionDxe/Gpt.c
MdeModulePkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / MdeModulePkg / Universal / Disk / PartitionDxe / Gpt.c
index 682e8b41b5a7e93679ca0c0b8202ed29219a5627..aefb2d6ecb3f74b12957c511f8d0be6ee2e84c07 100644 (file)
@@ -2,14 +2,20 @@
   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
-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
-http://opensource.org/licenses/bsd-license.php\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
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\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
+SPDX-License-Identifier: BSD-2-Clause-Patent\r
 \r
 **/\r
 \r
@@ -19,6 +25,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 +87,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 +171,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,23 +194,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_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
@@ -208,6 +230,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
@@ -283,7 +312,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
@@ -297,7 +326,7 @@ PartitionInstallGptChildHandles (
   //\r
   // Read the EFI Partition Entries\r
   //\r
-  PartEntry = AllocatePool (PrimaryHeader->NumberOfPartitionEntries * sizeof (EFI_PARTITION_ENTRY));\r
+  PartEntry = AllocatePool (PrimaryHeader->NumberOfPartitionEntries * PrimaryHeader->SizeOfPartitionEntry);\r
   if (PartEntry == NULL) {\r
     DEBUG ((EFI_D_ERROR, "Allocate pool error\n"));\r
     goto Done;\r
@@ -340,7 +369,8 @@ PartitionInstallGptChildHandles (
   // Create child device handles\r
   //\r
   for (Index = 0; Index < PrimaryHeader->NumberOfPartitionEntries; Index++) {\r
-    if (CompareGuid (&PartEntry[Index].PartitionTypeGUID, &gEfiPartTypeUnusedGuid) ||\r
+    Entry = (EFI_PARTITION_ENTRY *) ((UINT8 *) PartEntry + Index * PrimaryHeader->SizeOfPartitionEntry);\r
+    if (CompareGuid (&Entry->PartitionTypeGUID, &gEfiPartTypeUnusedGuid) ||\r
         PEntryStatus[Index].OutOfRange ||\r
         PEntryStatus[Index].Overlap ||\r
         PEntryStatus[Index].OsSpecific\r
@@ -353,36 +383,46 @@ 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  = PartEntry[Index].StartingLBA;\r
-    HdDev.PartitionSize   = PartEntry[Index].EndingLBA - PartEntry[Index].StartingLBA + 1;\r
-    CopyMem (HdDev.Signature, &PartEntry[Index].UniquePartitionGUID, sizeof (EFI_GUID));\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) PartEntry[Index].EndingLBA));\r
+    DEBUG ((EFI_D_INFO, " End LBA : %lx\n", (UINT64) Entry->EndingLBA));\r
     DEBUG ((EFI_D_INFO, " Partition size: %lx\n", (UINT64) HdDev.PartitionSize));\r
-    DEBUG ((EFI_D_INFO, " Start : %lx", MultU64x32 (PartEntry[Index].StartingLBA, BlockSize)));\r
-    DEBUG ((EFI_D_INFO, " End : %lx\n", MultU64x32 (PartEntry[Index].EndingLBA, BlockSize)));\r
+    DEBUG ((EFI_D_INFO, " Start : %lx", MultU64x32 (Entry->StartingLBA, BlockSize)));\r
+    DEBUG ((EFI_D_INFO, " End : %lx\n", MultU64x32 (Entry->EndingLBA, BlockSize)));\r
 \r
     Status = PartitionInstallChildHandle (\r
                This,\r
                Handle,\r
                DiskIo,\r
+               DiskIo2,\r
                BlockIo,\r
                BlockIo2,\r
                DevicePath,\r
                (EFI_DEVICE_PATH_PROTOCOL *) &HdDev,\r
-               PartEntry[Index].StartingLBA,\r
-               PartEntry[Index].EndingLBA,\r
+               &PartitionInfo,\r
+               Entry->StartingLBA,\r
+               Entry->EndingLBA,\r
                BlockSize,\r
-               CompareGuid(&PartEntry[Index].PartitionTypeGUID, &gEfiPartTypeSystemPartGuid)\r
+               &Entry->PartitionTypeGUID\r
                );\r
   }\r
 \r
@@ -409,7 +449,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
@@ -458,13 +502,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
@@ -481,7 +534,6 @@ PartitionValidGptTable (
   for Partition entry array.\r
 \r
   @param[in]  BlockIo     Parent BlockIo interface\r
-  @param[in]  BlockIo2    Parent BlockIo2 interface.\r
   @param[in]  DiskIo      Disk Io Protocol.\r
   @param[in]  PartHeader  Partition table header structure\r
 \r
@@ -638,14 +690,16 @@ Done:
   return TRUE;\r
 }\r
 \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
@@ -656,20 +710,21 @@ PartitionCheckGptEntry (
   OUT EFI_PARTITION_ENTRY_STATUS  *PEntryStatus\r
   )\r
 {\r
-  EFI_LBA StartingLBA;\r
-  EFI_LBA EndingLBA;\r
-  UINTN   Index1;\r
-  UINTN   Index2;\r
-  UINT64  Attributes;\r
+  EFI_LBA              StartingLBA;\r
+  EFI_LBA              EndingLBA;\r
+  EFI_PARTITION_ENTRY  *Entry;\r
+  UINTN                Index1;\r
+  UINTN                Index2;\r
 \r
   DEBUG ((EFI_D_INFO, " start check partition entries\n"));\r
   for (Index1 = 0; Index1 < PartHeader->NumberOfPartitionEntries; Index1++) {\r
-    if (CompareGuid (&PartEntry[Index1].PartitionTypeGUID, &gEfiPartTypeUnusedGuid)) {\r
+    Entry = (EFI_PARTITION_ENTRY *) ((UINT8 *) PartEntry + Index1 * PartHeader->SizeOfPartitionEntry);\r
+    if (CompareGuid (&Entry->PartitionTypeGUID, &gEfiPartTypeUnusedGuid)) {\r
       continue;\r
     }\r
 \r
-    StartingLBA = PartEntry[Index1].StartingLBA;\r
-    EndingLBA   = PartEntry[Index1].EndingLBA;\r
+    StartingLBA = Entry->StartingLBA;\r
+    EndingLBA   = Entry->EndingLBA;\r
     if (StartingLBA > EndingLBA ||\r
         StartingLBA < PartHeader->FirstUsableLBA ||\r
         StartingLBA > PartHeader->LastUsableLBA ||\r
@@ -680,30 +735,28 @@ PartitionCheckGptEntry (
       continue;\r
     }\r
 \r
-    for (Index2 = Index1 + 1; Index2 < PartHeader->NumberOfPartitionEntries; Index2++) {\r
+    if ((Entry->Attributes & BIT1) != 0) {\r
+      //\r
+      // If Bit 1 is set, this indicate that this is an OS specific GUID partition.\r
+      //\r
+      PEntryStatus[Index1].OsSpecific = TRUE;\r
+    }\r
 \r
-      if (CompareGuid (&PartEntry[Index2].PartitionTypeGUID, &gEfiPartTypeUnusedGuid)) {\r
+    for (Index2 = Index1 + 1; Index2 < PartHeader->NumberOfPartitionEntries; Index2++) {\r
+      Entry = (EFI_PARTITION_ENTRY *) ((UINT8 *) PartEntry + Index2 * PartHeader->SizeOfPartitionEntry);\r
+      if (CompareGuid (&Entry->PartitionTypeGUID, &gEfiPartTypeUnusedGuid)) {\r
         continue;\r
       }\r
 \r
-      if (PartEntry[Index2].EndingLBA >= StartingLBA && PartEntry[Index2].StartingLBA <= EndingLBA) {\r
+      if (Entry->EndingLBA >= StartingLBA && Entry->StartingLBA <= EndingLBA) {\r
         //\r
         // This region overlaps with the Index1'th region\r
         //\r
         PEntryStatus[Index1].Overlap  = TRUE;\r
         PEntryStatus[Index2].Overlap  = TRUE;\r
         continue;\r
-\r
       }\r
     }\r
-\r
-    Attributes = PartEntry[Index1].Attributes;\r
-    if ((Attributes & BIT1) != 0) {\r
-      //\r
-      // If Bit 1 is set, this indicate that this is an OS specific GUID partition. \r
-      //\r
-      PEntryStatus[Index1].OsSpecific = TRUE;\r
-    }\r
   }\r
 \r
   DEBUG ((EFI_D_INFO, " End check partition entries\n"));\r