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