Coverage Report

Created: 2025-12-09 07:02

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