summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--meta/recipes-core/ovmf/ovmf/CVE-2022-36763-0001.patch985
-rw-r--r--meta/recipes-core/ovmf/ovmf/CVE-2022-36763-0002.patch889
-rw-r--r--meta/recipes-core/ovmf/ovmf/CVE-2022-36763-0003.patch55
-rw-r--r--meta/recipes-core/ovmf/ovmf_git.bb3
4 files changed, 1932 insertions, 0 deletions
diff --git a/meta/recipes-core/ovmf/ovmf/CVE-2022-36763-0001.patch b/meta/recipes-core/ovmf/ovmf/CVE-2022-36763-0001.patch
new file mode 100644
index 0000000000..93cefe7740
--- /dev/null
+++ b/meta/recipes-core/ovmf/ovmf/CVE-2022-36763-0001.patch
@@ -0,0 +1,985 @@
1From 224446543206450ddb5830e6abd026d61d3c7f4b Mon Sep 17 00:00:00 2001
2From: "Douglas Flick [MSFT]" <doug.edk2@gmail.com>
3Date: Fri, 12 Jan 2024 02:16:01 +0800
4Subject: [PATCH] SecurityPkg: DxeTpm2MeasureBootLib: SECURITY PATCH 4117 - CVE
5 2022-36763
6
7This commit contains the patch files and tests for DxeTpm2MeasureBootLib
8CVE 2022-36763.
9
10Cc: Jiewen Yao <jiewen.yao@intel.com>
11
12Signed-off-by: Doug Flick [MSFT] <doug.edk2@gmail.com>
13
14CVE: CVE-2022-36763
15
16Upstream-Status: Backport [https://github.com/tianocore/edk2/commit/224446543206450ddb5830e6abd026d61d3c7f4b]
17
18Signed-off-by: Soumya Sambu <soumya.sambu@windriver.com>
19---
20 .../DxeTpm2MeasureBootLib.c | 69 ++--
21 .../DxeTpm2MeasureBootLib.inf | 4 +-
22 .../DxeTpm2MeasureBootLibSanitization.c | 275 ++++++++++++++++
23 .../DxeTpm2MeasureBootLibSanitization.h | 113 +++++++
24 .../DxeTpm2MeasureBootLibSanitizationTest.c | 303 ++++++++++++++++++
25 ...Tpm2MeasureBootLibSanitizationTestHost.inf | 28 ++
26 SecurityPkg/SecurityPkg.ci.yaml | 1 +
27 7 files changed, 763 insertions(+), 30 deletions(-)
28 create mode 100644 SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLibSanitization.c
29 create mode 100644 SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLibSanitization.h
30 create mode 100644 SecurityPkg/Library/DxeTpm2MeasureBootLib/InternalUnitTest/DxeTpm2MeasureBootLibSanitizationTest.c
31 create mode 100644 SecurityPkg/Library/DxeTpm2MeasureBootLib/InternalUnitTest/DxeTpm2MeasureBootLibSanitizationTestHost.inf
32
33diff --git a/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.c b/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.c
34index 36a256a7af..0475103d6e 100644
35--- a/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.c
36+++ b/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.c
37@@ -20,6 +20,8 @@ Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
38 (C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
39 SPDX-License-Identifier: BSD-2-Clause-Patent
40
41+Copyright (c) Microsoft Corporation.<BR>
42+SPDX-License-Identifier: BSD-2-Clause-Patent
43 **/
44
45 #include <PiDxe.h>
46@@ -44,6 +46,8 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
47 #include <Library/HobLib.h>
48 #include <Protocol/CcMeasurement.h>
49
50+#include "DxeTpm2MeasureBootLibSanitization.h"
51+
52 typedef struct {
53 EFI_TCG2_PROTOCOL *Tcg2Protocol;
54 EFI_CC_MEASUREMENT_PROTOCOL *CcProtocol;
55@@ -144,10 +148,11 @@ Tcg2MeasureGptTable (
56 EFI_TCG2_EVENT *Tcg2Event;
57 EFI_CC_EVENT *CcEvent;
58 EFI_GPT_DATA *GptData;
59- UINT32 EventSize;
60+ UINT32 TcgEventSize;
61 EFI_TCG2_PROTOCOL *Tcg2Protocol;
62 EFI_CC_MEASUREMENT_PROTOCOL *CcProtocol;
63 EFI_CC_MR_INDEX MrIndex;
64+ UINT32 AllocSize;
65
66 if (mTcg2MeasureGptCount > 0) {
67 return EFI_SUCCESS;
68@@ -195,25 +200,22 @@ Tcg2MeasureGptTable (
69 BlockIo->Media->BlockSize,
70 (UINT8 *)PrimaryHeader
71 );
72- if (EFI_ERROR (Status)) {
73- DEBUG ((DEBUG_ERROR, "Failed to Read Partition Table Header!\n"));
74+ if (EFI_ERROR (Status) || EFI_ERROR (SanitizeEfiPartitionTableHeader (PrimaryHeader, BlockIo))) {
75+ DEBUG ((DEBUG_ERROR, "Failed to read Partition Table Header or invalid Partition Table Header!\n"));
76 FreePool (PrimaryHeader);
77 return EFI_DEVICE_ERROR;
78 }
79
80 //
81- // PrimaryHeader->SizeOfPartitionEntry should not be zero
82+ // Read the partition entry.
83 //
84- if (PrimaryHeader->SizeOfPartitionEntry == 0) {
85- DEBUG ((DEBUG_ERROR, "SizeOfPartitionEntry should not be zero!\n"));
86+ Status = SanitizePrimaryHeaderAllocationSize (PrimaryHeader, &AllocSize);
87+ if (EFI_ERROR (Status)) {
88 FreePool (PrimaryHeader);
89 return EFI_BAD_BUFFER_SIZE;
90 }
91
92- //
93- // Read the partition entry.
94- //
95- EntryPtr = (UINT8 *)AllocatePool (PrimaryHeader->NumberOfPartitionEntries * PrimaryHeader->SizeOfPartitionEntry);
96+ EntryPtr = (UINT8 *)AllocatePool (AllocSize);
97 if (EntryPtr == NULL) {
98 FreePool (PrimaryHeader);
99 return EFI_OUT_OF_RESOURCES;
100@@ -223,7 +225,7 @@ Tcg2MeasureGptTable (
101 DiskIo,
102 BlockIo->Media->MediaId,
103 MultU64x32 (PrimaryHeader->PartitionEntryLBA, BlockIo->Media->BlockSize),
104- PrimaryHeader->NumberOfPartitionEntries * PrimaryHeader->SizeOfPartitionEntry,
105+ AllocSize,
106 EntryPtr
107 );
108 if (EFI_ERROR (Status)) {
109@@ -248,16 +250,21 @@ Tcg2MeasureGptTable (
110 //
111 // Prepare Data for Measurement (CcProtocol and Tcg2Protocol)
112 //
113- EventSize = (UINT32)(sizeof (EFI_GPT_DATA) - sizeof (GptData->Partitions)
114- + NumberOfPartition * PrimaryHeader->SizeOfPartitionEntry);
115- EventPtr = (UINT8 *)AllocateZeroPool (EventSize + sizeof (EFI_TCG2_EVENT) - sizeof (Tcg2Event->Event));
116+ Status = SanitizePrimaryHeaderGptEventSize (PrimaryHeader, NumberOfPartition, &TcgEventSize);
117+ if (EFI_ERROR (Status)) {
118+ FreePool (PrimaryHeader);
119+ FreePool (EntryPtr);
120+ return EFI_DEVICE_ERROR;
121+ }
122+
123+ EventPtr = (UINT8 *)AllocateZeroPool (TcgEventSize);
124 if (EventPtr == NULL) {
125 Status = EFI_OUT_OF_RESOURCES;
126 goto Exit;
127 }
128
129 Tcg2Event = (EFI_TCG2_EVENT *)EventPtr;
130- Tcg2Event->Size = EventSize + sizeof (EFI_TCG2_EVENT) - sizeof (Tcg2Event->Event);
131+ Tcg2Event->Size = TcgEventSize;
132 Tcg2Event->Header.HeaderSize = sizeof (EFI_TCG2_EVENT_HEADER);
133 Tcg2Event->Header.HeaderVersion = EFI_TCG2_EVENT_HEADER_VERSION;
134 Tcg2Event->Header.PCRIndex = 5;
135@@ -310,7 +317,7 @@ Tcg2MeasureGptTable (
136 CcProtocol,
137 0,
138 (EFI_PHYSICAL_ADDRESS)(UINTN)(VOID *)GptData,
139- (UINT64)EventSize,
140+ (UINT64)TcgEventSize - OFFSET_OF (EFI_TCG2_EVENT, Event),
141 CcEvent
142 );
143 if (!EFI_ERROR (Status)) {
144@@ -326,7 +333,7 @@ Tcg2MeasureGptTable (
145 Tcg2Protocol,
146 0,
147 (EFI_PHYSICAL_ADDRESS)(UINTN)(VOID *)GptData,
148- (UINT64)EventSize,
149+ (UINT64)TcgEventSize - OFFSET_OF (EFI_TCG2_EVENT, Event),
150 Tcg2Event
151 );
152 if (!EFI_ERROR (Status)) {
153@@ -443,11 +450,13 @@ Tcg2MeasurePeImage (
154 Tcg2Event->Header.PCRIndex = 2;
155 break;
156 default:
157- DEBUG ((
158- DEBUG_ERROR,
159- "Tcg2MeasurePeImage: Unknown subsystem type %d",
160- ImageType
161- ));
162+ DEBUG (
163+ (
164+ DEBUG_ERROR,
165+ "Tcg2MeasurePeImage: Unknown subsystem type %d",
166+ ImageType
167+ )
168+ );
169 goto Finish;
170 }
171
172@@ -515,7 +524,7 @@ Finish:
173
174 @param MeasureBootProtocols Pointer to the located measure boot protocol instances.
175
176- @retval EFI_SUCCESS Sucessfully locate the measure boot protocol instances (at least one instance).
177+ @retval EFI_SUCCESS Successfully locate the measure boot protocol instances (at least one instance).
178 @retval EFI_UNSUPPORTED Measure boot is not supported.
179 **/
180 EFI_STATUS
181@@ -646,12 +655,14 @@ DxeTpm2MeasureBootHandler (
182 return EFI_SUCCESS;
183 }
184
185- DEBUG ((
186- DEBUG_INFO,
187- "Tcg2Protocol = %p, CcMeasurementProtocol = %p\n",
188- MeasureBootProtocols.Tcg2Protocol,
189- MeasureBootProtocols.CcProtocol
190- ));
191+ DEBUG (
192+ (
193+ DEBUG_INFO,
194+ "Tcg2Protocol = %p, CcMeasurementProtocol = %p\n",
195+ MeasureBootProtocols.Tcg2Protocol,
196+ MeasureBootProtocols.CcProtocol
197+ )
198+ );
199
200 //
201 // Copy File Device Path
202diff --git a/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.inf b/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.inf
203index 6dca79a20c..28995f438d 100644
204--- a/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.inf
205+++ b/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.inf
206@@ -37,6 +37,8 @@
207
208 [Sources]
209 DxeTpm2MeasureBootLib.c
210+ DxeTpm2MeasureBootLibSanitization.c
211+ DxeTpm2MeasureBootLibSanitization.h
212
213 [Packages]
214 MdePkg/MdePkg.dec
215@@ -46,6 +48,7 @@
216
217 [LibraryClasses]
218 BaseMemoryLib
219+ SafeIntLib
220 DebugLib
221 MemoryAllocationLib
222 DevicePathLib
223@@ -65,4 +68,3 @@
224 gEfiFirmwareVolumeBlockProtocolGuid ## SOMETIMES_CONSUMES
225 gEfiBlockIoProtocolGuid ## SOMETIMES_CONSUMES
226 gEfiDiskIoProtocolGuid ## SOMETIMES_CONSUMES
227-
228diff --git a/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLibSanitization.c b/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLibSanitization.c
229new file mode 100644
230index 0000000000..e2309655d3
231--- /dev/null
232+++ b/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLibSanitization.c
233@@ -0,0 +1,275 @@
234+/** @file
235+ The library instance provides security service of TPM2 measure boot and
236+ Confidential Computing (CC) measure boot.
237+
238+ Caution: This file requires additional review when modified.
239+ This library will have external input - PE/COFF image and GPT partition.
240+ This external input must be validated carefully to avoid security issue like
241+ buffer overflow, integer overflow.
242+
243+ This file will pull out the validation logic from the following functions, in an
244+ attempt to validate the untrusted input in the form of unit tests
245+
246+ These are those functions:
247+
248+ DxeTpm2MeasureBootLibImageRead() function will make sure the PE/COFF image content
249+ read is within the image buffer.
250+
251+ Tcg2MeasureGptTable() function will receive untrusted GPT partition table, and parse
252+ partition data carefully.
253+
254+ Copyright (c) Microsoft Corporation.<BR>
255+ SPDX-License-Identifier: BSD-2-Clause-Patent
256+**/
257+#include <Uefi.h>
258+#include <Uefi/UefiSpec.h>
259+#include <Library/SafeIntLib.h>
260+#include <Library/UefiLib.h>
261+#include <Library/DebugLib.h>
262+#include <Library/BaseLib.h>
263+#include <IndustryStandard/UefiTcgPlatform.h>
264+#include <Protocol/BlockIo.h>
265+#include <Library/MemoryAllocationLib.h>
266+
267+#include "DxeTpm2MeasureBootLibSanitization.h"
268+
269+#define GPT_HEADER_REVISION_V1 0x00010000
270+
271+/**
272+ This function will validate the EFI_PARTITION_TABLE_HEADER structure is safe to parse
273+ However this function will not attempt to verify the validity of the GPT partition
274+ It will check the following:
275+ - Signature
276+ - Revision
277+ - AlternateLBA
278+ - FirstUsableLBA
279+ - LastUsableLBA
280+ - PartitionEntryLBA
281+ - NumberOfPartitionEntries
282+ - SizeOfPartitionEntry
283+ - BlockIo
284+
285+ @param[in] PrimaryHeader
286+ Pointer to the EFI_PARTITION_TABLE_HEADER structure.
287+
288+ @param[in] BlockIo
289+ Pointer to the EFI_BLOCK_IO_PROTOCOL structure.
290+
291+ @retval EFI_SUCCESS
292+ The EFI_PARTITION_TABLE_HEADER structure is valid.
293+
294+ @retval EFI_INVALID_PARAMETER
295+ The EFI_PARTITION_TABLE_HEADER structure is invalid.
296+**/
297+EFI_STATUS
298+EFIAPI
299+SanitizeEfiPartitionTableHeader (
300+ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader,
301+ IN CONST EFI_BLOCK_IO_PROTOCOL *BlockIo
302+ )
303+{
304+ //
305+ // Verify that the input parameters are safe to use
306+ //
307+ if (PrimaryHeader == NULL) {
308+ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header!\n"));
309+ return EFI_INVALID_PARAMETER;
310+ }
311+
312+ if ((BlockIo == NULL) || (BlockIo->Media == NULL)) {
313+ DEBUG ((DEBUG_ERROR, "Invalid BlockIo!\n"));
314+ return EFI_INVALID_PARAMETER;
315+ }
316+
317+ //
318+ // The signature must be EFI_PTAB_HEADER_ID ("EFI PART" in ASCII)
319+ //
320+ if (PrimaryHeader->Header.Signature != EFI_PTAB_HEADER_ID) {
321+ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header!\n"));
322+ return EFI_DEVICE_ERROR;
323+ }
324+
325+ //
326+ // The version must be GPT_HEADER_REVISION_V1 (0x00010000)
327+ //
328+ if (PrimaryHeader->Header.Revision != GPT_HEADER_REVISION_V1) {
329+ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header Revision!\n"));
330+ return EFI_DEVICE_ERROR;
331+ }
332+
333+ //
334+ // The HeaderSize must be greater than or equal to 92 and must be less than or equal to the logical block size
335+ //
336+ if ((PrimaryHeader->Header.HeaderSize < sizeof (EFI_PARTITION_TABLE_HEADER)) || (PrimaryHeader->Header.HeaderSize > BlockIo->Media->BlockSize)) {
337+ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header HeaderSize!\n"));
338+ return EFI_DEVICE_ERROR;
339+ }
340+
341+ //
342+ // The partition entries should all be before the first usable block
343+ //
344+ if (PrimaryHeader->FirstUsableLBA <= PrimaryHeader->PartitionEntryLBA) {
345+ DEBUG ((DEBUG_ERROR, "GPT PartitionEntryLBA is not less than FirstUsableLBA!\n"));
346+ return EFI_DEVICE_ERROR;
347+ }
348+
349+ //
350+ // Check that the PartitionEntryLBA greater than the Max LBA
351+ // This will be used later for multiplication
352+ //
353+ if (PrimaryHeader->PartitionEntryLBA > DivU64x32 (MAX_UINT64, BlockIo->Media->BlockSize)) {
354+ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header PartitionEntryLBA!\n"));
355+ return EFI_DEVICE_ERROR;
356+ }
357+
358+ //
359+ // Check that the number of partition entries is greater than zero
360+ //
361+ if (PrimaryHeader->NumberOfPartitionEntries == 0) {
362+ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header NumberOfPartitionEntries!\n"));
363+ return EFI_DEVICE_ERROR;
364+ }
365+
366+ //
367+ // SizeOfPartitionEntry must be 128, 256, 512... improper size may lead to accessing uninitialized memory
368+ //
369+ if ((PrimaryHeader->SizeOfPartitionEntry < 128) || ((PrimaryHeader->SizeOfPartitionEntry & (PrimaryHeader->SizeOfPartitionEntry - 1)) != 0)) {
370+ DEBUG ((DEBUG_ERROR, "SizeOfPartitionEntry shall be set to a value of 128 x 2^n where n is an integer greater than or equal to zero (e.g., 128, 256, 512, etc.)!\n"));
371+ return EFI_DEVICE_ERROR;
372+ }
373+
374+ //
375+ // This check is to prevent overflow when calculating the allocation size for the partition entries
376+ // This check will be used later for multiplication
377+ //
378+ if (PrimaryHeader->NumberOfPartitionEntries > DivU64x32 (MAX_UINT64, PrimaryHeader->SizeOfPartitionEntry)) {
379+ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header NumberOfPartitionEntries!\n"));
380+ return EFI_DEVICE_ERROR;
381+ }
382+
383+ return EFI_SUCCESS;
384+}
385+
386+/**
387+ This function will validate that the allocation size from the primary header is sane
388+ It will check the following:
389+ - AllocationSize does not overflow
390+
391+ @param[in] PrimaryHeader
392+ Pointer to the EFI_PARTITION_TABLE_HEADER structure.
393+
394+ @param[out] AllocationSize
395+ Pointer to the allocation size.
396+
397+ @retval EFI_SUCCESS
398+ The allocation size is valid.
399+
400+ @retval EFI_OUT_OF_RESOURCES
401+ The allocation size is invalid.
402+**/
403+EFI_STATUS
404+EFIAPI
405+SanitizePrimaryHeaderAllocationSize (
406+ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader,
407+ OUT UINT32 *AllocationSize
408+ )
409+{
410+ EFI_STATUS Status;
411+
412+ if (PrimaryHeader == NULL) {
413+ return EFI_INVALID_PARAMETER;
414+ }
415+
416+ if (AllocationSize == NULL) {
417+ return EFI_INVALID_PARAMETER;
418+ }
419+
420+ //
421+ // Replacing logic:
422+ // PrimaryHeader->NumberOfPartitionEntries * PrimaryHeader->SizeOfPartitionEntry;
423+ //
424+ Status = SafeUint32Mult (PrimaryHeader->NumberOfPartitionEntries, PrimaryHeader->SizeOfPartitionEntry, AllocationSize);
425+ if (EFI_ERROR (Status)) {
426+ DEBUG ((DEBUG_ERROR, "Allocation Size would have overflowed!\n"));
427+ return EFI_BAD_BUFFER_SIZE;
428+ }
429+
430+ return EFI_SUCCESS;
431+}
432+
433+/**
434+ This function will validate that the Gpt Event Size calculated from the primary header is sane
435+ It will check the following:
436+ - EventSize does not overflow
437+
438+ Important: This function includes the entire length of the allocated space, including
439+ (sizeof (EFI_TCG2_EVENT) - sizeof (Tcg2Event->Event)) . When hashing the buffer allocated with this
440+ size, the caller must subtract the size of the (sizeof (EFI_TCG2_EVENT) - sizeof (Tcg2Event->Event))
441+ from the size of the buffer before hashing.
442+
443+ @param[in] PrimaryHeader - Pointer to the EFI_PARTITION_TABLE_HEADER structure.
444+ @param[in] NumberOfPartition - Number of partitions.
445+ @param[out] EventSize - Pointer to the event size.
446+
447+ @retval EFI_SUCCESS
448+ The event size is valid.
449+
450+ @retval EFI_OUT_OF_RESOURCES
451+ Overflow would have occurred.
452+
453+ @retval EFI_INVALID_PARAMETER
454+ One of the passed parameters was invalid.
455+**/
456+EFI_STATUS
457+SanitizePrimaryHeaderGptEventSize (
458+ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader,
459+ IN UINTN NumberOfPartition,
460+ OUT UINT32 *EventSize
461+ )
462+{
463+ EFI_STATUS Status;
464+ UINT32 SafeNumberOfPartitions;
465+
466+ if (PrimaryHeader == NULL) {
467+ return EFI_INVALID_PARAMETER;
468+ }
469+
470+ if (EventSize == NULL) {
471+ return EFI_INVALID_PARAMETER;
472+ }
473+
474+ //
475+ // We shouldn't even attempt to perform the multiplication if the number of partitions is greater than the maximum value of UINT32
476+ //
477+ Status = SafeUintnToUint32 (NumberOfPartition, &SafeNumberOfPartitions);
478+ if (EFI_ERROR (Status)) {
479+ DEBUG ((DEBUG_ERROR, "NumberOfPartition would have overflowed!\n"));
480+ return EFI_INVALID_PARAMETER;
481+ }
482+
483+ //
484+ // Replacing logic:
485+ // (UINT32)(sizeof (EFI_GPT_DATA) - sizeof (GptData->Partitions) + NumberOfPartition * PrimaryHeader.SizeOfPartitionEntry);
486+ //
487+ Status = SafeUint32Mult (SafeNumberOfPartitions, PrimaryHeader->SizeOfPartitionEntry, EventSize);
488+ if (EFI_ERROR (Status)) {
489+ DEBUG ((DEBUG_ERROR, "Event Size would have overflowed!\n"));
490+ return EFI_BAD_BUFFER_SIZE;
491+ }
492+
493+ //
494+ // Replacing logic:
495+ // *EventSize + sizeof (EFI_TCG2_EVENT) - sizeof (Tcg2Event->Event);
496+ //
497+ Status = SafeUint32Add (
498+ OFFSET_OF (EFI_TCG2_EVENT, Event) + OFFSET_OF (EFI_GPT_DATA, Partitions),
499+ *EventSize,
500+ EventSize
501+ );
502+ if (EFI_ERROR (Status)) {
503+ DEBUG ((DEBUG_ERROR, "Event Size would have overflowed because of GPTData!\n"));
504+ return EFI_BAD_BUFFER_SIZE;
505+ }
506+
507+ return EFI_SUCCESS;
508+}
509diff --git a/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLibSanitization.h b/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLibSanitization.h
510new file mode 100644
511index 0000000000..048b738987
512--- /dev/null
513+++ b/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLibSanitization.h
514@@ -0,0 +1,113 @@
515+/** @file
516+ This file includes the function prototypes for the sanitization functions.
517+
518+ These are those functions:
519+
520+ DxeTpm2MeasureBootLibImageRead() function will make sure the PE/COFF image content
521+ read is within the image buffer.
522+
523+ Tcg2MeasureGptTable() function will receive untrusted GPT partition table, and parse
524+ partition data carefully.
525+
526+ Copyright (c) Microsoft Corporation.<BR>
527+ SPDX-License-Identifier: BSD-2-Clause-Patent
528+
529+**/
530+
531+#ifndef DXE_TPM2_MEASURE_BOOT_LIB_SANITATION_
532+#define DXE_TPM2_MEASURE_BOOT_LIB_SANITATION_
533+
534+#include <Uefi.h>
535+#include <Uefi/UefiSpec.h>
536+#include <Protocol/BlockIo.h>
537+#include <IndustryStandard/UefiTcgPlatform.h>
538+#include <Protocol/Tcg2Protocol.h>
539+
540+/**
541+ This function will validate the EFI_PARTITION_TABLE_HEADER structure is safe to parse
542+ However this function will not attempt to verify the validity of the GPT partition
543+ It will check the following:
544+ - Signature
545+ - Revision
546+ - AlternateLBA
547+ - FirstUsableLBA
548+ - LastUsableLBA
549+ - PartitionEntryLBA
550+ - NumberOfPartitionEntries
551+ - SizeOfPartitionEntry
552+ - BlockIo
553+
554+ @param[in] PrimaryHeader
555+ Pointer to the EFI_PARTITION_TABLE_HEADER structure.
556+
557+ @param[in] BlockIo
558+ Pointer to the EFI_BLOCK_IO_PROTOCOL structure.
559+
560+ @retval EFI_SUCCESS
561+ The EFI_PARTITION_TABLE_HEADER structure is valid.
562+
563+ @retval EFI_INVALID_PARAMETER
564+ The EFI_PARTITION_TABLE_HEADER structure is invalid.
565+**/
566+EFI_STATUS
567+EFIAPI
568+SanitizeEfiPartitionTableHeader (
569+ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader,
570+ IN CONST EFI_BLOCK_IO_PROTOCOL *BlockIo
571+ );
572+
573+/**
574+ This function will validate that the allocation size from the primary header is sane
575+ It will check the following:
576+ - AllocationSize does not overflow
577+
578+ @param[in] PrimaryHeader
579+ Pointer to the EFI_PARTITION_TABLE_HEADER structure.
580+
581+ @param[out] AllocationSize
582+ Pointer to the allocation size.
583+
584+ @retval EFI_SUCCESS
585+ The allocation size is valid.
586+
587+ @retval EFI_OUT_OF_RESOURCES
588+ The allocation size is invalid.
589+**/
590+EFI_STATUS
591+EFIAPI
592+SanitizePrimaryHeaderAllocationSize (
593+ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader,
594+ OUT UINT32 *AllocationSize
595+ );
596+
597+/**
598+ This function will validate that the Gpt Event Size calculated from the primary header is sane
599+ It will check the following:
600+ - EventSize does not overflow
601+
602+ Important: This function includes the entire length of the allocated space, including
603+ (sizeof (EFI_TCG2_EVENT) - sizeof (Tcg2Event->Event)) . When hashing the buffer allocated with this
604+ size, the caller must subtract the size of the (sizeof (EFI_TCG2_EVENT) - sizeof (Tcg2Event->Event))
605+ from the size of the buffer before hashing.
606+
607+ @param[in] PrimaryHeader - Pointer to the EFI_PARTITION_TABLE_HEADER structure.
608+ @param[in] NumberOfPartition - Number of partitions.
609+ @param[out] EventSize - Pointer to the event size.
610+
611+ @retval EFI_SUCCESS
612+ The event size is valid.
613+
614+ @retval EFI_OUT_OF_RESOURCES
615+ Overflow would have occurred.
616+
617+ @retval EFI_INVALID_PARAMETER
618+ One of the passed parameters was invalid.
619+**/
620+EFI_STATUS
621+SanitizePrimaryHeaderGptEventSize (
622+ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader,
623+ IN UINTN NumberOfPartition,
624+ OUT UINT32 *EventSize
625+ );
626+
627+#endif // DXE_TPM2_MEASURE_BOOT_LIB_SANITATION_
628diff --git a/SecurityPkg/Library/DxeTpm2MeasureBootLib/InternalUnitTest/DxeTpm2MeasureBootLibSanitizationTest.c b/SecurityPkg/Library/DxeTpm2MeasureBootLib/InternalUnitTest/DxeTpm2MeasureBootLibSanitizationTest.c
629new file mode 100644
630index 0000000000..3eb9763e3c
631--- /dev/null
632+++ b/SecurityPkg/Library/DxeTpm2MeasureBootLib/InternalUnitTest/DxeTpm2MeasureBootLibSanitizationTest.c
633@@ -0,0 +1,303 @@
634+/** @file
635+ This file includes the unit test cases for the DxeTpm2MeasureBootLibSanitizationTest.c.
636+
637+ Copyright (c) Microsoft Corporation.<BR>
638+ SPDX-License-Identifier: BSD-2-Clause-Patent
639+**/
640+
641+#include <Uefi.h>
642+#include <Library/UefiLib.h>
643+#include <Library/DebugLib.h>
644+#include <Library/UnitTestLib.h>
645+#include <Protocol/BlockIo.h>
646+#include <Library/MemoryAllocationLib.h>
647+#include <Library/BaseMemoryLib.h>
648+#include <IndustryStandard/UefiTcgPlatform.h>
649+#include <Protocol/Tcg2Protocol.h>
650+
651+#include "../DxeTpm2MeasureBootLibSanitization.h"
652+
653+#define UNIT_TEST_NAME "DxeTpm2MeasureBootLibSanitizationTest"
654+#define UNIT_TEST_VERSION "1.0"
655+
656+#define DEFAULT_PRIMARY_TABLE_HEADER_REVISION 0x00010000
657+#define DEFAULT_PRIMARY_TABLE_HEADER_NUMBER_OF_PARTITION_ENTRIES 1
658+#define DEFAULT_PRIMARY_TABLE_HEADER_SIZE_OF_PARTITION_ENTRY 128
659+
660+/**
661+ This function tests the SanitizeEfiPartitionTableHeader function.
662+ It's intent is to test that a malicious EFI_PARTITION_TABLE_HEADER
663+ structure will not cause undefined or unexpected behavior.
664+
665+ In general the TPM should still be able to measure the data, but
666+ be the header should be sanitized to prevent any unexpected behavior.
667+
668+ @param[in] Context The unit test context.
669+
670+ @retval UNIT_TEST_PASSED The test passed.
671+ @retval UNIT_TEST_ERROR_TEST_FAILED The test failed.
672+**/
673+UNIT_TEST_STATUS
674+EFIAPI
675+TestSanitizeEfiPartitionTableHeader (
676+ IN UNIT_TEST_CONTEXT Context
677+ )
678+{
679+ EFI_STATUS Status;
680+ EFI_PARTITION_TABLE_HEADER PrimaryHeader;
681+ EFI_BLOCK_IO_PROTOCOL BlockIo;
682+ EFI_BLOCK_IO_MEDIA BlockMedia;
683+
684+ // Generate EFI_BLOCK_IO_MEDIA test data
685+ BlockMedia.MediaId = 1;
686+ BlockMedia.RemovableMedia = FALSE;
687+ BlockMedia.MediaPresent = TRUE;
688+ BlockMedia.LogicalPartition = FALSE;
689+ BlockMedia.ReadOnly = FALSE;
690+ BlockMedia.WriteCaching = FALSE;
691+ BlockMedia.BlockSize = 512;
692+ BlockMedia.IoAlign = 1;
693+ BlockMedia.LastBlock = 0;
694+
695+ // Generate EFI_BLOCK_IO_PROTOCOL test data
696+ BlockIo.Revision = 1;
697+ BlockIo.Media = &BlockMedia;
698+ BlockIo.Reset = NULL;
699+ BlockIo.ReadBlocks = NULL;
700+ BlockIo.WriteBlocks = NULL;
701+ BlockIo.FlushBlocks = NULL;
702+
703+ // Geneate EFI_PARTITION_TABLE_HEADER test data
704+ PrimaryHeader.Header.Signature = EFI_PTAB_HEADER_ID;
705+ PrimaryHeader.Header.Revision = DEFAULT_PRIMARY_TABLE_HEADER_REVISION;
706+ PrimaryHeader.Header.HeaderSize = sizeof (EFI_PARTITION_TABLE_HEADER);
707+ PrimaryHeader.MyLBA = 1;
708+ PrimaryHeader.AlternateLBA = 2;
709+ PrimaryHeader.FirstUsableLBA = 3;
710+ PrimaryHeader.LastUsableLBA = 4;
711+ PrimaryHeader.PartitionEntryLBA = 5;
712+ PrimaryHeader.NumberOfPartitionEntries = DEFAULT_PRIMARY_TABLE_HEADER_NUMBER_OF_PARTITION_ENTRIES;
713+ PrimaryHeader.SizeOfPartitionEntry = DEFAULT_PRIMARY_TABLE_HEADER_SIZE_OF_PARTITION_ENTRY;
714+ PrimaryHeader.PartitionEntryArrayCRC32 = 0; // Purposely invalid
715+
716+ // Calculate the CRC32 of the PrimaryHeader
717+ PrimaryHeader.Header.CRC32 = CalculateCrc32 ((UINT8 *)&PrimaryHeader, PrimaryHeader.Header.HeaderSize);
718+
719+ // Test that a normal PrimaryHeader passes validation
720+ Status = SanitizeEfiPartitionTableHeader (&PrimaryHeader, &BlockIo);
721+ UT_ASSERT_NOT_EFI_ERROR (Status);
722+
723+ // Test that when number of partition entries is 0, the function returns EFI_DEVICE_ERROR
724+ // Should print "Invalid Partition Table Header NumberOfPartitionEntries!""
725+ PrimaryHeader.NumberOfPartitionEntries = 0;
726+ Status = SanitizeEfiPartitionTableHeader (&PrimaryHeader, &BlockIo);
727+ UT_ASSERT_EQUAL (Status, EFI_DEVICE_ERROR);
728+ PrimaryHeader.NumberOfPartitionEntries = DEFAULT_PRIMARY_TABLE_HEADER_SIZE_OF_PARTITION_ENTRY;
729+
730+ // Test that when the header size is too small, the function returns EFI_DEVICE_ERROR
731+ // Should print "Invalid Partition Table Header Size!"
732+ PrimaryHeader.Header.HeaderSize = 0;
733+ Status = SanitizeEfiPartitionTableHeader (&PrimaryHeader, &BlockIo);
734+ UT_ASSERT_EQUAL (Status, EFI_DEVICE_ERROR);
735+ PrimaryHeader.Header.HeaderSize = sizeof (EFI_PARTITION_TABLE_HEADER);
736+
737+ // Test that when the SizeOfPartitionEntry is too small, the function returns EFI_DEVICE_ERROR
738+ // should print: "SizeOfPartitionEntry shall be set to a value of 128 x 2^n where n is an integer greater than or equal to zero (e.g., 128, 256, 512, etc.)!"
739+ PrimaryHeader.SizeOfPartitionEntry = 1;
740+ Status = SanitizeEfiPartitionTableHeader (&PrimaryHeader, &BlockIo);
741+ UT_ASSERT_EQUAL (Status, EFI_DEVICE_ERROR);
742+
743+ DEBUG ((DEBUG_INFO, "%a: Test passed\n", __func__));
744+
745+ return UNIT_TEST_PASSED;
746+}
747+
748+/**
749+ This function tests the SanitizePrimaryHeaderAllocationSize function.
750+ It's intent is to test that the untrusted input from a EFI_PARTITION_TABLE_HEADER
751+ structure will not cause an overflow when calculating the allocation size.
752+
753+ @param[in] Context The unit test context.
754+
755+ @retval UNIT_TEST_PASSED The test passed.
756+ @retval UNIT_TEST_ERROR_TEST_FAILED The test failed.
757+**/
758+UNIT_TEST_STATUS
759+EFIAPI
760+TestSanitizePrimaryHeaderAllocationSize (
761+ IN UNIT_TEST_CONTEXT Context
762+ )
763+{
764+ UINT32 AllocationSize;
765+
766+ EFI_STATUS Status;
767+ EFI_PARTITION_TABLE_HEADER PrimaryHeader;
768+
769+ // Test that a normal PrimaryHeader passes validation
770+ PrimaryHeader.NumberOfPartitionEntries = 5;
771+ PrimaryHeader.SizeOfPartitionEntry = DEFAULT_PRIMARY_TABLE_HEADER_SIZE_OF_PARTITION_ENTRY;
772+
773+ Status = SanitizePrimaryHeaderAllocationSize (&PrimaryHeader, &AllocationSize);
774+ UT_ASSERT_NOT_EFI_ERROR (Status);
775+
776+ // Test that the allocation size is correct compared to the existing logic
777+ UT_ASSERT_EQUAL (AllocationSize, PrimaryHeader.NumberOfPartitionEntries * PrimaryHeader.SizeOfPartitionEntry);
778+
779+ // Test that an overflow is detected
780+ PrimaryHeader.NumberOfPartitionEntries = MAX_UINT32;
781+ PrimaryHeader.SizeOfPartitionEntry = 5;
782+ Status = SanitizePrimaryHeaderAllocationSize (&PrimaryHeader, &AllocationSize);
783+ UT_ASSERT_EQUAL (Status, EFI_BAD_BUFFER_SIZE);
784+
785+ // Test the inverse
786+ PrimaryHeader.NumberOfPartitionEntries = 5;
787+ PrimaryHeader.SizeOfPartitionEntry = MAX_UINT32;
788+ Status = SanitizePrimaryHeaderAllocationSize (&PrimaryHeader, &AllocationSize);
789+ UT_ASSERT_EQUAL (Status, EFI_BAD_BUFFER_SIZE);
790+
791+ // Test the worst case scenario
792+ PrimaryHeader.NumberOfPartitionEntries = MAX_UINT32;
793+ PrimaryHeader.SizeOfPartitionEntry = MAX_UINT32;
794+ Status = SanitizePrimaryHeaderAllocationSize (&PrimaryHeader, &AllocationSize);
795+ UT_ASSERT_EQUAL (Status, EFI_BAD_BUFFER_SIZE);
796+
797+ DEBUG ((DEBUG_INFO, "%a: Test passed\n", __func__));
798+
799+ return UNIT_TEST_PASSED;
800+}
801+
802+/**
803+ This function tests the SanitizePrimaryHeaderGptEventSize function.
804+ It's intent is to test that the untrusted input from a EFI_GPT_DATA structure
805+ will not cause an overflow when calculating the event size.
806+
807+ @param[in] Context The unit test context.
808+
809+ @retval UNIT_TEST_PASSED The test passed.
810+ @retval UNIT_TEST_ERROR_TEST_FAILED The test failed.
811+**/
812+UNIT_TEST_STATUS
813+EFIAPI
814+TestSanitizePrimaryHeaderGptEventSize (
815+ IN UNIT_TEST_CONTEXT Context
816+ )
817+{
818+ UINT32 EventSize;
819+ UINT32 ExistingLogicEventSize;
820+ EFI_STATUS Status;
821+ EFI_PARTITION_TABLE_HEADER PrimaryHeader;
822+ UINTN NumberOfPartition;
823+ EFI_GPT_DATA *GptData;
824+ EFI_TCG2_EVENT *Tcg2Event;
825+
826+ Tcg2Event = NULL;
827+ GptData = NULL;
828+
829+ // Test that a normal PrimaryHeader passes validation
830+ PrimaryHeader.NumberOfPartitionEntries = 5;
831+ PrimaryHeader.SizeOfPartitionEntry = DEFAULT_PRIMARY_TABLE_HEADER_SIZE_OF_PARTITION_ENTRY;
832+
833+ // set the number of partitions
834+ NumberOfPartition = 13;
835+
836+ // that the primary event size is correct
837+ Status = SanitizePrimaryHeaderGptEventSize (&PrimaryHeader, NumberOfPartition, &EventSize);
838+ UT_ASSERT_NOT_EFI_ERROR (Status);
839+
840+ // Calculate the existing logic event size
841+ ExistingLogicEventSize = (UINT32)(OFFSET_OF (EFI_TCG2_EVENT, Event) + OFFSET_OF (EFI_GPT_DATA, Partitions)
842+ + NumberOfPartition * PrimaryHeader.SizeOfPartitionEntry);
843+
844+ // Check that the event size is correct
845+ UT_ASSERT_EQUAL (EventSize, ExistingLogicEventSize);
846+
847+ // Tests that the primary event size may not overflow
848+ Status = SanitizePrimaryHeaderGptEventSize (&PrimaryHeader, MAX_UINT32, &EventSize);
849+ UT_ASSERT_EQUAL (Status, EFI_BAD_BUFFER_SIZE);
850+
851+ // Test that the size of partition entries may not overflow
852+ PrimaryHeader.SizeOfPartitionEntry = MAX_UINT32;
853+ Status = SanitizePrimaryHeaderGptEventSize (&PrimaryHeader, NumberOfPartition, &EventSize);
854+ UT_ASSERT_EQUAL (Status, EFI_BAD_BUFFER_SIZE);
855+
856+ DEBUG ((DEBUG_INFO, "%a: Test passed\n", __func__));
857+
858+ return UNIT_TEST_PASSED;
859+}
860+
861+// *--------------------------------------------------------------------*
862+// * Unit Test Code Main Function
863+// *--------------------------------------------------------------------*
864+
865+/**
866+ This function acts as the entry point for the unit tests.
867+
868+ @retval UNIT_TEST_PASSED The test passed.
869+ @retval UNIT_TEST_ERROR_TEST_FAILED The test failed.
870+ @retval others The test failed.
871+**/
872+EFI_STATUS
873+EFIAPI
874+UefiTestMain (
875+ VOID
876+ )
877+{
878+ EFI_STATUS Status;
879+ UNIT_TEST_FRAMEWORK_HANDLE Framework;
880+ UNIT_TEST_SUITE_HANDLE Tcg2MeasureBootLibValidationTestSuite;
881+
882+ Framework = NULL;
883+
884+ DEBUG ((DEBUG_INFO, "%a: TestMain() - Start\n", UNIT_TEST_NAME));
885+
886+ Status = InitUnitTestFramework (&Framework, UNIT_TEST_NAME, gEfiCallerBaseName, UNIT_TEST_VERSION);
887+ if (EFI_ERROR (Status)) {
888+ DEBUG ((DEBUG_ERROR, "%a: Failed in InitUnitTestFramework. Status = %r\n", UNIT_TEST_NAME, Status));
889+ goto EXIT;
890+ }
891+
892+ Status = CreateUnitTestSuite (&Tcg2MeasureBootLibValidationTestSuite, Framework, "Tcg2MeasureBootLibValidationTestSuite", "Common.Tcg2MeasureBootLibValidation", NULL, NULL);
893+ if (EFI_ERROR (Status)) {
894+ DEBUG ((DEBUG_ERROR, "%s: Failed in CreateUnitTestSuite for Tcg2MeasureBootLibValidationTestSuite\n", UNIT_TEST_NAME));
895+ Status = EFI_OUT_OF_RESOURCES;
896+ goto EXIT;
897+ }
898+
899+ // -----------Suite---------------------------------Description----------------------------Class----------------------------------Test Function------------------------Pre---Clean-Context
900+ AddTestCase (Tcg2MeasureBootLibValidationTestSuite, "Tests Validating EFI Partition Table", "Common.Tcg2MeasureBootLibValidation", TestSanitizeEfiPartitionTableHeader, NULL, NULL, NULL);
901+ AddTestCase (Tcg2MeasureBootLibValidationTestSuite, "Tests Primary header gpt event checks for overflow", "Common.Tcg2MeasureBootLibValidation", TestSanitizePrimaryHeaderAllocationSize, NULL, NULL, NULL);
902+ AddTestCase (Tcg2MeasureBootLibValidationTestSuite, "Tests Primary header allocation size checks for overflow", "Common.Tcg2MeasureBootLibValidation", TestSanitizePrimaryHeaderGptEventSize, NULL, NULL, NULL);
903+
904+ Status = RunAllTestSuites (Framework);
905+
906+EXIT:
907+ if (Framework != NULL) {
908+ FreeUnitTestFramework (Framework);
909+ }
910+
911+ DEBUG ((DEBUG_INFO, "%a: TestMain() - End\n", UNIT_TEST_NAME));
912+ return Status;
913+}
914+
915+///
916+/// Avoid ECC error for function name that starts with lower case letter
917+///
918+#define DxeTpm2MeasureBootLibUnitTestMain main
919+
920+/**
921+ Standard POSIX C entry point for host based unit test execution.
922+
923+ @param[in] Argc Number of arguments
924+ @param[in] Argv Array of pointers to arguments
925+
926+ @retval 0 Success
927+ @retval other Error
928+**/
929+INT32
930+DxeTpm2MeasureBootLibUnitTestMain (
931+ IN INT32 Argc,
932+ IN CHAR8 *Argv[]
933+ )
934+{
935+ return (INT32)UefiTestMain ();
936+}
937diff --git a/SecurityPkg/Library/DxeTpm2MeasureBootLib/InternalUnitTest/DxeTpm2MeasureBootLibSanitizationTestHost.inf b/SecurityPkg/Library/DxeTpm2MeasureBootLib/InternalUnitTest/DxeTpm2MeasureBootLibSanitizationTestHost.inf
938new file mode 100644
939index 0000000000..2999aa2a44
940--- /dev/null
941+++ b/SecurityPkg/Library/DxeTpm2MeasureBootLib/InternalUnitTest/DxeTpm2MeasureBootLibSanitizationTestHost.inf
942@@ -0,0 +1,28 @@
943+## @file
944+# This file builds the unit tests for DxeTpm2MeasureBootLib
945+#
946+# Copyright (C) Microsoft Corporation.<BR>
947+# SPDX-License-Identifier: BSD-2-Clause-Patent
948+##
949+
950+[Defines]
951+ INF_VERSION = 0x00010006
952+ BASE_NAME = DxeTpm2MeasuredBootLibTest
953+ FILE_GUID = 144d757f-d423-484e-9309-a23695fad5bd
954+ MODULE_TYPE = HOST_APPLICATION
955+ VERSION_STRING = 1.0
956+ ENTRY_POINT = main
957+
958+[Sources]
959+ DxeTpm2MeasureBootLibSanitizationTest.c
960+ ../DxeTpm2MeasureBootLibSanitization.c
961+
962+[Packages]
963+ MdePkg/MdePkg.dec
964+
965+[LibraryClasses]
966+ BaseLib
967+ DebugLib
968+ UnitTestLib
969+ PrintLib
970+ SafeIntLib
971diff --git a/SecurityPkg/SecurityPkg.ci.yaml b/SecurityPkg/SecurityPkg.ci.yaml
972index 7912142398..da811fdf93 100644
973--- a/SecurityPkg/SecurityPkg.ci.yaml
974+++ b/SecurityPkg/SecurityPkg.ci.yaml
975@@ -15,6 +15,7 @@
976 ## "<ErrorID>", "<KeyWord>"
977 ## ]
978 "ExceptionList": [
979+ "8001", "DxeTpm2MeasureBootLibUnitTestMain",
980 ],
981 ## Both file path and directory path are accepted.
982 "IgnoreFiles": [
983--
9842.40.0
985
diff --git a/meta/recipes-core/ovmf/ovmf/CVE-2022-36763-0002.patch b/meta/recipes-core/ovmf/ovmf/CVE-2022-36763-0002.patch
new file mode 100644
index 0000000000..6c20cc305e
--- /dev/null
+++ b/meta/recipes-core/ovmf/ovmf/CVE-2022-36763-0002.patch
@@ -0,0 +1,889 @@
1From 4776a1b39ee08fc45c70c1eab5a0195f325000d3 Mon Sep 17 00:00:00 2001
2From: "Douglas Flick [MSFT]" <doug.edk2@gmail.com>
3Date: Fri, 12 Jan 2024 02:16:02 +0800
4Subject: [PATCH] SecurityPkg: DxeTpmMeasureBootLib: SECURITY PATCH 4117 - CVE
5 2022-36763
6
7This commit contains the patch files and tests for DxeTpmMeasureBootLib
8CVE 2022-36763.
9
10Cc: Jiewen Yao <jiewen.yao@intel.com>
11
12Signed-off-by: Doug Flick [MSFT] <doug.edk2@gmail.com>
13Reviewed-by: Jiewen Yao <jiewen.yao@intel.com>
14
15CVE: CVE-2022-36763
16
17Upstream-Status: Backport [https://github.com/tianocore/edk2/commit/4776a1b39ee08fc45c70c1eab5a0195f325000d3]
18
19Signed-off-by: Soumya Sambu <soumya.sambu@windriver.com>
20---
21 .../DxeTpmMeasureBootLib.c | 40 ++-
22 .../DxeTpmMeasureBootLib.inf | 4 +-
23 .../DxeTpmMeasureBootLibSanitization.c | 241 ++++++++++++++
24 .../DxeTpmMeasureBootLibSanitization.h | 114 +++++++
25 .../DxeTpmMeasureBootLibSanitizationTest.c | 301 ++++++++++++++++++
26 ...eTpmMeasureBootLibSanitizationTestHost.inf | 28 ++
27 SecurityPkg/SecurityPkg.ci.yaml | 1 +
28 7 files changed, 715 insertions(+), 14 deletions(-)
29 create mode 100644 SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLibSanitization.c
30 create mode 100644 SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLibSanitization.h
31 create mode 100644 SecurityPkg/Library/DxeTpmMeasureBootLib/InternalUnitTest/DxeTpmMeasureBootLibSanitizationTest.c
32 create mode 100644 SecurityPkg/Library/DxeTpmMeasureBootLib/InternalUnitTest/DxeTpmMeasureBootLibSanitizationTestHost.inf
33
34diff --git a/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.c b/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.c
35index 220393dd2b..669ab19134 100644
36--- a/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.c
37+++ b/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.c
38@@ -18,6 +18,8 @@
39 Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
40 SPDX-License-Identifier: BSD-2-Clause-Patent
41
42+Copyright (c) Microsoft Corporation.<BR>
43+SPDX-License-Identifier: BSD-2-Clause-Patent
44 **/
45
46 #include <PiDxe.h>
47@@ -40,6 +42,8 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
48 #include <Library/SecurityManagementLib.h>
49 #include <Library/HobLib.h>
50
51+#include "DxeTpmMeasureBootLibSanitization.h"
52+
53 //
54 // Flag to check GPT partition. It only need be measured once.
55 //
56@@ -136,6 +140,9 @@ TcgMeasureGptTable (
57 UINT32 EventSize;
58 UINT32 EventNumber;
59 EFI_PHYSICAL_ADDRESS EventLogLastEntry;
60+ UINT32 AllocSize;
61+
62+ GptData = NULL;
63
64 if (mMeasureGptCount > 0) {
65 return EFI_SUCCESS;
66@@ -166,8 +173,8 @@ TcgMeasureGptTable (
67 BlockIo->Media->BlockSize,
68 (UINT8 *)PrimaryHeader
69 );
70- if (EFI_ERROR (Status)) {
71- DEBUG ((DEBUG_ERROR, "Failed to Read Partition Table Header!\n"));
72+ if (EFI_ERROR (Status) || EFI_ERROR (SanitizeEfiPartitionTableHeader (PrimaryHeader, BlockIo))) {
73+ DEBUG ((DEBUG_ERROR, "Failed to read Partition Table Header or invalid Partition Table Header!\n"));
74 FreePool (PrimaryHeader);
75 return EFI_DEVICE_ERROR;
76 }
77@@ -175,7 +182,13 @@ TcgMeasureGptTable (
78 //
79 // Read the partition entry.
80 //
81- EntryPtr = (UINT8 *)AllocatePool (PrimaryHeader->NumberOfPartitionEntries * PrimaryHeader->SizeOfPartitionEntry);
82+ Status = SanitizePrimaryHeaderAllocationSize (PrimaryHeader, &AllocSize);
83+ if (EFI_ERROR (Status)) {
84+ FreePool (PrimaryHeader);
85+ return EFI_DEVICE_ERROR;
86+ }
87+
88+ EntryPtr = (UINT8 *)AllocatePool (AllocSize);
89 if (EntryPtr == NULL) {
90 FreePool (PrimaryHeader);
91 return EFI_OUT_OF_RESOURCES;
92@@ -185,7 +198,7 @@ TcgMeasureGptTable (
93 DiskIo,
94 BlockIo->Media->MediaId,
95 MultU64x32 (PrimaryHeader->PartitionEntryLBA, BlockIo->Media->BlockSize),
96- PrimaryHeader->NumberOfPartitionEntries * PrimaryHeader->SizeOfPartitionEntry,
97+ AllocSize,
98 EntryPtr
99 );
100 if (EFI_ERROR (Status)) {
101@@ -210,9 +223,8 @@ TcgMeasureGptTable (
102 //
103 // Prepare Data for Measurement
104 //
105- EventSize = (UINT32)(sizeof (EFI_GPT_DATA) - sizeof (GptData->Partitions)
106- + NumberOfPartition * PrimaryHeader->SizeOfPartitionEntry);
107- TcgEvent = (TCG_PCR_EVENT *)AllocateZeroPool (EventSize + sizeof (TCG_PCR_EVENT_HDR));
108+ Status = SanitizePrimaryHeaderGptEventSize (PrimaryHeader, NumberOfPartition, &EventSize);
109+ TcgEvent = (TCG_PCR_EVENT *)AllocateZeroPool (EventSize);
110 if (TcgEvent == NULL) {
111 FreePool (PrimaryHeader);
112 FreePool (EntryPtr);
113@@ -221,7 +233,7 @@ TcgMeasureGptTable (
114
115 TcgEvent->PCRIndex = 5;
116 TcgEvent->EventType = EV_EFI_GPT_EVENT;
117- TcgEvent->EventSize = EventSize;
118+ TcgEvent->EventSize = EventSize - sizeof (TCG_PCR_EVENT_HDR);
119 GptData = (EFI_GPT_DATA *)TcgEvent->Event;
120
121 //
122@@ -361,11 +373,13 @@ TcgMeasurePeImage (
123 TcgEvent->PCRIndex = 2;
124 break;
125 default:
126- DEBUG ((
127- DEBUG_ERROR,
128- "TcgMeasurePeImage: Unknown subsystem type %d",
129- ImageType
130- ));
131+ DEBUG (
132+ (
133+ DEBUG_ERROR,
134+ "TcgMeasurePeImage: Unknown subsystem type %d",
135+ ImageType
136+ )
137+ );
138 goto Finish;
139 }
140
141diff --git a/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.inf b/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.inf
142index ebab6f7c1e..414c654d15 100644
143--- a/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.inf
144+++ b/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.inf
145@@ -32,6 +32,8 @@
146
147 [Sources]
148 DxeTpmMeasureBootLib.c
149+ DxeTpmMeasureBootLibSanitization.c
150+ DxeTpmMeasureBootLibSanitization.h
151
152 [Packages]
153 MdePkg/MdePkg.dec
154@@ -41,6 +43,7 @@
155
156 [LibraryClasses]
157 BaseMemoryLib
158+ SafeIntLib
159 DebugLib
160 MemoryAllocationLib
161 DevicePathLib
162@@ -59,4 +62,3 @@
163 gEfiFirmwareVolumeBlockProtocolGuid ## SOMETIMES_CONSUMES
164 gEfiBlockIoProtocolGuid ## SOMETIMES_CONSUMES
165 gEfiDiskIoProtocolGuid ## SOMETIMES_CONSUMES
166-
167diff --git a/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLibSanitization.c b/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLibSanitization.c
168new file mode 100644
169index 0000000000..a3fa46f5e6
170--- /dev/null
171+++ b/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLibSanitization.c
172@@ -0,0 +1,241 @@
173+/** @file
174+ The library instance provides security service of TPM2 measure boot and
175+ Confidential Computing (CC) measure boot.
176+
177+ Caution: This file requires additional review when modified.
178+ This library will have external input - PE/COFF image and GPT partition.
179+ This external input must be validated carefully to avoid security issue like
180+ buffer overflow, integer overflow.
181+
182+ This file will pull out the validation logic from the following functions, in an
183+ attempt to validate the untrusted input in the form of unit tests
184+
185+ These are those functions:
186+
187+ DxeTpmMeasureBootLibImageRead() function will make sure the PE/COFF image content
188+ read is within the image buffer.
189+
190+ Tcg2MeasureGptTable() function will receive untrusted GPT partition table, and parse
191+ partition data carefully.
192+
193+ Copyright (c) Microsoft Corporation.<BR>
194+ SPDX-License-Identifier: BSD-2-Clause-Patent
195+**/
196+#include <Uefi.h>
197+#include <Uefi/UefiSpec.h>
198+#include <Library/SafeIntLib.h>
199+#include <Library/UefiLib.h>
200+#include <Library/DebugLib.h>
201+#include <Library/BaseLib.h>
202+#include <IndustryStandard/UefiTcgPlatform.h>
203+#include <Protocol/BlockIo.h>
204+#include <Library/MemoryAllocationLib.h>
205+
206+#include "DxeTpmMeasureBootLibSanitization.h"
207+
208+#define GPT_HEADER_REVISION_V1 0x00010000
209+
210+/**
211+ This function will validate the EFI_PARTITION_TABLE_HEADER structure is safe to parse
212+ However this function will not attempt to verify the validity of the GPT partition
213+ It will check the following:
214+ - Signature
215+ - Revision
216+ - AlternateLBA
217+ - FirstUsableLBA
218+ - LastUsableLBA
219+ - PartitionEntryLBA
220+ - NumberOfPartitionEntries
221+ - SizeOfPartitionEntry
222+ - BlockIo
223+
224+ @param[in] PrimaryHeader
225+ Pointer to the EFI_PARTITION_TABLE_HEADER structure.
226+
227+ @param[in] BlockIo
228+ Pointer to the EFI_BLOCK_IO_PROTOCOL structure.
229+
230+ @retval EFI_SUCCESS
231+ The EFI_PARTITION_TABLE_HEADER structure is valid.
232+
233+ @retval EFI_INVALID_PARAMETER
234+ The EFI_PARTITION_TABLE_HEADER structure is invalid.
235+**/
236+EFI_STATUS
237+EFIAPI
238+SanitizeEfiPartitionTableHeader (
239+ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader,
240+ IN CONST EFI_BLOCK_IO_PROTOCOL *BlockIo
241+ )
242+{
243+ // Verify that the input parameters are safe to use
244+ if (PrimaryHeader == NULL) {
245+ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header!\n"));
246+ return EFI_INVALID_PARAMETER;
247+ }
248+
249+ if ((BlockIo == NULL) || (BlockIo->Media == NULL)) {
250+ DEBUG ((DEBUG_ERROR, "Invalid BlockIo!\n"));
251+ return EFI_INVALID_PARAMETER;
252+ }
253+
254+ // The signature must be EFI_PTAB_HEADER_ID ("EFI PART" in ASCII)
255+ if (PrimaryHeader->Header.Signature != EFI_PTAB_HEADER_ID) {
256+ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header!\n"));
257+ return EFI_DEVICE_ERROR;
258+ }
259+
260+ // The version must be GPT_HEADER_REVISION_V1 (0x00010000)
261+ if (PrimaryHeader->Header.Revision != GPT_HEADER_REVISION_V1) {
262+ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header Revision!\n"));
263+ return EFI_DEVICE_ERROR;
264+ }
265+
266+ // The HeaderSize must be greater than or equal to 92 and must be less than or equal to the logical block size
267+ if ((PrimaryHeader->Header.HeaderSize < sizeof (EFI_PARTITION_TABLE_HEADER)) || (PrimaryHeader->Header.HeaderSize > BlockIo->Media->BlockSize)) {
268+ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header HeaderSize!\n"));
269+ return EFI_DEVICE_ERROR;
270+ }
271+
272+ // check that the PartitionEntryLBA greater than the Max LBA
273+ // This will be used later for multiplication
274+ if (PrimaryHeader->PartitionEntryLBA > DivU64x32 (MAX_UINT64, BlockIo->Media->BlockSize)) {
275+ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header PartitionEntryLBA!\n"));
276+ return EFI_DEVICE_ERROR;
277+ }
278+
279+ // Check that the number of partition entries is greater than zero
280+ if (PrimaryHeader->NumberOfPartitionEntries == 0) {
281+ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header NumberOfPartitionEntries!\n"));
282+ return EFI_DEVICE_ERROR;
283+ }
284+
285+ // SizeOfPartitionEntry must be 128, 256, 512... improper size may lead to accessing uninitialized memory
286+ if ((PrimaryHeader->SizeOfPartitionEntry < 128) || ((PrimaryHeader->SizeOfPartitionEntry & (PrimaryHeader->SizeOfPartitionEntry - 1)) != 0)) {
287+ DEBUG ((DEBUG_ERROR, "SizeOfPartitionEntry shall be set to a value of 128 x 2^n where n is an integer greater than or equal to zero (e.g., 128, 256, 512, etc.)!\n"));
288+ return EFI_DEVICE_ERROR;
289+ }
290+
291+ // This check is to prevent overflow when calculating the allocation size for the partition entries
292+ // This check will be used later for multiplication
293+ if (PrimaryHeader->NumberOfPartitionEntries > DivU64x32 (MAX_UINT64, PrimaryHeader->SizeOfPartitionEntry)) {
294+ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header NumberOfPartitionEntries!\n"));
295+ return EFI_DEVICE_ERROR;
296+ }
297+
298+ return EFI_SUCCESS;
299+}
300+
301+/**
302+ This function will validate that the allocation size from the primary header is sane
303+ It will check the following:
304+ - AllocationSize does not overflow
305+
306+ @param[in] PrimaryHeader
307+ Pointer to the EFI_PARTITION_TABLE_HEADER structure.
308+
309+ @param[out] AllocationSize
310+ Pointer to the allocation size.
311+
312+ @retval EFI_SUCCESS
313+ The allocation size is valid.
314+
315+ @retval EFI_OUT_OF_RESOURCES
316+ The allocation size is invalid.
317+**/
318+EFI_STATUS
319+EFIAPI
320+SanitizePrimaryHeaderAllocationSize (
321+ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader,
322+ OUT UINT32 *AllocationSize
323+ )
324+{
325+ EFI_STATUS Status;
326+
327+ if (PrimaryHeader == NULL) {
328+ return EFI_INVALID_PARAMETER;
329+ }
330+
331+ if (AllocationSize == NULL) {
332+ return EFI_INVALID_PARAMETER;
333+ }
334+
335+ // Replacing logic:
336+ // PrimaryHeader->NumberOfPartitionEntries * PrimaryHeader->SizeOfPartitionEntry;
337+ Status = SafeUint32Mult (PrimaryHeader->NumberOfPartitionEntries, PrimaryHeader->SizeOfPartitionEntry, AllocationSize);
338+ if (EFI_ERROR (Status)) {
339+ DEBUG ((DEBUG_ERROR, "Allocation Size would have overflowed!\n"));
340+ return EFI_BAD_BUFFER_SIZE;
341+ }
342+
343+ return EFI_SUCCESS;
344+}
345+
346+/**
347+ This function will validate that the Gpt Event Size calculated from the primary header is sane
348+ It will check the following:
349+ - EventSize does not overflow
350+
351+ Important: This function includes the entire length of the allocated space, including the
352+ TCG_PCR_EVENT_HDR. When hashing the buffer allocated with this size, the caller must subtract
353+ the size of the TCG_PCR_EVENT_HDR from the size of the buffer before hashing.
354+
355+ @param[in] PrimaryHeader - Pointer to the EFI_PARTITION_TABLE_HEADER structure.
356+ @param[in] NumberOfPartition - Number of partitions.
357+ @param[out] EventSize - Pointer to the event size.
358+
359+ @retval EFI_SUCCESS
360+ The event size is valid.
361+
362+ @retval EFI_OUT_OF_RESOURCES
363+ Overflow would have occurred.
364+
365+ @retval EFI_INVALID_PARAMETER
366+ One of the passed parameters was invalid.
367+**/
368+EFI_STATUS
369+SanitizePrimaryHeaderGptEventSize (
370+ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader,
371+ IN UINTN NumberOfPartition,
372+ OUT UINT32 *EventSize
373+ )
374+{
375+ EFI_STATUS Status;
376+ UINT32 SafeNumberOfPartitions;
377+
378+ if (PrimaryHeader == NULL) {
379+ return EFI_INVALID_PARAMETER;
380+ }
381+
382+ if (EventSize == NULL) {
383+ return EFI_INVALID_PARAMETER;
384+ }
385+
386+ // We shouldn't even attempt to perform the multiplication if the number of partitions is greater than the maximum value of UINT32
387+ Status = SafeUintnToUint32 (NumberOfPartition, &SafeNumberOfPartitions);
388+ if (EFI_ERROR (Status)) {
389+ DEBUG ((DEBUG_ERROR, "NumberOfPartition would have overflowed!\n"));
390+ return EFI_INVALID_PARAMETER;
391+ }
392+
393+ // Replacing logic:
394+ // (UINT32)(sizeof (EFI_GPT_DATA) - sizeof (GptData->Partitions) + NumberOfPartition * PrimaryHeader.SizeOfPartitionEntry + sizeof (TCG_PCR_EVENT_HDR));
395+ Status = SafeUint32Mult (SafeNumberOfPartitions, PrimaryHeader->SizeOfPartitionEntry, EventSize);
396+ if (EFI_ERROR (Status)) {
397+ DEBUG ((DEBUG_ERROR, "Event Size would have overflowed!\n"));
398+ return EFI_BAD_BUFFER_SIZE;
399+ }
400+
401+ Status = SafeUint32Add (
402+ sizeof (TCG_PCR_EVENT_HDR) +
403+ OFFSET_OF (EFI_GPT_DATA, Partitions),
404+ *EventSize,
405+ EventSize
406+ );
407+ if (EFI_ERROR (Status)) {
408+ DEBUG ((DEBUG_ERROR, "Event Size would have overflowed because of GPTData!\n"));
409+ return EFI_BAD_BUFFER_SIZE;
410+ }
411+
412+ return EFI_SUCCESS;
413+}
414diff --git a/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLibSanitization.h b/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLibSanitization.h
415new file mode 100644
416index 0000000000..0d9d00c281
417--- /dev/null
418+++ b/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLibSanitization.h
419@@ -0,0 +1,114 @@
420+/** @file
421+ This file includes the function prototypes for the sanitization functions.
422+
423+ These are those functions:
424+
425+ DxeTpmMeasureBootLibImageRead() function will make sure the PE/COFF image content
426+ read is within the image buffer.
427+
428+ TcgMeasurePeImage() function will accept untrusted PE/COFF image and validate its
429+ data structure within this image buffer before use.
430+
431+ TcgMeasureGptTable() function will receive untrusted GPT partition table, and parse
432+ partition data carefully.
433+
434+ Copyright (c) Microsoft Corporation.<BR>
435+ SPDX-License-Identifier: BSD-2-Clause-Patent
436+
437+**/
438+
439+#ifndef DXE_TPM_MEASURE_BOOT_LIB_VALIDATION_
440+#define DXE_TPM_MEASURE_BOOT_LIB_VALIDATION_
441+
442+#include <Uefi.h>
443+#include <Uefi/UefiSpec.h>
444+#include <Protocol/BlockIo.h>
445+#include <IndustryStandard/UefiTcgPlatform.h>
446+
447+/**
448+ This function will validate the EFI_PARTITION_TABLE_HEADER structure is safe to parse
449+ However this function will not attempt to verify the validity of the GPT partition
450+ It will check the following:
451+ - Signature
452+ - Revision
453+ - AlternateLBA
454+ - FirstUsableLBA
455+ - LastUsableLBA
456+ - PartitionEntryLBA
457+ - NumberOfPartitionEntries
458+ - SizeOfPartitionEntry
459+ - BlockIo
460+
461+ @param[in] PrimaryHeader
462+ Pointer to the EFI_PARTITION_TABLE_HEADER structure.
463+
464+ @param[in] BlockIo
465+ Pointer to the EFI_BLOCK_IO_PROTOCOL structure.
466+
467+ @retval EFI_SUCCESS
468+ The EFI_PARTITION_TABLE_HEADER structure is valid.
469+
470+ @retval EFI_INVALID_PARAMETER
471+ The EFI_PARTITION_TABLE_HEADER structure is invalid.
472+**/
473+EFI_STATUS
474+EFIAPI
475+SanitizeEfiPartitionTableHeader (
476+ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader,
477+ IN CONST EFI_BLOCK_IO_PROTOCOL *BlockIo
478+ );
479+
480+/**
481+ This function will validate that the allocation size from the primary header is sane
482+ It will check the following:
483+ - AllocationSize does not overflow
484+
485+ @param[in] PrimaryHeader
486+ Pointer to the EFI_PARTITION_TABLE_HEADER structure.
487+
488+ @param[out] AllocationSize
489+ Pointer to the allocation size.
490+
491+ @retval EFI_SUCCESS
492+ The allocation size is valid.
493+
494+ @retval EFI_OUT_OF_RESOURCES
495+ The allocation size is invalid.
496+**/
497+EFI_STATUS
498+EFIAPI
499+SanitizePrimaryHeaderAllocationSize (
500+ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader,
501+ OUT UINT32 *AllocationSize
502+ );
503+
504+/**
505+ This function will validate that the Gpt Event Size calculated from the primary header is sane
506+ It will check the following:
507+ - EventSize does not overflow
508+
509+ Important: This function includes the entire length of the allocated space, including the
510+ TCG_PCR_EVENT_HDR. When hashing the buffer allocated with this size, the caller must subtract
511+ the size of the TCG_PCR_EVENT_HDR from the size of the buffer before hashing.
512+
513+ @param[in] PrimaryHeader - Pointer to the EFI_PARTITION_TABLE_HEADER structure.
514+ @param[in] NumberOfPartition - Number of partitions.
515+ @param[out] EventSize - Pointer to the event size.
516+
517+ @retval EFI_SUCCESS
518+ The event size is valid.
519+
520+ @retval EFI_OUT_OF_RESOURCES
521+ Overflow would have occurred.
522+
523+ @retval EFI_INVALID_PARAMETER
524+ One of the passed parameters was invalid.
525+**/
526+EFI_STATUS
527+SanitizePrimaryHeaderGptEventSize (
528+ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader,
529+ IN UINTN NumberOfPartition,
530+ OUT UINT32 *EventSize
531+ );
532+
533+#endif // DXE_TPM_MEASURE_BOOT_LIB_VALIDATION_
534diff --git a/SecurityPkg/Library/DxeTpmMeasureBootLib/InternalUnitTest/DxeTpmMeasureBootLibSanitizationTest.c b/SecurityPkg/Library/DxeTpmMeasureBootLib/InternalUnitTest/DxeTpmMeasureBootLibSanitizationTest.c
535new file mode 100644
536index 0000000000..eeb928cdb0
537--- /dev/null
538+++ b/SecurityPkg/Library/DxeTpmMeasureBootLib/InternalUnitTest/DxeTpmMeasureBootLibSanitizationTest.c
539@@ -0,0 +1,301 @@
540+/** @file
541+This file includes the unit test cases for the DxeTpmMeasureBootLibSanitizationTest.c.
542+
543+Copyright (c) Microsoft Corporation.<BR>
544+SPDX-License-Identifier: BSD-2-Clause-Patent
545+**/
546+
547+#include <Uefi.h>
548+#include <Library/UefiLib.h>
549+#include <Library/DebugLib.h>
550+#include <Library/UnitTestLib.h>
551+#include <Protocol/BlockIo.h>
552+#include <Library/MemoryAllocationLib.h>
553+#include <Library/BaseMemoryLib.h>
554+#include <IndustryStandard/UefiTcgPlatform.h>
555+
556+#include "../DxeTpmMeasureBootLibSanitization.h"
557+
558+#define UNIT_TEST_NAME "DxeTpmMeasureBootLibSanitizationTest"
559+#define UNIT_TEST_VERSION "1.0"
560+
561+#define DEFAULT_PRIMARY_TABLE_HEADER_REVISION 0x00010000
562+#define DEFAULT_PRIMARY_TABLE_HEADER_NUMBER_OF_PARTITION_ENTRIES 1
563+#define DEFAULT_PRIMARY_TABLE_HEADER_SIZE_OF_PARTITION_ENTRY 128
564+
565+/**
566+ This function tests the SanitizeEfiPartitionTableHeader function.
567+ It's intent is to test that a malicious EFI_PARTITION_TABLE_HEADER
568+ structure will not cause undefined or unexpected behavior.
569+
570+ In general the TPM should still be able to measure the data, but
571+ be the header should be sanitized to prevent any unexpected behavior.
572+
573+ @param[in] Context The unit test context.
574+
575+ @retval UNIT_TEST_PASSED The test passed.
576+ @retval UNIT_TEST_ERROR_TEST_FAILED The test failed.
577+**/
578+UNIT_TEST_STATUS
579+EFIAPI
580+TestSanitizeEfiPartitionTableHeader (
581+ IN UNIT_TEST_CONTEXT Context
582+ )
583+{
584+ EFI_STATUS Status;
585+ EFI_PARTITION_TABLE_HEADER PrimaryHeader;
586+ EFI_BLOCK_IO_PROTOCOL BlockIo;
587+ EFI_BLOCK_IO_MEDIA BlockMedia;
588+
589+ // Generate EFI_BLOCK_IO_MEDIA test data
590+ BlockMedia.MediaId = 1;
591+ BlockMedia.RemovableMedia = FALSE;
592+ BlockMedia.MediaPresent = TRUE;
593+ BlockMedia.LogicalPartition = FALSE;
594+ BlockMedia.ReadOnly = FALSE;
595+ BlockMedia.WriteCaching = FALSE;
596+ BlockMedia.BlockSize = 512;
597+ BlockMedia.IoAlign = 1;
598+ BlockMedia.LastBlock = 0;
599+
600+ // Generate EFI_BLOCK_IO_PROTOCOL test data
601+ BlockIo.Revision = 1;
602+ BlockIo.Media = &BlockMedia;
603+ BlockIo.Reset = NULL;
604+ BlockIo.ReadBlocks = NULL;
605+ BlockIo.WriteBlocks = NULL;
606+ BlockIo.FlushBlocks = NULL;
607+
608+ // Geneate EFI_PARTITION_TABLE_HEADER test data
609+ PrimaryHeader.Header.Signature = EFI_PTAB_HEADER_ID;
610+ PrimaryHeader.Header.Revision = DEFAULT_PRIMARY_TABLE_HEADER_REVISION;
611+ PrimaryHeader.Header.HeaderSize = sizeof (EFI_PARTITION_TABLE_HEADER);
612+ PrimaryHeader.MyLBA = 1;
613+ PrimaryHeader.AlternateLBA = 2;
614+ PrimaryHeader.FirstUsableLBA = 3;
615+ PrimaryHeader.LastUsableLBA = 4;
616+ PrimaryHeader.PartitionEntryLBA = 5;
617+ PrimaryHeader.NumberOfPartitionEntries = DEFAULT_PRIMARY_TABLE_HEADER_NUMBER_OF_PARTITION_ENTRIES;
618+ PrimaryHeader.SizeOfPartitionEntry = DEFAULT_PRIMARY_TABLE_HEADER_SIZE_OF_PARTITION_ENTRY;
619+ PrimaryHeader.PartitionEntryArrayCRC32 = 0; // Purposely invalid
620+
621+ // Calculate the CRC32 of the PrimaryHeader
622+ PrimaryHeader.Header.CRC32 = CalculateCrc32 ((UINT8 *)&PrimaryHeader, PrimaryHeader.Header.HeaderSize);
623+
624+ // Test that a normal PrimaryHeader passes validation
625+ Status = SanitizeEfiPartitionTableHeader (&PrimaryHeader, &BlockIo);
626+ UT_ASSERT_NOT_EFI_ERROR (Status);
627+
628+ // Test that when number of partition entries is 0, the function returns EFI_DEVICE_ERROR
629+ // Should print "Invalid Partition Table Header NumberOfPartitionEntries!""
630+ PrimaryHeader.NumberOfPartitionEntries = 0;
631+ Status = SanitizeEfiPartitionTableHeader (&PrimaryHeader, &BlockIo);
632+ UT_ASSERT_EQUAL (Status, EFI_DEVICE_ERROR);
633+ PrimaryHeader.NumberOfPartitionEntries = DEFAULT_PRIMARY_TABLE_HEADER_SIZE_OF_PARTITION_ENTRY;
634+
635+ // Test that when the header size is too small, the function returns EFI_DEVICE_ERROR
636+ // Should print "Invalid Partition Table Header Size!"
637+ PrimaryHeader.Header.HeaderSize = 0;
638+ Status = SanitizeEfiPartitionTableHeader (&PrimaryHeader, &BlockIo);
639+ UT_ASSERT_EQUAL (Status, EFI_DEVICE_ERROR);
640+ PrimaryHeader.Header.HeaderSize = sizeof (EFI_PARTITION_TABLE_HEADER);
641+
642+ // Test that when the SizeOfPartitionEntry is too small, the function returns EFI_DEVICE_ERROR
643+ // should print: "SizeOfPartitionEntry shall be set to a value of 128 x 2^n where n is an integer greater than or equal to zero (e.g., 128, 256, 512, etc.)!"
644+ PrimaryHeader.SizeOfPartitionEntry = 1;
645+ Status = SanitizeEfiPartitionTableHeader (&PrimaryHeader, &BlockIo);
646+ UT_ASSERT_EQUAL (Status, EFI_DEVICE_ERROR);
647+
648+ DEBUG ((DEBUG_INFO, "%a: Test passed\n", __func__));
649+
650+ return UNIT_TEST_PASSED;
651+}
652+
653+/**
654+ This function tests the SanitizePrimaryHeaderAllocationSize function.
655+ It's intent is to test that the untrusted input from a EFI_PARTITION_TABLE_HEADER
656+ structure will not cause an overflow when calculating the allocation size.
657+
658+ @param[in] Context The unit test context.
659+
660+ @retval UNIT_TEST_PASSED The test passed.
661+ @retval UNIT_TEST_ERROR_TEST_FAILED The test failed.
662+**/
663+UNIT_TEST_STATUS
664+EFIAPI
665+TestSanitizePrimaryHeaderAllocationSize (
666+ IN UNIT_TEST_CONTEXT Context
667+ )
668+{
669+ UINT32 AllocationSize;
670+
671+ EFI_STATUS Status;
672+ EFI_PARTITION_TABLE_HEADER PrimaryHeader;
673+
674+ // Test that a normal PrimaryHeader passes validation
675+ PrimaryHeader.NumberOfPartitionEntries = 5;
676+ PrimaryHeader.SizeOfPartitionEntry = DEFAULT_PRIMARY_TABLE_HEADER_SIZE_OF_PARTITION_ENTRY;
677+
678+ Status = SanitizePrimaryHeaderAllocationSize (&PrimaryHeader, &AllocationSize);
679+ UT_ASSERT_NOT_EFI_ERROR (Status);
680+
681+ // Test that the allocation size is correct compared to the existing logic
682+ UT_ASSERT_EQUAL (AllocationSize, PrimaryHeader.NumberOfPartitionEntries * PrimaryHeader.SizeOfPartitionEntry);
683+
684+ // Test that an overflow is detected
685+ PrimaryHeader.NumberOfPartitionEntries = MAX_UINT32;
686+ PrimaryHeader.SizeOfPartitionEntry = 5;
687+ Status = SanitizePrimaryHeaderAllocationSize (&PrimaryHeader, &AllocationSize);
688+ UT_ASSERT_EQUAL (Status, EFI_BAD_BUFFER_SIZE);
689+
690+ // Test the inverse
691+ PrimaryHeader.NumberOfPartitionEntries = 5;
692+ PrimaryHeader.SizeOfPartitionEntry = MAX_UINT32;
693+ Status = SanitizePrimaryHeaderAllocationSize (&PrimaryHeader, &AllocationSize);
694+ UT_ASSERT_EQUAL (Status, EFI_BAD_BUFFER_SIZE);
695+
696+ // Test the worst case scenario
697+ PrimaryHeader.NumberOfPartitionEntries = MAX_UINT32;
698+ PrimaryHeader.SizeOfPartitionEntry = MAX_UINT32;
699+ Status = SanitizePrimaryHeaderAllocationSize (&PrimaryHeader, &AllocationSize);
700+ UT_ASSERT_EQUAL (Status, EFI_BAD_BUFFER_SIZE);
701+
702+ DEBUG ((DEBUG_INFO, "%a: Test passed\n", __func__));
703+
704+ return UNIT_TEST_PASSED;
705+}
706+
707+/**
708+ This function tests the SanitizePrimaryHeaderGptEventSize function.
709+ It's intent is to test that the untrusted input from a EFI_GPT_DATA structure
710+ will not cause an overflow when calculating the event size.
711+
712+ @param[in] Context The unit test context.
713+
714+ @retval UNIT_TEST_PASSED The test passed.
715+ @retval UNIT_TEST_ERROR_TEST_FAILED The test failed.
716+**/
717+UNIT_TEST_STATUS
718+EFIAPI
719+TestSanitizePrimaryHeaderGptEventSize (
720+ IN UNIT_TEST_CONTEXT Context
721+ )
722+{
723+ UINT32 EventSize;
724+ UINT32 ExistingLogicEventSize;
725+ EFI_STATUS Status;
726+ EFI_PARTITION_TABLE_HEADER PrimaryHeader;
727+ UINTN NumberOfPartition;
728+ EFI_GPT_DATA *GptData;
729+
730+ GptData = NULL;
731+
732+ // Test that a normal PrimaryHeader passes validation
733+ PrimaryHeader.NumberOfPartitionEntries = 5;
734+ PrimaryHeader.SizeOfPartitionEntry = DEFAULT_PRIMARY_TABLE_HEADER_SIZE_OF_PARTITION_ENTRY;
735+
736+ // set the number of partitions
737+ NumberOfPartition = 13;
738+
739+ // that the primary event size is correct
740+ Status = SanitizePrimaryHeaderGptEventSize (&PrimaryHeader, NumberOfPartition, &EventSize);
741+ UT_ASSERT_NOT_EFI_ERROR (Status);
742+
743+ // Calculate the existing logic event size
744+ ExistingLogicEventSize = (UINT32)(sizeof (TCG_PCR_EVENT_HDR) + OFFSET_OF (EFI_GPT_DATA, Partitions)
745+ + NumberOfPartition * PrimaryHeader.SizeOfPartitionEntry);
746+
747+ // Check that the event size is correct
748+ UT_ASSERT_EQUAL (EventSize, ExistingLogicEventSize);
749+
750+ // Tests that the primary event size may not overflow
751+ Status = SanitizePrimaryHeaderGptEventSize (&PrimaryHeader, MAX_UINT32, &EventSize);
752+ UT_ASSERT_EQUAL (Status, EFI_BAD_BUFFER_SIZE);
753+
754+ // Test that the size of partition entries may not overflow
755+ PrimaryHeader.SizeOfPartitionEntry = MAX_UINT32;
756+ Status = SanitizePrimaryHeaderGptEventSize (&PrimaryHeader, NumberOfPartition, &EventSize);
757+ UT_ASSERT_EQUAL (Status, EFI_BAD_BUFFER_SIZE);
758+
759+ DEBUG ((DEBUG_INFO, "%a: Test passed\n", __func__));
760+
761+ return UNIT_TEST_PASSED;
762+}
763+
764+// *--------------------------------------------------------------------*
765+// * Unit Test Code Main Function
766+// *--------------------------------------------------------------------*
767+
768+/**
769+ This function acts as the entry point for the unit tests.
770+
771+ @param argc - The number of command line arguments
772+ @param argv - The command line arguments
773+
774+ @return int - The status of the test
775+**/
776+EFI_STATUS
777+EFIAPI
778+UefiTestMain (
779+ VOID
780+ )
781+{
782+ EFI_STATUS Status;
783+ UNIT_TEST_FRAMEWORK_HANDLE Framework;
784+ UNIT_TEST_SUITE_HANDLE TcgMeasureBootLibValidationTestSuite;
785+
786+ Framework = NULL;
787+
788+ DEBUG ((DEBUG_INFO, "%a: TestMain() - Start\n", UNIT_TEST_NAME));
789+
790+ Status = InitUnitTestFramework (&Framework, UNIT_TEST_NAME, gEfiCallerBaseName, UNIT_TEST_VERSION);
791+ if (EFI_ERROR (Status)) {
792+ DEBUG ((DEBUG_ERROR, "%a: Failed in InitUnitTestFramework. Status = %r\n", UNIT_TEST_NAME, Status));
793+ goto EXIT;
794+ }
795+
796+ Status = CreateUnitTestSuite (&TcgMeasureBootLibValidationTestSuite, Framework, "TcgMeasureBootLibValidationTestSuite", "Common.TcgMeasureBootLibValidation", NULL, NULL);
797+ if (EFI_ERROR (Status)) {
798+ DEBUG ((DEBUG_ERROR, "%s: Failed in CreateUnitTestSuite for TcgMeasureBootLibValidationTestSuite\n", UNIT_TEST_NAME));
799+ Status = EFI_OUT_OF_RESOURCES;
800+ goto EXIT;
801+ }
802+
803+ // -----------Suite---------------------------------Description----------------------------Class----------------------------------Test Function------------------------Pre---Clean-Context
804+ AddTestCase (TcgMeasureBootLibValidationTestSuite, "Tests Validating EFI Partition Table", "Common.TcgMeasureBootLibValidation", TestSanitizeEfiPartitionTableHeader, NULL, NULL, NULL);
805+ AddTestCase (TcgMeasureBootLibValidationTestSuite, "Tests Primary header gpt event checks for overflow", "Common.TcgMeasureBootLibValidation", TestSanitizePrimaryHeaderAllocationSize, NULL, NULL, NULL);
806+ AddTestCase (TcgMeasureBootLibValidationTestSuite, "Tests Primary header allocation size checks for overflow", "Common.TcgMeasureBootLibValidation", TestSanitizePrimaryHeaderGptEventSize, NULL, NULL, NULL);
807+
808+ Status = RunAllTestSuites (Framework);
809+
810+EXIT:
811+ if (Framework != NULL) {
812+ FreeUnitTestFramework (Framework);
813+ }
814+
815+ DEBUG ((DEBUG_INFO, "%a: TestMain() - End\n", UNIT_TEST_NAME));
816+ return Status;
817+}
818+
819+///
820+/// Avoid ECC error for function name that starts with lower case letter
821+///
822+#define DxeTpmMeasureBootLibUnitTestMain main
823+
824+/**
825+ Standard POSIX C entry point for host based unit test execution.
826+
827+ @param[in] Argc Number of arguments
828+ @param[in] Argv Array of pointers to arguments
829+
830+ @retval 0 Success
831+ @retval other Error
832+**/
833+INT32
834+DxeTpmMeasureBootLibUnitTestMain (
835+ IN INT32 Argc,
836+ IN CHAR8 *Argv[]
837+ )
838+{
839+ return (INT32)UefiTestMain ();
840+}
841diff --git a/SecurityPkg/Library/DxeTpmMeasureBootLib/InternalUnitTest/DxeTpmMeasureBootLibSanitizationTestHost.inf b/SecurityPkg/Library/DxeTpmMeasureBootLib/InternalUnitTest/DxeTpmMeasureBootLibSanitizationTestHost.inf
842new file mode 100644
843index 0000000000..47b0811b00
844--- /dev/null
845+++ b/SecurityPkg/Library/DxeTpmMeasureBootLib/InternalUnitTest/DxeTpmMeasureBootLibSanitizationTestHost.inf
846@@ -0,0 +1,28 @@
847+## @file
848+# This file builds the unit tests for DxeTpmMeasureBootLib
849+#
850+# Copyright (C) Microsoft Corporation.<BR>
851+# SPDX-License-Identifier: BSD-2-Clause-Patent
852+##
853+
854+[Defines]
855+ INF_VERSION = 0x00010006
856+ BASE_NAME = DxeTpmMeasuredBootLibTest
857+ FILE_GUID = eb01bc38-309c-4d3e-967e-9f078c90772f
858+ MODULE_TYPE = HOST_APPLICATION
859+ VERSION_STRING = 1.0
860+ ENTRY_POINT = main
861+
862+[Sources]
863+ DxeTpmMeasureBootLibSanitizationTest.c
864+ ../DxeTpmMeasureBootLibSanitization.c
865+
866+[Packages]
867+ MdePkg/MdePkg.dec
868+
869+[LibraryClasses]
870+ BaseLib
871+ DebugLib
872+ UnitTestLib
873+ PrintLib
874+ SafeIntLib
875diff --git a/SecurityPkg/SecurityPkg.ci.yaml b/SecurityPkg/SecurityPkg.ci.yaml
876index da811fdf93..0e40eaa0fe 100644
877--- a/SecurityPkg/SecurityPkg.ci.yaml
878+++ b/SecurityPkg/SecurityPkg.ci.yaml
879@@ -16,6 +16,7 @@
880 ## ]
881 "ExceptionList": [
882 "8001", "DxeTpm2MeasureBootLibUnitTestMain",
883+ "8001", "DxeTpmMeasureBootLibUnitTestMain"
884 ],
885 ## Both file path and directory path are accepted.
886 "IgnoreFiles": [
887--
8882.40.0
889
diff --git a/meta/recipes-core/ovmf/ovmf/CVE-2022-36763-0003.patch b/meta/recipes-core/ovmf/ovmf/CVE-2022-36763-0003.patch
new file mode 100644
index 0000000000..59bd5c4910
--- /dev/null
+++ b/meta/recipes-core/ovmf/ovmf/CVE-2022-36763-0003.patch
@@ -0,0 +1,55 @@
1From 1ddcb9fc6b4164e882687b031e8beacfcf7df29e Mon Sep 17 00:00:00 2001
2From: "Douglas Flick [MSFT]" <doug.edk2@gmail.com>
3Date: Fri, 12 Jan 2024 02:16:03 +0800
4Subject: [PATCH] SecurityPkg: : Adding CVE 2022-36763 to SecurityFixes.yaml
5
6This creates / adds a security file that tracks the security fixes
7found in this package and can be used to find the fixes that were
8applied.
9
10Cc: Jiewen Yao <jiewen.yao@intel.com>
11
12Signed-off-by: Doug Flick [MSFT] <doug.edk2@gmail.com>
13Reviewed-by: Jiewen Yao <jiewen.yao@intel.com>
14
15CVE: CVE-2022-36763
16
17Upstream-Status: Backport [https://github.com/tianocore/edk2/commit/1ddcb9fc6b4164e882687b031e8beacfcf7df29e]
18
19Signed-off-by: Soumya Sambu <soumya.sambu@windriver.com>
20---
21 SecurityPkg/SecurityFixes.yaml | 22 ++++++++++++++++++++++
22 1 file changed, 22 insertions(+)
23 create mode 100644 SecurityPkg/SecurityFixes.yaml
24
25diff --git a/SecurityPkg/SecurityFixes.yaml b/SecurityPkg/SecurityFixes.yaml
26new file mode 100644
27index 0000000000..f9e3e7be74
28--- /dev/null
29+++ b/SecurityPkg/SecurityFixes.yaml
30@@ -0,0 +1,22 @@
31+## @file
32+# Security Fixes for SecurityPkg
33+#
34+# Copyright (c) Microsoft Corporation
35+# SPDX-License-Identifier: BSD-2-Clause-Patent
36+##
37+CVE_2022_36763:
38+ commit_titles:
39+ - "SecurityPkg: DxeTpm2Measurement: SECURITY PATCH 4117 - CVE 2022-36763"
40+ - "SecurityPkg: DxeTpmMeasurement: SECURITY PATCH 4117 - CVE 2022-36763"
41+ - "SecurityPkg: : Adding CVE 2022-36763 to SecurityFixes.yaml"
42+ cve: CVE-2022-36763
43+ date_reported: 2022-10-25 11:31 UTC
44+ description: (CVE-2022-36763) - Heap Buffer Overflow in Tcg2MeasureGptTable()
45+ note: This patch is related to and supersedes TCBZ2168
46+ files_impacted:
47+ - Library\DxeTpm2MeasureBootLib\DxeTpm2MeasureBootLib.c
48+ - Library\DxeTpmMeasureBootLib\DxeTpmMeasureBootLib.c
49+ links:
50+ - https://bugzilla.tianocore.org/show_bug.cgi?id=4117
51+ - https://bugzilla.tianocore.org/show_bug.cgi?id=2168
52+ - https://bugzilla.tianocore.org/show_bug.cgi?id=1990
53--
542.40.0
55
diff --git a/meta/recipes-core/ovmf/ovmf_git.bb b/meta/recipes-core/ovmf/ovmf_git.bb
index 84e3360a3a..78d86ad879 100644
--- a/meta/recipes-core/ovmf/ovmf_git.bb
+++ b/meta/recipes-core/ovmf/ovmf_git.bb
@@ -27,6 +27,9 @@ SRC_URI = "gitsm://github.com/tianocore/edk2.git;branch=master;protocol=https \
27 file://0006-reproducible.patch \ 27 file://0006-reproducible.patch \
28 file://0001-BaseTools-fix-gcc12-warning.patch \ 28 file://0001-BaseTools-fix-gcc12-warning.patch \
29 file://0001-BaseTools-fix-gcc12-warning-1.patch \ 29 file://0001-BaseTools-fix-gcc12-warning-1.patch \
30 file://CVE-2022-36763-0001.patch \
31 file://CVE-2022-36763-0002.patch \
32 file://CVE-2022-36763-0003.patch \
30 " 33 "
31 34
32PV = "edk2-stable202202" 35PV = "edk2-stable202202"