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
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)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
PartitionValidGptTable(IN EFI_BLOCK_IO_PROTOCOL * BlockIo,IN EFI_DISK_IO_PROTOCOL * DiskIo,IN EFI_LBA Lba,OUT EFI_PARTITION_TABLE_HEADER * PartHeader)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
PartitionCheckGptEntryArrayCRC(IN EFI_BLOCK_IO_PROTOCOL * BlockIo,IN EFI_DISK_IO_PROTOCOL * DiskIo,IN EFI_PARTITION_TABLE_HEADER * PartHeader)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
PartitionRestoreGptTable(IN EFI_BLOCK_IO_PROTOCOL * BlockIo,IN EFI_DISK_IO_PROTOCOL * DiskIo,IN EFI_PARTITION_TABLE_HEADER * PartHeader)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
PartitionCheckGptEntry(IN EFI_PARTITION_TABLE_HEADER * PartHeader,IN EFI_PARTITION_ENTRY * PartEntry,OUT EFI_PARTITION_ENTRY_STATUS * PEntryStatus)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
PartitionSetCrc(IN OUT EFI_TABLE_HEADER * Hdr)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
PartitionSetCrcAltSize(IN UINTN Size,IN OUT EFI_TABLE_HEADER * Hdr)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
PartitionCheckCrc(IN UINTN MaxSize,IN OUT EFI_TABLE_HEADER * Hdr)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
PartitionCheckCrcAltSize(IN UINTN MaxSize,IN UINTN Size,IN OUT EFI_TABLE_HEADER * Hdr)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