Home | History | Annotate | Download | only in PartitionDxe
      1 /** @file
      2   Decode a hard disk partitioned with the GPT scheme in the UEFI 2.0
      3   specification.
      4 
      5   Caution: This file requires additional review when modified.
      6   This driver will have external input - disk partition.
      7   This external input must be validated carefully to avoid security issue like
      8   buffer overflow, integer overflow.
      9 
     10   PartitionInstallGptChildHandles() routine will read disk partition content and
     11   do basic validation before PartitionInstallChildHandle().
     12 
     13   PartitionValidGptTable(), PartitionCheckGptEntry() routine will accept disk
     14   partition content and validate the GPT table and GPT entry.
     15 
     16 Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>
     17 This program and the accompanying materials
     18 are licensed and made available under the terms and conditions of the BSD License
     19 which accompanies this distribution.  The full text of the license may be found at
     20 http://opensource.org/licenses/bsd-license.php
     21 
     22 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     23 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     24 
     25 **/
     26 
     27 
     28 #include "Partition.h"
     29 
     30 /**
     31   Install child handles if the Handle supports GPT partition structure.
     32 
     33   Caution: This function may receive untrusted input.
     34   The GPT partition table header is external input, so this routine
     35   will do basic validation for GPT partition table header before return.
     36 
     37   @param[in]  BlockIo     Parent BlockIo interface.
     38   @param[in]  DiskIo      Disk Io protocol.
     39   @param[in]  Lba         The starting Lba of the Partition Table
     40   @param[out] PartHeader  Stores the partition table that is read
     41 
     42   @retval TRUE      The partition table is valid
     43   @retval FALSE     The partition table is not valid
     44 
     45 **/
     46 BOOLEAN
     47 PartitionValidGptTable (
     48   IN  EFI_BLOCK_IO_PROTOCOL       *BlockIo,
     49   IN  EFI_DISK_IO_PROTOCOL        *DiskIo,
     50   IN  EFI_LBA                     Lba,
     51   OUT EFI_PARTITION_TABLE_HEADER  *PartHeader
     52   );
     53 
     54 /**
     55   Check if the CRC field in the Partition table header is valid
     56   for Partition entry array.
     57 
     58   @param[in]  BlockIo     Parent BlockIo interface
     59   @param[in]  DiskIo      Disk Io Protocol.
     60   @param[in]  PartHeader  Partition table header structure
     61 
     62   @retval TRUE      the CRC is valid
     63   @retval FALSE     the CRC is invalid
     64 
     65 **/
     66 BOOLEAN
     67 PartitionCheckGptEntryArrayCRC (
     68   IN  EFI_BLOCK_IO_PROTOCOL       *BlockIo,
     69   IN  EFI_DISK_IO_PROTOCOL        *DiskIo,
     70   IN  EFI_PARTITION_TABLE_HEADER  *PartHeader
     71   );
     72 
     73 
     74 /**
     75   Restore Partition Table to its alternate place
     76   (Primary -> Backup or Backup -> Primary).
     77 
     78   @param[in]  BlockIo     Parent BlockIo interface.
     79   @param[in]  DiskIo      Disk Io Protocol.
     80   @param[in]  PartHeader  Partition table header structure.
     81 
     82   @retval TRUE      Restoring succeeds
     83   @retval FALSE     Restoring failed
     84 
     85 **/
     86 BOOLEAN
     87 PartitionRestoreGptTable (
     88   IN  EFI_BLOCK_IO_PROTOCOL       *BlockIo,
     89   IN  EFI_DISK_IO_PROTOCOL        *DiskIo,
     90   IN  EFI_PARTITION_TABLE_HEADER  *PartHeader
     91   );
     92 
     93 
     94 /**
     95   This routine will check GPT partition entry and return entry status.
     96 
     97   Caution: This function may receive untrusted input.
     98   The GPT partition entry is external input, so this routine
     99   will do basic validation for GPT partition entry and report status.
    100 
    101   @param[in]    PartHeader    Partition table header structure
    102   @param[in]    PartEntry     The partition entry array
    103   @param[out]   PEntryStatus  the partition entry status array
    104                               recording the status of each partition
    105 
    106 **/
    107 VOID
    108 PartitionCheckGptEntry (
    109   IN  EFI_PARTITION_TABLE_HEADER  *PartHeader,
    110   IN  EFI_PARTITION_ENTRY         *PartEntry,
    111   OUT EFI_PARTITION_ENTRY_STATUS  *PEntryStatus
    112   );
    113 
    114 
    115 /**
    116   Checks the CRC32 value in the table header.
    117 
    118   @param  MaxSize   Max Size limit
    119   @param  Size      The size of the table
    120   @param  Hdr       Table to check
    121 
    122   @return TRUE    CRC Valid
    123   @return FALSE   CRC Invalid
    124 
    125 **/
    126 BOOLEAN
    127 PartitionCheckCrcAltSize (
    128   IN UINTN                 MaxSize,
    129   IN UINTN                 Size,
    130   IN OUT EFI_TABLE_HEADER  *Hdr
    131   );
    132 
    133 
    134 /**
    135   Checks the CRC32 value in the table header.
    136 
    137   @param  MaxSize   Max Size limit
    138   @param  Hdr       Table to check
    139 
    140   @return TRUE      CRC Valid
    141   @return FALSE     CRC Invalid
    142 
    143 **/
    144 BOOLEAN
    145 PartitionCheckCrc (
    146   IN UINTN                 MaxSize,
    147   IN OUT EFI_TABLE_HEADER  *Hdr
    148   );
    149 
    150 
    151 /**
    152   Updates the CRC32 value in the table header.
    153 
    154   @param  Size   The size of the table
    155   @param  Hdr    Table to update
    156 
    157 **/
    158 VOID
    159 PartitionSetCrcAltSize (
    160   IN UINTN                 Size,
    161   IN OUT EFI_TABLE_HEADER  *Hdr
    162   );
    163 
    164 
    165 /**
    166   Updates the CRC32 value in the table header.
    167 
    168   @param  Hdr    Table to update
    169 
    170 **/
    171 VOID
    172 PartitionSetCrc (
    173   IN OUT EFI_TABLE_HEADER *Hdr
    174   );
    175 
    176 /**
    177   Install child handles if the Handle supports GPT partition structure.
    178 
    179   Caution: This function may receive untrusted input.
    180   The GPT partition table is external input, so this routine
    181   will do basic validation for GPT partition table before install
    182   child handle for each GPT partition.
    183 
    184   @param[in]  This       Calling context.
    185   @param[in]  Handle     Parent Handle.
    186   @param[in]  DiskIo     Parent DiskIo interface.
    187   @param[in]  DiskIo2    Parent DiskIo2 interface.
    188   @param[in]  BlockIo    Parent BlockIo interface.
    189   @param[in]  BlockIo2   Parent BlockIo2 interface.
    190   @param[in]  DevicePath Parent Device Path.
    191 
    192   @retval EFI_SUCCESS           Valid GPT disk.
    193   @retval EFI_MEDIA_CHANGED     Media changed Detected.
    194   @retval other                 Not a valid GPT disk.
    195 
    196 **/
    197 EFI_STATUS
    198 PartitionInstallGptChildHandles (
    199   IN  EFI_DRIVER_BINDING_PROTOCOL  *This,
    200   IN  EFI_HANDLE                   Handle,
    201   IN  EFI_DISK_IO_PROTOCOL         *DiskIo,
    202   IN  EFI_DISK_IO2_PROTOCOL        *DiskIo2,
    203   IN  EFI_BLOCK_IO_PROTOCOL        *BlockIo,
    204   IN  EFI_BLOCK_IO2_PROTOCOL       *BlockIo2,
    205   IN  EFI_DEVICE_PATH_PROTOCOL     *DevicePath
    206   )
    207 {
    208   EFI_STATUS                  Status;
    209   UINT32                      BlockSize;
    210   EFI_LBA                     LastBlock;
    211   MASTER_BOOT_RECORD          *ProtectiveMbr;
    212   EFI_PARTITION_TABLE_HEADER  *PrimaryHeader;
    213   EFI_PARTITION_TABLE_HEADER  *BackupHeader;
    214   EFI_PARTITION_ENTRY         *PartEntry;
    215   EFI_PARTITION_ENTRY         *Entry;
    216   EFI_PARTITION_ENTRY_STATUS  *PEntryStatus;
    217   UINTN                       Index;
    218   EFI_STATUS                  GptValidStatus;
    219   HARDDRIVE_DEVICE_PATH       HdDev;
    220   UINT32                      MediaId;
    221 
    222   ProtectiveMbr = NULL;
    223   PrimaryHeader = NULL;
    224   BackupHeader  = NULL;
    225   PartEntry     = NULL;
    226   PEntryStatus  = NULL;
    227 
    228   BlockSize     = BlockIo->Media->BlockSize;
    229   LastBlock     = BlockIo->Media->LastBlock;
    230   MediaId       = BlockIo->Media->MediaId;
    231 
    232   DEBUG ((EFI_D_INFO, " BlockSize : %d \n", BlockSize));
    233   DEBUG ((EFI_D_INFO, " LastBlock : %lx \n", LastBlock));
    234 
    235   GptValidStatus = EFI_NOT_FOUND;
    236 
    237   //
    238   // Allocate a buffer for the Protective MBR
    239   //
    240   ProtectiveMbr = AllocatePool (BlockSize);
    241   if (ProtectiveMbr == NULL) {
    242     return EFI_NOT_FOUND;
    243   }
    244 
    245   //
    246   // Read the Protective MBR from LBA #0
    247   //
    248   Status = DiskIo->ReadDisk (
    249                      DiskIo,
    250                      MediaId,
    251                      0,
    252                      BlockSize,
    253                      ProtectiveMbr
    254                      );
    255   if (EFI_ERROR (Status)) {
    256     GptValidStatus = Status;
    257     goto Done;
    258   }
    259 
    260   //
    261   // Verify that the Protective MBR is valid
    262   //
    263   for (Index = 0; Index < MAX_MBR_PARTITIONS; Index++) {
    264     if (ProtectiveMbr->Partition[Index].BootIndicator == 0x00 &&
    265         ProtectiveMbr->Partition[Index].OSIndicator == PMBR_GPT_PARTITION &&
    266         UNPACK_UINT32 (ProtectiveMbr->Partition[Index].StartingLBA) == 1
    267         ) {
    268       break;
    269     }
    270   }
    271   if (Index == MAX_MBR_PARTITIONS) {
    272     goto Done;
    273   }
    274 
    275   //
    276   // Allocate the GPT structures
    277   //
    278   PrimaryHeader = AllocateZeroPool (sizeof (EFI_PARTITION_TABLE_HEADER));
    279   if (PrimaryHeader == NULL) {
    280     goto Done;
    281   }
    282 
    283   BackupHeader = AllocateZeroPool (sizeof (EFI_PARTITION_TABLE_HEADER));
    284   if (BackupHeader == NULL) {
    285     goto Done;
    286   }
    287 
    288   //
    289   // Check primary and backup partition tables
    290   //
    291   if (!PartitionValidGptTable (BlockIo, DiskIo, PRIMARY_PART_HEADER_LBA, PrimaryHeader)) {
    292     DEBUG ((EFI_D_INFO, " Not Valid primary partition table\n"));
    293 
    294     if (!PartitionValidGptTable (BlockIo, DiskIo, LastBlock, BackupHeader)) {
    295       DEBUG ((EFI_D_INFO, " Not Valid backup partition table\n"));
    296       goto Done;
    297     } else {
    298       DEBUG ((EFI_D_INFO, " Valid backup partition table\n"));
    299       DEBUG ((EFI_D_INFO, " Restore primary partition table by the backup\n"));
    300       if (!PartitionRestoreGptTable (BlockIo, DiskIo, BackupHeader)) {
    301         DEBUG ((EFI_D_INFO, " Restore primary partition table error\n"));
    302       }
    303 
    304       if (PartitionValidGptTable (BlockIo, DiskIo, BackupHeader->AlternateLBA, PrimaryHeader)) {
    305         DEBUG ((EFI_D_INFO, " Restore backup partition table success\n"));
    306       }
    307     }
    308   } else if (!PartitionValidGptTable (BlockIo, DiskIo, PrimaryHeader->AlternateLBA, BackupHeader)) {
    309     DEBUG ((EFI_D_INFO, " Valid primary and !Valid backup partition table\n"));
    310     DEBUG ((EFI_D_INFO, " Restore backup partition table by the primary\n"));
    311     if (!PartitionRestoreGptTable (BlockIo, DiskIo, PrimaryHeader)) {
    312       DEBUG ((EFI_D_INFO, " Restore backup partition table error\n"));
    313     }
    314 
    315     if (PartitionValidGptTable (BlockIo, DiskIo, PrimaryHeader->AlternateLBA, BackupHeader)) {
    316       DEBUG ((EFI_D_INFO, " Restore backup partition table success\n"));
    317     }
    318 
    319   }
    320 
    321   DEBUG ((EFI_D_INFO, " Valid primary and Valid backup partition table\n"));
    322 
    323   //
    324   // Read the EFI Partition Entries
    325   //
    326   PartEntry = AllocatePool (PrimaryHeader->NumberOfPartitionEntries * PrimaryHeader->SizeOfPartitionEntry);
    327   if (PartEntry == NULL) {
    328     DEBUG ((EFI_D_ERROR, "Allocate pool error\n"));
    329     goto Done;
    330   }
    331 
    332   Status = DiskIo->ReadDisk (
    333                      DiskIo,
    334                      MediaId,
    335                      MultU64x32(PrimaryHeader->PartitionEntryLBA, BlockSize),
    336                      PrimaryHeader->NumberOfPartitionEntries * (PrimaryHeader->SizeOfPartitionEntry),
    337                      PartEntry
    338                      );
    339   if (EFI_ERROR (Status)) {
    340     GptValidStatus = Status;
    341     DEBUG ((EFI_D_ERROR, " Partition Entry ReadDisk error\n"));
    342     goto Done;
    343   }
    344 
    345   DEBUG ((EFI_D_INFO, " Partition entries read block success\n"));
    346 
    347   DEBUG ((EFI_D_INFO, " Number of partition entries: %d\n", PrimaryHeader->NumberOfPartitionEntries));
    348 
    349   PEntryStatus = AllocateZeroPool (PrimaryHeader->NumberOfPartitionEntries * sizeof (EFI_PARTITION_ENTRY_STATUS));
    350   if (PEntryStatus == NULL) {
    351     DEBUG ((EFI_D_ERROR, "Allocate pool error\n"));
    352     goto Done;
    353   }
    354 
    355   //
    356   // Check the integrity of partition entries
    357   //
    358   PartitionCheckGptEntry (PrimaryHeader, PartEntry, PEntryStatus);
    359 
    360   //
    361   // If we got this far the GPT layout of the disk is valid and we should return true
    362   //
    363   GptValidStatus = EFI_SUCCESS;
    364 
    365   //
    366   // Create child device handles
    367   //
    368   for (Index = 0; Index < PrimaryHeader->NumberOfPartitionEntries; Index++) {
    369     Entry = (EFI_PARTITION_ENTRY *) ((UINT8 *) PartEntry + Index * PrimaryHeader->SizeOfPartitionEntry);
    370     if (CompareGuid (&Entry->PartitionTypeGUID, &gEfiPartTypeUnusedGuid) ||
    371         PEntryStatus[Index].OutOfRange ||
    372         PEntryStatus[Index].Overlap ||
    373         PEntryStatus[Index].OsSpecific
    374         ) {
    375       //
    376       // Don't use null EFI Partition Entries, Invalid Partition Entries or OS specific
    377       // partition Entries
    378       //
    379       continue;
    380     }
    381 
    382     ZeroMem (&HdDev, sizeof (HdDev));
    383     HdDev.Header.Type     = MEDIA_DEVICE_PATH;
    384     HdDev.Header.SubType  = MEDIA_HARDDRIVE_DP;
    385     SetDevicePathNodeLength (&HdDev.Header, sizeof (HdDev));
    386 
    387     HdDev.PartitionNumber = (UINT32) Index + 1;
    388     HdDev.MBRType         = MBR_TYPE_EFI_PARTITION_TABLE_HEADER;
    389     HdDev.SignatureType   = SIGNATURE_TYPE_GUID;
    390     HdDev.PartitionStart  = Entry->StartingLBA;
    391     HdDev.PartitionSize   = Entry->EndingLBA - Entry->StartingLBA + 1;
    392     CopyMem (HdDev.Signature, &Entry->UniquePartitionGUID, sizeof (EFI_GUID));
    393 
    394     DEBUG ((EFI_D_INFO, " Index : %d\n", (UINT32) Index));
    395     DEBUG ((EFI_D_INFO, " Start LBA : %lx\n", (UINT64) HdDev.PartitionStart));
    396     DEBUG ((EFI_D_INFO, " End LBA : %lx\n", (UINT64) Entry->EndingLBA));
    397     DEBUG ((EFI_D_INFO, " Partition size: %lx\n", (UINT64) HdDev.PartitionSize));
    398     DEBUG ((EFI_D_INFO, " Start : %lx", MultU64x32 (Entry->StartingLBA, BlockSize)));
    399     DEBUG ((EFI_D_INFO, " End : %lx\n", MultU64x32 (Entry->EndingLBA, BlockSize)));
    400 
    401     Status = PartitionInstallChildHandle (
    402                This,
    403                Handle,
    404                DiskIo,
    405                DiskIo2,
    406                BlockIo,
    407                BlockIo2,
    408                DevicePath,
    409                (EFI_DEVICE_PATH_PROTOCOL *) &HdDev,
    410                Entry->StartingLBA,
    411                Entry->EndingLBA,
    412                BlockSize,
    413                CompareGuid(&Entry->PartitionTypeGUID, &gEfiPartTypeSystemPartGuid)
    414                );
    415   }
    416 
    417   DEBUG ((EFI_D_INFO, "Prepare to Free Pool\n"));
    418 
    419 Done:
    420   if (ProtectiveMbr != NULL) {
    421     FreePool (ProtectiveMbr);
    422   }
    423   if (PrimaryHeader != NULL) {
    424     FreePool (PrimaryHeader);
    425   }
    426   if (BackupHeader != NULL) {
    427     FreePool (BackupHeader);
    428   }
    429   if (PartEntry != NULL) {
    430     FreePool (PartEntry);
    431   }
    432   if (PEntryStatus != NULL) {
    433     FreePool (PEntryStatus);
    434   }
    435 
    436   return GptValidStatus;
    437 }
    438 
    439 /**
    440   This routine will read GPT partition table header and return it.
    441 
    442   Caution: This function may receive untrusted input.
    443   The GPT partition table header is external input, so this routine
    444   will do basic validation for GPT partition table header before return.
    445 
    446   @param[in]  BlockIo     Parent BlockIo interface.
    447   @param[in]  DiskIo      Disk Io protocol.
    448   @param[in]  Lba         The starting Lba of the Partition Table
    449   @param[out] PartHeader  Stores the partition table that is read
    450 
    451   @retval TRUE      The partition table is valid
    452   @retval FALSE     The partition table is not valid
    453 
    454 **/
    455 BOOLEAN
    456 PartitionValidGptTable (
    457   IN  EFI_BLOCK_IO_PROTOCOL       *BlockIo,
    458   IN  EFI_DISK_IO_PROTOCOL        *DiskIo,
    459   IN  EFI_LBA                     Lba,
    460   OUT EFI_PARTITION_TABLE_HEADER  *PartHeader
    461   )
    462 {
    463   EFI_STATUS                  Status;
    464   UINT32                      BlockSize;
    465   EFI_PARTITION_TABLE_HEADER  *PartHdr;
    466   UINT32                      MediaId;
    467 
    468   BlockSize = BlockIo->Media->BlockSize;
    469   MediaId   = BlockIo->Media->MediaId;
    470   PartHdr   = AllocateZeroPool (BlockSize);
    471 
    472   if (PartHdr == NULL) {
    473     DEBUG ((EFI_D_ERROR, "Allocate pool error\n"));
    474     return FALSE;
    475   }
    476   //
    477   // Read the EFI Partition Table Header
    478   //
    479   Status = DiskIo->ReadDisk (
    480                      DiskIo,
    481                      MediaId,
    482                      MultU64x32 (Lba, BlockSize),
    483                      BlockSize,
    484                      PartHdr
    485                      );
    486   if (EFI_ERROR (Status)) {
    487     FreePool (PartHdr);
    488     return FALSE;
    489   }
    490 
    491   if ((PartHdr->Header.Signature != EFI_PTAB_HEADER_ID) ||
    492       !PartitionCheckCrc (BlockSize, &PartHdr->Header) ||
    493       PartHdr->MyLBA != Lba ||
    494       (PartHdr->SizeOfPartitionEntry < sizeof (EFI_PARTITION_ENTRY))
    495       ) {
    496     DEBUG ((EFI_D_INFO, "Invalid efi partition table header\n"));
    497     FreePool (PartHdr);
    498     return FALSE;
    499   }
    500 
    501   //
    502   // Ensure the NumberOfPartitionEntries * SizeOfPartitionEntry doesn't overflow.
    503   //
    504   if (PartHdr->NumberOfPartitionEntries > DivU64x32 (MAX_UINTN, PartHdr->SizeOfPartitionEntry)) {
    505     FreePool (PartHdr);
    506     return FALSE;
    507   }
    508 
    509   CopyMem (PartHeader, PartHdr, sizeof (EFI_PARTITION_TABLE_HEADER));
    510   if (!PartitionCheckGptEntryArrayCRC (BlockIo, DiskIo, PartHeader)) {
    511     FreePool (PartHdr);
    512     return FALSE;
    513   }
    514 
    515   DEBUG ((EFI_D_INFO, " Valid efi partition table header\n"));
    516   FreePool (PartHdr);
    517   return TRUE;
    518 }
    519 
    520 /**
    521   Check if the CRC field in the Partition table header is valid
    522   for Partition entry array.
    523 
    524   @param[in]  BlockIo     Parent BlockIo interface
    525   @param[in]  DiskIo      Disk Io Protocol.
    526   @param[in]  PartHeader  Partition table header structure
    527 
    528   @retval TRUE      the CRC is valid
    529   @retval FALSE     the CRC is invalid
    530 
    531 **/
    532 BOOLEAN
    533 PartitionCheckGptEntryArrayCRC (
    534   IN  EFI_BLOCK_IO_PROTOCOL       *BlockIo,
    535   IN  EFI_DISK_IO_PROTOCOL        *DiskIo,
    536   IN  EFI_PARTITION_TABLE_HEADER  *PartHeader
    537   )
    538 {
    539   EFI_STATUS  Status;
    540   UINT8       *Ptr;
    541   UINT32      Crc;
    542   UINTN       Size;
    543 
    544   //
    545   // Read the EFI Partition Entries
    546   //
    547   Ptr = AllocatePool (PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry);
    548   if (Ptr == NULL) {
    549     DEBUG ((EFI_D_ERROR, " Allocate pool error\n"));
    550     return FALSE;
    551   }
    552 
    553   Status = DiskIo->ReadDisk (
    554                     DiskIo,
    555                     BlockIo->Media->MediaId,
    556                     MultU64x32(PartHeader->PartitionEntryLBA, BlockIo->Media->BlockSize),
    557                     PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry,
    558                     Ptr
    559                     );
    560   if (EFI_ERROR (Status)) {
    561     FreePool (Ptr);
    562     return FALSE;
    563   }
    564 
    565   Size    = PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry;
    566 
    567   Status  = gBS->CalculateCrc32 (Ptr, Size, &Crc);
    568   if (EFI_ERROR (Status)) {
    569     DEBUG ((EFI_D_ERROR, "CheckPEntryArrayCRC: Crc calculation failed\n"));
    570     FreePool (Ptr);
    571     return FALSE;
    572   }
    573 
    574   FreePool (Ptr);
    575 
    576   return (BOOLEAN) (PartHeader->PartitionEntryArrayCRC32 == Crc);
    577 }
    578 
    579 
    580 /**
    581   Restore Partition Table to its alternate place
    582   (Primary -> Backup or Backup -> Primary).
    583 
    584   @param[in]  BlockIo     Parent BlockIo interface.
    585   @param[in]  DiskIo      Disk Io Protocol.
    586   @param[in]  PartHeader  Partition table header structure.
    587 
    588   @retval TRUE      Restoring succeeds
    589   @retval FALSE     Restoring failed
    590 
    591 **/
    592 BOOLEAN
    593 PartitionRestoreGptTable (
    594   IN  EFI_BLOCK_IO_PROTOCOL       *BlockIo,
    595   IN  EFI_DISK_IO_PROTOCOL        *DiskIo,
    596   IN  EFI_PARTITION_TABLE_HEADER  *PartHeader
    597   )
    598 {
    599   EFI_STATUS                  Status;
    600   UINTN                       BlockSize;
    601   EFI_PARTITION_TABLE_HEADER  *PartHdr;
    602   EFI_LBA                     PEntryLBA;
    603   UINT8                       *Ptr;
    604   UINT32                      MediaId;
    605 
    606   PartHdr   = NULL;
    607   Ptr       = NULL;
    608 
    609   BlockSize = BlockIo->Media->BlockSize;
    610   MediaId   = BlockIo->Media->MediaId;
    611 
    612   PartHdr   = AllocateZeroPool (BlockSize);
    613 
    614   if (PartHdr == NULL) {
    615     DEBUG ((EFI_D_ERROR, "Allocate pool error\n"));
    616     return FALSE;
    617   }
    618 
    619   PEntryLBA = (PartHeader->MyLBA == PRIMARY_PART_HEADER_LBA) ? \
    620                              (PartHeader->LastUsableLBA + 1) : \
    621                              (PRIMARY_PART_HEADER_LBA + 1);
    622 
    623   CopyMem (PartHdr, PartHeader, sizeof (EFI_PARTITION_TABLE_HEADER));
    624 
    625   PartHdr->MyLBA              = PartHeader->AlternateLBA;
    626   PartHdr->AlternateLBA       = PartHeader->MyLBA;
    627   PartHdr->PartitionEntryLBA  = PEntryLBA;
    628   PartitionSetCrc ((EFI_TABLE_HEADER *) PartHdr);
    629 
    630   Status = DiskIo->WriteDisk (
    631                      DiskIo,
    632                      MediaId,
    633                      MultU64x32 (PartHdr->MyLBA, (UINT32) BlockSize),
    634                      BlockSize,
    635                      PartHdr
    636                      );
    637   if (EFI_ERROR (Status)) {
    638     goto Done;
    639   }
    640 
    641   Ptr = AllocatePool (PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry);
    642   if (Ptr == NULL) {
    643     DEBUG ((EFI_D_ERROR, " Allocate pool error\n"));
    644     Status = EFI_OUT_OF_RESOURCES;
    645     goto Done;
    646   }
    647 
    648   Status = DiskIo->ReadDisk (
    649                     DiskIo,
    650                     MediaId,
    651                     MultU64x32(PartHeader->PartitionEntryLBA, (UINT32) BlockSize),
    652                     PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry,
    653                     Ptr
    654                     );
    655   if (EFI_ERROR (Status)) {
    656     goto Done;
    657   }
    658 
    659   Status = DiskIo->WriteDisk (
    660                     DiskIo,
    661                     MediaId,
    662                     MultU64x32(PEntryLBA, (UINT32) BlockSize),
    663                     PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry,
    664                     Ptr
    665                     );
    666 
    667 Done:
    668   FreePool (PartHdr);
    669 
    670   if (Ptr != NULL) {
    671     FreePool (Ptr);
    672   }
    673 
    674   if (EFI_ERROR (Status)) {
    675     return FALSE;
    676   }
    677 
    678   return TRUE;
    679 }
    680 
    681 /**
    682   This routine will check GPT partition entry and return entry status.
    683 
    684   Caution: This function may receive untrusted input.
    685   The GPT partition entry is external input, so this routine
    686   will do basic validation for GPT partition entry and report status.
    687 
    688   @param[in]    PartHeader    Partition table header structure
    689   @param[in]    PartEntry     The partition entry array
    690   @param[out]   PEntryStatus  the partition entry status array
    691                               recording the status of each partition
    692 
    693 **/
    694 VOID
    695 PartitionCheckGptEntry (
    696   IN  EFI_PARTITION_TABLE_HEADER  *PartHeader,
    697   IN  EFI_PARTITION_ENTRY         *PartEntry,
    698   OUT EFI_PARTITION_ENTRY_STATUS  *PEntryStatus
    699   )
    700 {
    701   EFI_LBA              StartingLBA;
    702   EFI_LBA              EndingLBA;
    703   EFI_PARTITION_ENTRY  *Entry;
    704   UINTN                Index1;
    705   UINTN                Index2;
    706 
    707   DEBUG ((EFI_D_INFO, " start check partition entries\n"));
    708   for (Index1 = 0; Index1 < PartHeader->NumberOfPartitionEntries; Index1++) {
    709     Entry = (EFI_PARTITION_ENTRY *) ((UINT8 *) PartEntry + Index1 * PartHeader->SizeOfPartitionEntry);
    710     if (CompareGuid (&Entry->PartitionTypeGUID, &gEfiPartTypeUnusedGuid)) {
    711       continue;
    712     }
    713 
    714     StartingLBA = Entry->StartingLBA;
    715     EndingLBA   = Entry->EndingLBA;
    716     if (StartingLBA > EndingLBA ||
    717         StartingLBA < PartHeader->FirstUsableLBA ||
    718         StartingLBA > PartHeader->LastUsableLBA ||
    719         EndingLBA < PartHeader->FirstUsableLBA ||
    720         EndingLBA > PartHeader->LastUsableLBA
    721         ) {
    722       PEntryStatus[Index1].OutOfRange = TRUE;
    723       continue;
    724     }
    725 
    726     if ((Entry->Attributes & BIT1) != 0) {
    727       //
    728       // If Bit 1 is set, this indicate that this is an OS specific GUID partition.
    729       //
    730       PEntryStatus[Index1].OsSpecific = TRUE;
    731     }
    732 
    733     for (Index2 = Index1 + 1; Index2 < PartHeader->NumberOfPartitionEntries; Index2++) {
    734       Entry = (EFI_PARTITION_ENTRY *) ((UINT8 *) PartEntry + Index2 * PartHeader->SizeOfPartitionEntry);
    735       if (CompareGuid (&Entry->PartitionTypeGUID, &gEfiPartTypeUnusedGuid)) {
    736         continue;
    737       }
    738 
    739       if (Entry->EndingLBA >= StartingLBA && Entry->StartingLBA <= EndingLBA) {
    740         //
    741         // This region overlaps with the Index1'th region
    742         //
    743         PEntryStatus[Index1].Overlap  = TRUE;
    744         PEntryStatus[Index2].Overlap  = TRUE;
    745         continue;
    746       }
    747     }
    748   }
    749 
    750   DEBUG ((EFI_D_INFO, " End check partition entries\n"));
    751 }
    752 
    753 
    754 /**
    755   Updates the CRC32 value in the table header.
    756 
    757   @param  Hdr    Table to update
    758 
    759 **/
    760 VOID
    761 PartitionSetCrc (
    762   IN OUT EFI_TABLE_HEADER *Hdr
    763   )
    764 {
    765   PartitionSetCrcAltSize (Hdr->HeaderSize, Hdr);
    766 }
    767 
    768 
    769 /**
    770   Updates the CRC32 value in the table header.
    771 
    772   @param  Size   The size of the table
    773   @param  Hdr    Table to update
    774 
    775 **/
    776 VOID
    777 PartitionSetCrcAltSize (
    778   IN UINTN                 Size,
    779   IN OUT EFI_TABLE_HEADER  *Hdr
    780   )
    781 {
    782   UINT32  Crc;
    783 
    784   Hdr->CRC32 = 0;
    785   gBS->CalculateCrc32 ((UINT8 *) Hdr, Size, &Crc);
    786   Hdr->CRC32 = Crc;
    787 }
    788 
    789 
    790 /**
    791   Checks the CRC32 value in the table header.
    792 
    793   @param  MaxSize   Max Size limit
    794   @param  Hdr       Table to check
    795 
    796   @return TRUE      CRC Valid
    797   @return FALSE     CRC Invalid
    798 
    799 **/
    800 BOOLEAN
    801 PartitionCheckCrc (
    802   IN UINTN                 MaxSize,
    803   IN OUT EFI_TABLE_HEADER  *Hdr
    804   )
    805 {
    806   return PartitionCheckCrcAltSize (MaxSize, Hdr->HeaderSize, Hdr);
    807 }
    808 
    809 
    810 /**
    811   Checks the CRC32 value in the table header.
    812 
    813   @param  MaxSize   Max Size limit
    814   @param  Size      The size of the table
    815   @param  Hdr       Table to check
    816 
    817   @return TRUE    CRC Valid
    818   @return FALSE   CRC Invalid
    819 
    820 **/
    821 BOOLEAN
    822 PartitionCheckCrcAltSize (
    823   IN UINTN                 MaxSize,
    824   IN UINTN                 Size,
    825   IN OUT EFI_TABLE_HEADER  *Hdr
    826   )
    827 {
    828   UINT32      Crc;
    829   UINT32      OrgCrc;
    830   EFI_STATUS  Status;
    831 
    832   Crc = 0;
    833 
    834   if (Size == 0) {
    835     //
    836     // If header size is 0 CRC will pass so return FALSE here
    837     //
    838     return FALSE;
    839   }
    840 
    841   if ((MaxSize != 0) && (Size > MaxSize)) {
    842     DEBUG ((EFI_D_ERROR, "CheckCrc32: Size > MaxSize\n"));
    843     return FALSE;
    844   }
    845   //
    846   // clear old crc from header
    847   //
    848   OrgCrc      = Hdr->CRC32;
    849   Hdr->CRC32  = 0;
    850 
    851   Status      = gBS->CalculateCrc32 ((UINT8 *) Hdr, Size, &Crc);
    852   if (EFI_ERROR (Status)) {
    853     DEBUG ((EFI_D_ERROR, "CheckCrc32: Crc calculation failed\n"));
    854     return FALSE;
    855   }
    856   //
    857   // set results
    858   //
    859   Hdr->CRC32 = Crc;
    860 
    861   //
    862   // return status
    863   //
    864   DEBUG_CODE_BEGIN ();
    865     if (OrgCrc != Crc) {
    866       DEBUG ((EFI_D_ERROR, "CheckCrc32: Crc check failed\n"));
    867     }
    868   DEBUG_CODE_END ();
    869 
    870   return (BOOLEAN) (OrgCrc == Crc);
    871 }
    872