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