]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Disk/PartitionDxe/Gpt.c
MdeModulePkg: Replace BSD License with BSD+Patent License
[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].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
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
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
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
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
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
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
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
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 }