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