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 | **/
|
---|
64 | EFI_STATUS
|
---|
65 | EFIAPI
|
---|
66 | TpmSanitizeEfiPartitionTableHeader (
|
---|
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 | **/
|
---|
146 | EFI_STATUS
|
---|
147 | EFIAPI
|
---|
148 | TpmSanitizePrimaryHeaderAllocationSize (
|
---|
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 | **/
|
---|
196 | EFI_STATUS
|
---|
197 | TpmSanitizePrimaryHeaderGptEventSize (
|
---|
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 | **/
|
---|
260 | EFI_STATUS
|
---|
261 | TpmSanitizePeImageEventSize (
|
---|
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 | }
|
---|