]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Disk/PartitionDxe/Gpt.c
efaff5e0808f8babd652dbd9660b67fc73736b66
[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 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
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].OSIndicator == PMBR_GPT_PARTITION &&
268 UNPACK_UINT32 (ProtectiveMbr->Partition[Index].StartingLBA) == 1
269 ) {
270 break;
271 }
272 }
273 if (Index == MAX_MBR_PARTITIONS) {
274 goto Done;
275 }
276
277 //
278 // Allocate the GPT structures
279 //
280 PrimaryHeader = AllocateZeroPool (sizeof (EFI_PARTITION_TABLE_HEADER));
281 if (PrimaryHeader == NULL) {
282 goto Done;
283 }
284
285 BackupHeader = AllocateZeroPool (sizeof (EFI_PARTITION_TABLE_HEADER));
286 if (BackupHeader == NULL) {
287 goto Done;
288 }
289
290 //
291 // Check primary and backup partition tables
292 //
293 if (!PartitionValidGptTable (BlockIo, DiskIo, PRIMARY_PART_HEADER_LBA, PrimaryHeader)) {
294 DEBUG ((EFI_D_INFO, " Not Valid primary partition table\n"));
295
296 if (!PartitionValidGptTable (BlockIo, DiskIo, LastBlock, BackupHeader)) {
297 DEBUG ((EFI_D_INFO, " Not Valid backup partition table\n"));
298 goto Done;
299 } else {
300 DEBUG ((EFI_D_INFO, " Valid backup partition table\n"));
301 DEBUG ((EFI_D_INFO, " Restore primary partition table by the backup\n"));
302 if (!PartitionRestoreGptTable (BlockIo, DiskIo, BackupHeader)) {
303 DEBUG ((EFI_D_INFO, " Restore primary partition table error\n"));
304 }
305
306 if (PartitionValidGptTable (BlockIo, DiskIo, BackupHeader->AlternateLBA, PrimaryHeader)) {
307 DEBUG ((EFI_D_INFO, " Restore backup partition table success\n"));
308 }
309 }
310 } else if (!PartitionValidGptTable (BlockIo, DiskIo, PrimaryHeader->AlternateLBA, BackupHeader)) {
311 DEBUG ((EFI_D_INFO, " Valid primary and !Valid backup partition table\n"));
312 DEBUG ((EFI_D_INFO, " Restore backup partition table by the primary\n"));
313 if (!PartitionRestoreGptTable (BlockIo, DiskIo, PrimaryHeader)) {
314 DEBUG ((EFI_D_INFO, " Restore backup partition table error\n"));
315 }
316
317 if (PartitionValidGptTable (BlockIo, DiskIo, PrimaryHeader->AlternateLBA, BackupHeader)) {
318 DEBUG ((EFI_D_INFO, " Restore backup partition table success\n"));
319 }
320
321 }
322
323 DEBUG ((EFI_D_INFO, " Valid primary and Valid backup partition table\n"));
324
325 //
326 // Read the EFI Partition Entries
327 //
328 PartEntry = AllocatePool (PrimaryHeader->NumberOfPartitionEntries * PrimaryHeader->SizeOfPartitionEntry);
329 if (PartEntry == NULL) {
330 DEBUG ((EFI_D_ERROR, "Allocate pool error\n"));
331 goto Done;
332 }
333
334 Status = DiskIo->ReadDisk (
335 DiskIo,
336 MediaId,
337 MultU64x32(PrimaryHeader->PartitionEntryLBA, BlockSize),
338 PrimaryHeader->NumberOfPartitionEntries * (PrimaryHeader->SizeOfPartitionEntry),
339 PartEntry
340 );
341 if (EFI_ERROR (Status)) {
342 GptValidStatus = Status;
343 DEBUG ((EFI_D_ERROR, " Partition Entry ReadDisk error\n"));
344 goto Done;
345 }
346
347 DEBUG ((EFI_D_INFO, " Partition entries read block success\n"));
348
349 DEBUG ((EFI_D_INFO, " Number of partition entries: %d\n", PrimaryHeader->NumberOfPartitionEntries));
350
351 PEntryStatus = AllocateZeroPool (PrimaryHeader->NumberOfPartitionEntries * sizeof (EFI_PARTITION_ENTRY_STATUS));
352 if (PEntryStatus == NULL) {
353 DEBUG ((EFI_D_ERROR, "Allocate pool error\n"));
354 goto Done;
355 }
356
357 //
358 // Check the integrity of partition entries
359 //
360 PartitionCheckGptEntry (PrimaryHeader, PartEntry, PEntryStatus);
361
362 //
363 // If we got this far the GPT layout of the disk is valid and we should return true
364 //
365 GptValidStatus = EFI_SUCCESS;
366
367 //
368 // Create child device handles
369 //
370 for (Index = 0; Index < PrimaryHeader->NumberOfPartitionEntries; Index++) {
371 Entry = (EFI_PARTITION_ENTRY *) ((UINT8 *) PartEntry + Index * PrimaryHeader->SizeOfPartitionEntry);
372 if (CompareGuid (&Entry->PartitionTypeGUID, &gEfiPartTypeUnusedGuid) ||
373 PEntryStatus[Index].OutOfRange ||
374 PEntryStatus[Index].Overlap ||
375 PEntryStatus[Index].OsSpecific
376 ) {
377 //
378 // Don't use null EFI Partition Entries, Invalid Partition Entries or OS specific
379 // partition Entries
380 //
381 continue;
382 }
383
384 ZeroMem (&HdDev, sizeof (HdDev));
385 HdDev.Header.Type = MEDIA_DEVICE_PATH;
386 HdDev.Header.SubType = MEDIA_HARDDRIVE_DP;
387 SetDevicePathNodeLength (&HdDev.Header, sizeof (HdDev));
388
389 HdDev.PartitionNumber = (UINT32) Index + 1;
390 HdDev.MBRType = MBR_TYPE_EFI_PARTITION_TABLE_HEADER;
391 HdDev.SignatureType = SIGNATURE_TYPE_GUID;
392 HdDev.PartitionStart = Entry->StartingLBA;
393 HdDev.PartitionSize = Entry->EndingLBA - Entry->StartingLBA + 1;
394 CopyMem (HdDev.Signature, &Entry->UniquePartitionGUID, sizeof (EFI_GUID));
395
396 ZeroMem (&PartitionInfo, sizeof (EFI_PARTITION_INFO_PROTOCOL));
397 PartitionInfo.Revision = EFI_PARTITION_INFO_PROTOCOL_REVISION;
398 PartitionInfo.Type = PARTITION_TYPE_GPT;
399 if (CompareGuid (&Entry->PartitionTypeGUID, &gEfiPartTypeSystemPartGuid)) {
400 PartitionInfo.System = 1;
401 }
402 CopyMem (&PartitionInfo.Info.Gpt, Entry, sizeof (EFI_PARTITION_ENTRY));
403
404 DEBUG ((EFI_D_INFO, " Index : %d\n", (UINT32) Index));
405 DEBUG ((EFI_D_INFO, " Start LBA : %lx\n", (UINT64) HdDev.PartitionStart));
406 DEBUG ((EFI_D_INFO, " End LBA : %lx\n", (UINT64) Entry->EndingLBA));
407 DEBUG ((EFI_D_INFO, " Partition size: %lx\n", (UINT64) HdDev.PartitionSize));
408 DEBUG ((EFI_D_INFO, " Start : %lx", MultU64x32 (Entry->StartingLBA, BlockSize)));
409 DEBUG ((EFI_D_INFO, " End : %lx\n", MultU64x32 (Entry->EndingLBA, BlockSize)));
410
411 Status = PartitionInstallChildHandle (
412 This,
413 Handle,
414 DiskIo,
415 DiskIo2,
416 BlockIo,
417 BlockIo2,
418 DevicePath,
419 (EFI_DEVICE_PATH_PROTOCOL *) &HdDev,
420 &PartitionInfo,
421 Entry->StartingLBA,
422 Entry->EndingLBA,
423 BlockSize,
424 &Entry->PartitionTypeGUID
425 );
426 }
427
428 DEBUG ((EFI_D_INFO, "Prepare to Free Pool\n"));
429
430 Done:
431 if (ProtectiveMbr != NULL) {
432 FreePool (ProtectiveMbr);
433 }
434 if (PrimaryHeader != NULL) {
435 FreePool (PrimaryHeader);
436 }
437 if (BackupHeader != NULL) {
438 FreePool (BackupHeader);
439 }
440 if (PartEntry != NULL) {
441 FreePool (PartEntry);
442 }
443 if (PEntryStatus != NULL) {
444 FreePool (PEntryStatus);
445 }
446
447 return GptValidStatus;
448 }
449
450 /**
451 This routine will read GPT partition table header and return it.
452
453 Caution: This function may receive untrusted input.
454 The GPT partition table header is external input, so this routine
455 will do basic validation for GPT partition table header before return.
456
457 @param[in] BlockIo Parent BlockIo interface.
458 @param[in] DiskIo Disk Io protocol.
459 @param[in] Lba The starting Lba of the Partition Table
460 @param[out] PartHeader Stores the partition table that is read
461
462 @retval TRUE The partition table is valid
463 @retval FALSE The partition table is not valid
464
465 **/
466 BOOLEAN
467 PartitionValidGptTable (
468 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
469 IN EFI_DISK_IO_PROTOCOL *DiskIo,
470 IN EFI_LBA Lba,
471 OUT EFI_PARTITION_TABLE_HEADER *PartHeader
472 )
473 {
474 EFI_STATUS Status;
475 UINT32 BlockSize;
476 EFI_PARTITION_TABLE_HEADER *PartHdr;
477 UINT32 MediaId;
478
479 BlockSize = BlockIo->Media->BlockSize;
480 MediaId = BlockIo->Media->MediaId;
481 PartHdr = AllocateZeroPool (BlockSize);
482
483 if (PartHdr == NULL) {
484 DEBUG ((EFI_D_ERROR, "Allocate pool error\n"));
485 return FALSE;
486 }
487 //
488 // Read the EFI Partition Table Header
489 //
490 Status = DiskIo->ReadDisk (
491 DiskIo,
492 MediaId,
493 MultU64x32 (Lba, BlockSize),
494 BlockSize,
495 PartHdr
496 );
497 if (EFI_ERROR (Status)) {
498 FreePool (PartHdr);
499 return FALSE;
500 }
501
502 if ((PartHdr->Header.Signature != EFI_PTAB_HEADER_ID) ||
503 !PartitionCheckCrc (BlockSize, &PartHdr->Header) ||
504 PartHdr->MyLBA != Lba ||
505 (PartHdr->SizeOfPartitionEntry < sizeof (EFI_PARTITION_ENTRY))
506 ) {
507 DEBUG ((EFI_D_INFO, "Invalid efi partition table header\n"));
508 FreePool (PartHdr);
509 return FALSE;
510 }
511
512 //
513 // Ensure the NumberOfPartitionEntries * SizeOfPartitionEntry doesn't overflow.
514 //
515 if (PartHdr->NumberOfPartitionEntries > DivU64x32 (MAX_UINTN, PartHdr->SizeOfPartitionEntry)) {
516 FreePool (PartHdr);
517 return FALSE;
518 }
519
520 CopyMem (PartHeader, PartHdr, sizeof (EFI_PARTITION_TABLE_HEADER));
521 if (!PartitionCheckGptEntryArrayCRC (BlockIo, DiskIo, PartHeader)) {
522 FreePool (PartHdr);
523 return FALSE;
524 }
525
526 DEBUG ((EFI_D_INFO, " Valid efi partition table header\n"));
527 FreePool (PartHdr);
528 return TRUE;
529 }
530
531 /**
532 Check if the CRC field in the Partition table header is valid
533 for Partition entry array.
534
535 @param[in] BlockIo Parent BlockIo interface
536 @param[in] DiskIo Disk Io Protocol.
537 @param[in] PartHeader Partition table header structure
538
539 @retval TRUE the CRC is valid
540 @retval FALSE the CRC is invalid
541
542 **/
543 BOOLEAN
544 PartitionCheckGptEntryArrayCRC (
545 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
546 IN EFI_DISK_IO_PROTOCOL *DiskIo,
547 IN EFI_PARTITION_TABLE_HEADER *PartHeader
548 )
549 {
550 EFI_STATUS Status;
551 UINT8 *Ptr;
552 UINT32 Crc;
553 UINTN Size;
554
555 //
556 // Read the EFI Partition Entries
557 //
558 Ptr = AllocatePool (PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry);
559 if (Ptr == NULL) {
560 DEBUG ((EFI_D_ERROR, " Allocate pool error\n"));
561 return FALSE;
562 }
563
564 Status = DiskIo->ReadDisk (
565 DiskIo,
566 BlockIo->Media->MediaId,
567 MultU64x32(PartHeader->PartitionEntryLBA, BlockIo->Media->BlockSize),
568 PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry,
569 Ptr
570 );
571 if (EFI_ERROR (Status)) {
572 FreePool (Ptr);
573 return FALSE;
574 }
575
576 Size = PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry;
577
578 Status = gBS->CalculateCrc32 (Ptr, Size, &Crc);
579 if (EFI_ERROR (Status)) {
580 DEBUG ((EFI_D_ERROR, "CheckPEntryArrayCRC: Crc calculation failed\n"));
581 FreePool (Ptr);
582 return FALSE;
583 }
584
585 FreePool (Ptr);
586
587 return (BOOLEAN) (PartHeader->PartitionEntryArrayCRC32 == Crc);
588 }
589
590
591 /**
592 Restore Partition Table to its alternate place
593 (Primary -> Backup or Backup -> Primary).
594
595 @param[in] BlockIo Parent BlockIo interface.
596 @param[in] DiskIo Disk Io Protocol.
597 @param[in] PartHeader Partition table header structure.
598
599 @retval TRUE Restoring succeeds
600 @retval FALSE Restoring failed
601
602 **/
603 BOOLEAN
604 PartitionRestoreGptTable (
605 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
606 IN EFI_DISK_IO_PROTOCOL *DiskIo,
607 IN EFI_PARTITION_TABLE_HEADER *PartHeader
608 )
609 {
610 EFI_STATUS Status;
611 UINTN BlockSize;
612 EFI_PARTITION_TABLE_HEADER *PartHdr;
613 EFI_LBA PEntryLBA;
614 UINT8 *Ptr;
615 UINT32 MediaId;
616
617 PartHdr = NULL;
618 Ptr = NULL;
619
620 BlockSize = BlockIo->Media->BlockSize;
621 MediaId = BlockIo->Media->MediaId;
622
623 PartHdr = AllocateZeroPool (BlockSize);
624
625 if (PartHdr == NULL) {
626 DEBUG ((EFI_D_ERROR, "Allocate pool error\n"));
627 return FALSE;
628 }
629
630 PEntryLBA = (PartHeader->MyLBA == PRIMARY_PART_HEADER_LBA) ? \
631 (PartHeader->LastUsableLBA + 1) : \
632 (PRIMARY_PART_HEADER_LBA + 1);
633
634 CopyMem (PartHdr, PartHeader, sizeof (EFI_PARTITION_TABLE_HEADER));
635
636 PartHdr->MyLBA = PartHeader->AlternateLBA;
637 PartHdr->AlternateLBA = PartHeader->MyLBA;
638 PartHdr->PartitionEntryLBA = PEntryLBA;
639 PartitionSetCrc ((EFI_TABLE_HEADER *) PartHdr);
640
641 Status = DiskIo->WriteDisk (
642 DiskIo,
643 MediaId,
644 MultU64x32 (PartHdr->MyLBA, (UINT32) BlockSize),
645 BlockSize,
646 PartHdr
647 );
648 if (EFI_ERROR (Status)) {
649 goto Done;
650 }
651
652 Ptr = AllocatePool (PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry);
653 if (Ptr == NULL) {
654 DEBUG ((EFI_D_ERROR, " Allocate pool error\n"));
655 Status = EFI_OUT_OF_RESOURCES;
656 goto Done;
657 }
658
659 Status = DiskIo->ReadDisk (
660 DiskIo,
661 MediaId,
662 MultU64x32(PartHeader->PartitionEntryLBA, (UINT32) BlockSize),
663 PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry,
664 Ptr
665 );
666 if (EFI_ERROR (Status)) {
667 goto Done;
668 }
669
670 Status = DiskIo->WriteDisk (
671 DiskIo,
672 MediaId,
673 MultU64x32(PEntryLBA, (UINT32) BlockSize),
674 PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry,
675 Ptr
676 );
677
678 Done:
679 FreePool (PartHdr);
680
681 if (Ptr != NULL) {
682 FreePool (Ptr);
683 }
684
685 if (EFI_ERROR (Status)) {
686 return FALSE;
687 }
688
689 return TRUE;
690 }
691
692 /**
693 This routine will check GPT partition entry and return entry status.
694
695 Caution: This function may receive untrusted input.
696 The GPT partition entry is external input, so this routine
697 will do basic validation for GPT partition entry and report status.
698
699 @param[in] PartHeader Partition table header structure
700 @param[in] PartEntry The partition entry array
701 @param[out] PEntryStatus the partition entry status array
702 recording the status of each partition
703
704 **/
705 VOID
706 PartitionCheckGptEntry (
707 IN EFI_PARTITION_TABLE_HEADER *PartHeader,
708 IN EFI_PARTITION_ENTRY *PartEntry,
709 OUT EFI_PARTITION_ENTRY_STATUS *PEntryStatus
710 )
711 {
712 EFI_LBA StartingLBA;
713 EFI_LBA EndingLBA;
714 EFI_PARTITION_ENTRY *Entry;
715 UINTN Index1;
716 UINTN Index2;
717
718 DEBUG ((EFI_D_INFO, " start check partition entries\n"));
719 for (Index1 = 0; Index1 < PartHeader->NumberOfPartitionEntries; Index1++) {
720 Entry = (EFI_PARTITION_ENTRY *) ((UINT8 *) PartEntry + Index1 * PartHeader->SizeOfPartitionEntry);
721 if (CompareGuid (&Entry->PartitionTypeGUID, &gEfiPartTypeUnusedGuid)) {
722 continue;
723 }
724
725 StartingLBA = Entry->StartingLBA;
726 EndingLBA = Entry->EndingLBA;
727 if (StartingLBA > EndingLBA ||
728 StartingLBA < PartHeader->FirstUsableLBA ||
729 StartingLBA > PartHeader->LastUsableLBA ||
730 EndingLBA < PartHeader->FirstUsableLBA ||
731 EndingLBA > PartHeader->LastUsableLBA
732 ) {
733 PEntryStatus[Index1].OutOfRange = TRUE;
734 continue;
735 }
736
737 if ((Entry->Attributes & BIT1) != 0) {
738 //
739 // If Bit 1 is set, this indicate that this is an OS specific GUID partition.
740 //
741 PEntryStatus[Index1].OsSpecific = TRUE;
742 }
743
744 for (Index2 = Index1 + 1; Index2 < PartHeader->NumberOfPartitionEntries; Index2++) {
745 Entry = (EFI_PARTITION_ENTRY *) ((UINT8 *) PartEntry + Index2 * PartHeader->SizeOfPartitionEntry);
746 if (CompareGuid (&Entry->PartitionTypeGUID, &gEfiPartTypeUnusedGuid)) {
747 continue;
748 }
749
750 if (Entry->EndingLBA >= StartingLBA && Entry->StartingLBA <= EndingLBA) {
751 //
752 // This region overlaps with the Index1'th region
753 //
754 PEntryStatus[Index1].Overlap = TRUE;
755 PEntryStatus[Index2].Overlap = TRUE;
756 continue;
757 }
758 }
759 }
760
761 DEBUG ((EFI_D_INFO, " End check partition entries\n"));
762 }
763
764
765 /**
766 Updates the CRC32 value in the table header.
767
768 @param Hdr Table to update
769
770 **/
771 VOID
772 PartitionSetCrc (
773 IN OUT EFI_TABLE_HEADER *Hdr
774 )
775 {
776 PartitionSetCrcAltSize (Hdr->HeaderSize, Hdr);
777 }
778
779
780 /**
781 Updates the CRC32 value in the table header.
782
783 @param Size The size of the table
784 @param Hdr Table to update
785
786 **/
787 VOID
788 PartitionSetCrcAltSize (
789 IN UINTN Size,
790 IN OUT EFI_TABLE_HEADER *Hdr
791 )
792 {
793 UINT32 Crc;
794
795 Hdr->CRC32 = 0;
796 gBS->CalculateCrc32 ((UINT8 *) Hdr, Size, &Crc);
797 Hdr->CRC32 = Crc;
798 }
799
800
801 /**
802 Checks the CRC32 value in the table header.
803
804 @param MaxSize Max Size limit
805 @param Hdr Table to check
806
807 @return TRUE CRC Valid
808 @return FALSE CRC Invalid
809
810 **/
811 BOOLEAN
812 PartitionCheckCrc (
813 IN UINTN MaxSize,
814 IN OUT EFI_TABLE_HEADER *Hdr
815 )
816 {
817 return PartitionCheckCrcAltSize (MaxSize, Hdr->HeaderSize, Hdr);
818 }
819
820
821 /**
822 Checks the CRC32 value in the table header.
823
824 @param MaxSize Max Size limit
825 @param Size The size of the table
826 @param Hdr Table to check
827
828 @return TRUE CRC Valid
829 @return FALSE CRC Invalid
830
831 **/
832 BOOLEAN
833 PartitionCheckCrcAltSize (
834 IN UINTN MaxSize,
835 IN UINTN Size,
836 IN OUT EFI_TABLE_HEADER *Hdr
837 )
838 {
839 UINT32 Crc;
840 UINT32 OrgCrc;
841 EFI_STATUS Status;
842
843 Crc = 0;
844
845 if (Size == 0) {
846 //
847 // If header size is 0 CRC will pass so return FALSE here
848 //
849 return FALSE;
850 }
851
852 if ((MaxSize != 0) && (Size > MaxSize)) {
853 DEBUG ((EFI_D_ERROR, "CheckCrc32: Size > MaxSize\n"));
854 return FALSE;
855 }
856 //
857 // clear old crc from header
858 //
859 OrgCrc = Hdr->CRC32;
860 Hdr->CRC32 = 0;
861
862 Status = gBS->CalculateCrc32 ((UINT8 *) Hdr, Size, &Crc);
863 if (EFI_ERROR (Status)) {
864 DEBUG ((EFI_D_ERROR, "CheckCrc32: Crc calculation failed\n"));
865 return FALSE;
866 }
867 //
868 // set results
869 //
870 Hdr->CRC32 = Crc;
871
872 //
873 // return status
874 //
875 DEBUG_CODE_BEGIN ();
876 if (OrgCrc != Crc) {
877 DEBUG ((EFI_D_ERROR, "CheckCrc32: Crc check failed\n"));
878 }
879 DEBUG_CODE_END ();
880
881 return (BOOLEAN) (OrgCrc == Crc);
882 }