VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/FirmwareNew/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLibSanitization.c

Last change on this file was 105670, checked in by vboxsync, 9 months ago

Devices/EFI/FirmwareNew: Merge edk2-stable-202405 and make it build on aarch64, bugref:4643

  • Property svn:eol-style set to native
File size: 9.3 KB
Line 
1/** @file
2 The library instance provides security service of TPM measure boot and
3 Confidential Computing (CC) measure boot.
4
5 Caution: This file requires additional review when modified.
6 This library will have external input - PE/COFF image and GPT partition.
7 This external input must be validated carefully to avoid security issue like
8 buffer overflow, integer overflow.
9
10 This file will pull out the validation logic from the following functions, in an
11 attempt to validate the untrusted input in the form of unit tests
12
13 These are those functions:
14
15 DxeTpmMeasureBootLibImageRead() function will make sure the PE/COFF image content
16 read is within the image buffer.
17
18 Tcg2MeasureGptTable() function will receive untrusted GPT partition table, and parse
19 partition data carefully.
20
21 Copyright (c) Microsoft Corporation.<BR>
22 SPDX-License-Identifier: BSD-2-Clause-Patent
23**/
24#include <Uefi.h>
25#include <Uefi/UefiSpec.h>
26#include <Library/SafeIntLib.h>
27#include <Library/UefiLib.h>
28#include <Library/DebugLib.h>
29#include <Library/BaseLib.h>
30#include <IndustryStandard/UefiTcgPlatform.h>
31#include <Protocol/BlockIo.h>
32#include <Library/MemoryAllocationLib.h>
33
34#include "DxeTpmMeasureBootLibSanitization.h"
35
36#define GPT_HEADER_REVISION_V1 0x00010000
37
38/**
39 This function will validate the EFI_PARTITION_TABLE_HEADER structure is safe to parse
40 However this function will not attempt to verify the validity of the GPT partition
41 It will check the following:
42 - Signature
43 - Revision
44 - AlternateLBA
45 - FirstUsableLBA
46 - LastUsableLBA
47 - PartitionEntryLBA
48 - NumberOfPartitionEntries
49 - SizeOfPartitionEntry
50 - BlockIo
51
52 @param[in] PrimaryHeader
53 Pointer to the EFI_PARTITION_TABLE_HEADER structure.
54
55 @param[in] BlockIo
56 Pointer to the EFI_BLOCK_IO_PROTOCOL structure.
57
58 @retval EFI_SUCCESS
59 The EFI_PARTITION_TABLE_HEADER structure is valid.
60
61 @retval EFI_INVALID_PARAMETER
62 The EFI_PARTITION_TABLE_HEADER structure is invalid.
63**/
64EFI_STATUS
65EFIAPI
66TpmSanitizeEfiPartitionTableHeader (
67 IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader,
68 IN CONST EFI_BLOCK_IO_PROTOCOL *BlockIo
69 )
70{
71 // Verify that the input parameters are safe to use
72 if (PrimaryHeader == NULL) {
73 DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header!\n"));
74 return EFI_INVALID_PARAMETER;
75 }
76
77 if ((BlockIo == NULL) || (BlockIo->Media == NULL)) {
78 DEBUG ((DEBUG_ERROR, "Invalid BlockIo!\n"));
79 return EFI_INVALID_PARAMETER;
80 }
81
82 // The signature must be EFI_PTAB_HEADER_ID ("EFI PART" in ASCII)
83 if (PrimaryHeader->Header.Signature != EFI_PTAB_HEADER_ID) {
84 DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header!\n"));
85 return EFI_DEVICE_ERROR;
86 }
87
88 // The version must be GPT_HEADER_REVISION_V1 (0x00010000)
89 if (PrimaryHeader->Header.Revision != GPT_HEADER_REVISION_V1) {
90 DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header Revision!\n"));
91 return EFI_DEVICE_ERROR;
92 }
93
94 // The HeaderSize must be greater than or equal to 92 and must be less than or equal to the logical block size
95 if ((PrimaryHeader->Header.HeaderSize < sizeof (EFI_PARTITION_TABLE_HEADER)) || (PrimaryHeader->Header.HeaderSize > BlockIo->Media->BlockSize)) {
96 DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header HeaderSize!\n"));
97 return EFI_DEVICE_ERROR;
98 }
99
100 // check that the PartitionEntryLBA greater than the Max LBA
101 // This will be used later for multiplication
102 if (PrimaryHeader->PartitionEntryLBA > DivU64x32 (MAX_UINT64, BlockIo->Media->BlockSize)) {
103 DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header PartitionEntryLBA!\n"));
104 return EFI_DEVICE_ERROR;
105 }
106
107 // Check that the number of partition entries is greater than zero
108 if (PrimaryHeader->NumberOfPartitionEntries == 0) {
109 DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header NumberOfPartitionEntries!\n"));
110 return EFI_DEVICE_ERROR;
111 }
112
113 // SizeOfPartitionEntry must be 128, 256, 512... improper size may lead to accessing uninitialized memory
114 if ((PrimaryHeader->SizeOfPartitionEntry < 128) || ((PrimaryHeader->SizeOfPartitionEntry & (PrimaryHeader->SizeOfPartitionEntry - 1)) != 0)) {
115 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"));
116 return EFI_DEVICE_ERROR;
117 }
118
119 // This check is to prevent overflow when calculating the allocation size for the partition entries
120 // This check will be used later for multiplication
121 if (PrimaryHeader->NumberOfPartitionEntries > DivU64x32 (MAX_UINT64, PrimaryHeader->SizeOfPartitionEntry)) {
122 DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header NumberOfPartitionEntries!\n"));
123 return EFI_DEVICE_ERROR;
124 }
125
126 return EFI_SUCCESS;
127}
128
129/**
130 This function will validate that the allocation size from the primary header is sane
131 It will check the following:
132 - AllocationSize does not overflow
133
134 @param[in] PrimaryHeader
135 Pointer to the EFI_PARTITION_TABLE_HEADER structure.
136
137 @param[out] AllocationSize
138 Pointer to the allocation size.
139
140 @retval EFI_SUCCESS
141 The allocation size is valid.
142
143 @retval EFI_OUT_OF_RESOURCES
144 The allocation size is invalid.
145**/
146EFI_STATUS
147EFIAPI
148TpmSanitizePrimaryHeaderAllocationSize (
149 IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader,
150 OUT UINT32 *AllocationSize
151 )
152{
153 EFI_STATUS Status;
154
155 if (PrimaryHeader == NULL) {
156 return EFI_INVALID_PARAMETER;
157 }
158
159 if (AllocationSize == NULL) {
160 return EFI_INVALID_PARAMETER;
161 }
162
163 // Replacing logic:
164 // PrimaryHeader->NumberOfPartitionEntries * PrimaryHeader->SizeOfPartitionEntry;
165 Status = SafeUint32Mult (PrimaryHeader->NumberOfPartitionEntries, PrimaryHeader->SizeOfPartitionEntry, AllocationSize);
166 if (EFI_ERROR (Status)) {
167 DEBUG ((DEBUG_ERROR, "Allocation Size would have overflowed!\n"));
168 return EFI_BAD_BUFFER_SIZE;
169 }
170
171 return EFI_SUCCESS;
172}
173
174/**
175 This function will validate that the Gpt Event Size calculated from the primary header is sane
176 It will check the following:
177 - EventSize does not overflow
178
179 Important: This function includes the entire length of the allocated space, including the
180 TCG_PCR_EVENT_HDR. When hashing the buffer allocated with this size, the caller must subtract
181 the size of the TCG_PCR_EVENT_HDR from the size of the buffer before hashing.
182
183 @param[in] PrimaryHeader - Pointer to the EFI_PARTITION_TABLE_HEADER structure.
184 @param[in] NumberOfPartition - Number of partitions.
185 @param[out] EventSize - Pointer to the event size.
186
187 @retval EFI_SUCCESS
188 The event size is valid.
189
190 @retval EFI_OUT_OF_RESOURCES
191 Overflow would have occurred.
192
193 @retval EFI_INVALID_PARAMETER
194 One of the passed parameters was invalid.
195**/
196EFI_STATUS
197TpmSanitizePrimaryHeaderGptEventSize (
198 IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader,
199 IN UINTN NumberOfPartition,
200 OUT UINT32 *EventSize
201 )
202{
203 EFI_STATUS Status;
204 UINT32 SafeNumberOfPartitions;
205
206 if (PrimaryHeader == NULL) {
207 return EFI_INVALID_PARAMETER;
208 }
209
210 if (EventSize == NULL) {
211 return EFI_INVALID_PARAMETER;
212 }
213
214 // We shouldn't even attempt to perform the multiplication if the number of partitions is greater than the maximum value of UINT32
215 Status = SafeUintnToUint32 (NumberOfPartition, &SafeNumberOfPartitions);
216 if (EFI_ERROR (Status)) {
217 DEBUG ((DEBUG_ERROR, "NumberOfPartition would have overflowed!\n"));
218 return EFI_INVALID_PARAMETER;
219 }
220
221 // Replacing logic:
222 // (UINT32)(sizeof (EFI_GPT_DATA) - sizeof (GptData->Partitions) + NumberOfPartition * PrimaryHeader.SizeOfPartitionEntry + sizeof (TCG_PCR_EVENT_HDR));
223 Status = SafeUint32Mult (SafeNumberOfPartitions, PrimaryHeader->SizeOfPartitionEntry, EventSize);
224 if (EFI_ERROR (Status)) {
225 DEBUG ((DEBUG_ERROR, "Event Size would have overflowed!\n"));
226 return EFI_BAD_BUFFER_SIZE;
227 }
228
229 Status = SafeUint32Add (
230 sizeof (TCG_PCR_EVENT_HDR) +
231 OFFSET_OF (EFI_GPT_DATA, Partitions),
232 *EventSize,
233 EventSize
234 );
235 if (EFI_ERROR (Status)) {
236 DEBUG ((DEBUG_ERROR, "Event Size would have overflowed because of GPTData!\n"));
237 return EFI_BAD_BUFFER_SIZE;
238 }
239
240 return EFI_SUCCESS;
241}
242
243/**
244 This function will validate that the PeImage Event Size from the loaded image is sane
245 It will check the following:
246 - EventSize does not overflow
247
248 @param[in] FilePathSize - Size of the file path.
249 @param[out] EventSize - Pointer to the event size.
250
251 @retval EFI_SUCCESS
252 The event size is valid.
253
254 @retval EFI_OUT_OF_RESOURCES
255 Overflow would have occurred.
256
257 @retval EFI_INVALID_PARAMETER
258 One of the passed parameters was invalid.
259**/
260EFI_STATUS
261TpmSanitizePeImageEventSize (
262 IN UINT32 FilePathSize,
263 OUT UINT32 *EventSize
264 )
265{
266 EFI_STATUS Status;
267
268 // Replacing logic:
269 // sizeof (*ImageLoad) - sizeof (ImageLoad->DevicePath) + FilePathSize;
270 Status = SafeUint32Add (OFFSET_OF (EFI_IMAGE_LOAD_EVENT, DevicePath), FilePathSize, EventSize);
271 if (EFI_ERROR (Status)) {
272 DEBUG ((DEBUG_ERROR, "EventSize would overflow!\n"));
273 return EFI_BAD_BUFFER_SIZE;
274 }
275
276 // Replacing logic:
277 // EventSize + sizeof (TCG_PCR_EVENT_HDR)
278 Status = SafeUint32Add (*EventSize, sizeof (TCG_PCR_EVENT_HDR), EventSize);
279 if (EFI_ERROR (Status)) {
280 DEBUG ((DEBUG_ERROR, "EventSize would overflow!\n"));
281 return EFI_BAD_BUFFER_SIZE;
282 }
283
284 return EFI_SUCCESS;
285}
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette