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