]> git.proxmox.com Git - mirror_edk2.git/blame - OvmfPkg/Library/PeilessStartupLib/IntelTdx.c
OvmfPkg: Implement MeasureHobList/MeasureFvImage
[mirror_edk2.git] / OvmfPkg / Library / PeilessStartupLib / IntelTdx.c
CommitLineData
4b0a6226
MX
1/** @file\r
2 Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>\r
3 SPDX-License-Identifier: BSD-2-Clause-Patent\r
4**/\r
5\r
6#include <PiPei.h>\r
7#include <Library/BaseLib.h>\r
8#include <Library/BaseMemoryLib.h>\r
9#include <Library/DebugLib.h>\r
10#include <Guid/VariableFormat.h>\r
11#include <Guid/SystemNvDataGuid.h>\r
ff0ffe59
MX
12#include <IndustryStandard/Tpm20.h>\r
13#include <IndustryStandard/UefiTcgPlatform.h>\r
14#include <Library/HobLib.h>\r
15#include <Library/PrintLib.h>\r
16#include <Library/TpmMeasurementLib.h>\r
17\r
4b0a6226
MX
18#include "PeilessStartupInternal.h"\r
19\r
ff0ffe59
MX
20#pragma pack(1)\r
21\r
22#define HANDOFF_TABLE_DESC "TdxTable"\r
23typedef struct {\r
24 UINT8 TableDescriptionSize;\r
25 UINT8 TableDescription[sizeof (HANDOFF_TABLE_DESC)];\r
26 UINT64 NumberOfTables;\r
27 EFI_CONFIGURATION_TABLE TableEntry[1];\r
28} TDX_HANDOFF_TABLE_POINTERS2;\r
29\r
30#define FV_HANDOFF_TABLE_DESC "Fv(XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX)"\r
31typedef struct {\r
32 UINT8 BlobDescriptionSize;\r
33 UINT8 BlobDescription[sizeof (FV_HANDOFF_TABLE_DESC)];\r
34 EFI_PHYSICAL_ADDRESS BlobBase;\r
35 UINT64 BlobLength;\r
36} FV_HANDOFF_TABLE_POINTERS2;\r
37\r
38#pragma pack()\r
39\r
4b0a6226
MX
40/**\r
41 Check padding data all bit should be 1.\r
42\r
43 @param[in] Buffer - A pointer to buffer header\r
44 @param[in] BufferSize - Buffer size\r
45\r
46 @retval TRUE - The padding data is valid.\r
47 @retval TRUE - The padding data is invalid.\r
48\r
49**/\r
50BOOLEAN\r
51CheckPaddingData (\r
52 IN UINT8 *Buffer,\r
53 IN UINT32 BufferSize\r
54 )\r
55{\r
56 UINT32 index;\r
57\r
58 for (index = 0; index < BufferSize; index++) {\r
59 if (Buffer[index] != 0xFF) {\r
60 return FALSE;\r
61 }\r
62 }\r
63\r
64 return TRUE;\r
65}\r
66\r
67/**\r
68 Check the integrity of CFV data.\r
69\r
70 @param[in] TdxCfvBase - A pointer to CFV header\r
71 @param[in] TdxCfvSize - CFV data size\r
72\r
73 @retval TRUE - The CFV data is valid.\r
74 @retval FALSE - The CFV data is invalid.\r
75\r
76**/\r
77BOOLEAN\r
78EFIAPI\r
79TdxValidateCfv (\r
80 IN UINT8 *TdxCfvBase,\r
81 IN UINT32 TdxCfvSize\r
82 )\r
83{\r
84 UINT16 Checksum;\r
85 UINTN VariableBase;\r
86 UINT32 VariableOffset;\r
87 UINT32 VariableOffsetBeforeAlign;\r
88 EFI_FIRMWARE_VOLUME_HEADER *CfvFvHeader;\r
89 VARIABLE_STORE_HEADER *CfvVariableStoreHeader;\r
90 AUTHENTICATED_VARIABLE_HEADER *VariableHeader;\r
91\r
92 static EFI_GUID FvHdrGUID = EFI_SYSTEM_NV_DATA_FV_GUID;\r
93 static EFI_GUID VarStoreHdrGUID = EFI_AUTHENTICATED_VARIABLE_GUID;\r
94\r
95 VariableOffset = 0;\r
96\r
97 if (TdxCfvBase == NULL) {\r
98 DEBUG ((DEBUG_ERROR, "TDX CFV: CFV pointer is NULL\n"));\r
99 return FALSE;\r
100 }\r
101\r
102 //\r
103 // Verify the header zerovetor, filesystemguid,\r
104 // revision, signature, attributes, fvlength, checksum\r
105 // HeaderLength cannot be an odd number\r
106 //\r
107 CfvFvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)TdxCfvBase;\r
108\r
109 if ((!IsZeroBuffer (CfvFvHeader->ZeroVector, 16)) ||\r
110 (!CompareGuid (&FvHdrGUID, &CfvFvHeader->FileSystemGuid)) ||\r
111 (CfvFvHeader->Signature != EFI_FVH_SIGNATURE) ||\r
112 (CfvFvHeader->Attributes != 0x4feff) ||\r
113 (CfvFvHeader->Revision != EFI_FVH_REVISION) ||\r
114 (CfvFvHeader->FvLength != TdxCfvSize)\r
115 )\r
116 {\r
117 DEBUG ((DEBUG_ERROR, "TDX CFV: Basic FV headers were invalid\n"));\r
118 return FALSE;\r
119 }\r
120\r
121 //\r
122 // Verify the header checksum\r
123 //\r
124 Checksum = CalculateSum16 ((VOID *)CfvFvHeader, CfvFvHeader->HeaderLength);\r
125\r
126 if (Checksum != 0) {\r
127 DEBUG ((DEBUG_ERROR, "TDX CFV: FV checksum was invalid\n"));\r
128 return FALSE;\r
129 }\r
130\r
131 //\r
132 // Verify the header signature, size, format, state\r
133 //\r
134 CfvVariableStoreHeader = (VARIABLE_STORE_HEADER *)(TdxCfvBase + CfvFvHeader->HeaderLength);\r
135 if ((!CompareGuid (&VarStoreHdrGUID, &CfvVariableStoreHeader->Signature)) ||\r
136 (CfvVariableStoreHeader->Format != VARIABLE_STORE_FORMATTED) ||\r
137 (CfvVariableStoreHeader->State != VARIABLE_STORE_HEALTHY) ||\r
138 (CfvVariableStoreHeader->Size > (CfvFvHeader->FvLength - CfvFvHeader->HeaderLength)) ||\r
139 (CfvVariableStoreHeader->Size < sizeof (VARIABLE_STORE_HEADER))\r
140 )\r
141 {\r
142 DEBUG ((DEBUG_ERROR, "TDX CFV: Variable Store header was invalid\n"));\r
143 return FALSE;\r
144 }\r
145\r
146 //\r
147 // Verify the header startId, state\r
148 // Verify data to the end\r
149 //\r
150 VariableBase = (UINTN)TdxCfvBase + CfvFvHeader->HeaderLength + sizeof (VARIABLE_STORE_HEADER);\r
151 while (VariableOffset < (CfvVariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER))) {\r
152 VariableHeader = (AUTHENTICATED_VARIABLE_HEADER *)(VariableBase + VariableOffset);\r
153 if (VariableHeader->StartId != VARIABLE_DATA) {\r
154 if (!CheckPaddingData ((UINT8 *)VariableHeader, CfvVariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER) - VariableOffset)) {\r
155 DEBUG ((DEBUG_ERROR, "TDX CFV: Variable header was invalid\n"));\r
156 return FALSE;\r
157 }\r
158\r
159 VariableOffset = CfvVariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER);\r
160 } else {\r
161 if (!((VariableHeader->State == VAR_IN_DELETED_TRANSITION) ||\r
162 (VariableHeader->State == VAR_DELETED) ||\r
163 (VariableHeader->State == VAR_HEADER_VALID_ONLY) ||\r
164 (VariableHeader->State == VAR_ADDED)))\r
165 {\r
166 DEBUG ((DEBUG_ERROR, "TDX CFV: Variable header was invalid\n"));\r
167 return FALSE;\r
168 }\r
169\r
170 VariableOffset += sizeof (AUTHENTICATED_VARIABLE_HEADER) + VariableHeader->NameSize + VariableHeader->DataSize;\r
171 // Verify VariableOffset should be less than or equal CfvVariableStoreHeader->Size - sizeof(VARIABLE_STORE_HEADER)\r
172 if (VariableOffset > (CfvVariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER))) {\r
173 DEBUG ((DEBUG_ERROR, "TDX CFV: Variable header was invalid\n"));\r
174 return FALSE;\r
175 }\r
176\r
177 VariableOffsetBeforeAlign = VariableOffset;\r
178 // 4 byte align\r
179 VariableOffset = (VariableOffset + 3) & (UINTN)(~3);\r
180\r
181 if (!CheckPaddingData ((UINT8 *)(VariableBase + VariableOffsetBeforeAlign), VariableOffset - VariableOffsetBeforeAlign)) {\r
182 DEBUG ((DEBUG_ERROR, "TDX CFV: Variable header was invalid\n"));\r
183 return FALSE;\r
184 }\r
185 }\r
186 }\r
187\r
188 return TRUE;\r
189}\r
ff0ffe59
MX
190\r
191/**\r
192 Measure the Hoblist passed from the VMM.\r
193\r
194 @param[in] VmmHobList The Hoblist pass the firmware\r
195\r
196 @retval EFI_SUCCESS Fv image is measured successfully\r
197 or it has been already measured.\r
198 @retval Others Other errors as indicated\r
199**/\r
200EFI_STATUS\r
201EFIAPI\r
202MeasureHobList (\r
203 IN CONST VOID *VmmHobList\r
204 )\r
205{\r
206 EFI_PEI_HOB_POINTERS Hob;\r
207 TDX_HANDOFF_TABLE_POINTERS2 HandoffTables;\r
208 EFI_STATUS Status;\r
209\r
210 if (!TdIsEnabled ()) {\r
211 ASSERT (FALSE);\r
212 return EFI_UNSUPPORTED;\r
213 }\r
214\r
215 Hob.Raw = (UINT8 *)VmmHobList;\r
216\r
217 //\r
218 // Parse the HOB list until end of list.\r
219 //\r
220 while (!END_OF_HOB_LIST (Hob)) {\r
221 Hob.Raw = GET_NEXT_HOB (Hob);\r
222 }\r
223\r
224 //\r
225 // Init the log event for HOB measurement\r
226 //\r
227\r
228 HandoffTables.TableDescriptionSize = sizeof (HandoffTables.TableDescription);\r
229 CopyMem (HandoffTables.TableDescription, HANDOFF_TABLE_DESC, sizeof (HandoffTables.TableDescription));\r
230 HandoffTables.NumberOfTables = 1;\r
231 CopyGuid (&(HandoffTables.TableEntry[0].VendorGuid), &gUefiOvmfPkgTokenSpaceGuid);\r
232 HandoffTables.TableEntry[0].VendorTable = (VOID *)VmmHobList;\r
233\r
234 Status = TpmMeasureAndLogData (\r
235 1, // PCRIndex\r
236 EV_EFI_HANDOFF_TABLES2, // EventType\r
237 (VOID *)&HandoffTables, // EventData\r
238 sizeof (HandoffTables), // EventSize\r
239 (UINT8 *)(UINTN)VmmHobList, // HashData\r
240 (UINTN)((UINT8 *)Hob.Raw - (UINT8 *)VmmHobList) // HashDataLen\r
241 );\r
242\r
243 if (EFI_ERROR (Status)) {\r
244 ASSERT (FALSE);\r
245 }\r
246\r
247 return Status;\r
248}\r
249\r
250/**\r
251 Get the FvName from the FV header.\r
252\r
253 Causion: The FV is untrusted input.\r
254\r
255 @param[in] FvBase Base address of FV image.\r
256 @param[in] FvLength Length of FV image.\r
257\r
258 @return FvName pointer\r
259 @retval NULL FvName is NOT found\r
260**/\r
261VOID *\r
262GetFvName (\r
263 IN EFI_PHYSICAL_ADDRESS FvBase,\r
264 IN UINT64 FvLength\r
265 )\r
266{\r
267 EFI_FIRMWARE_VOLUME_HEADER *FvHeader;\r
268 EFI_FIRMWARE_VOLUME_EXT_HEADER *FvExtHeader;\r
269\r
270 if (FvBase >= MAX_ADDRESS) {\r
271 return NULL;\r
272 }\r
273\r
274 if (FvLength >= MAX_ADDRESS - FvBase) {\r
275 return NULL;\r
276 }\r
277\r
278 if (FvLength < sizeof (EFI_FIRMWARE_VOLUME_HEADER)) {\r
279 return NULL;\r
280 }\r
281\r
282 FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)FvBase;\r
283 if (FvHeader->ExtHeaderOffset < sizeof (EFI_FIRMWARE_VOLUME_HEADER)) {\r
284 return NULL;\r
285 }\r
286\r
287 if (FvHeader->ExtHeaderOffset + sizeof (EFI_FIRMWARE_VOLUME_EXT_HEADER) > FvLength) {\r
288 return NULL;\r
289 }\r
290\r
291 FvExtHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER *)(UINTN)(FvBase + FvHeader->ExtHeaderOffset);\r
292\r
293 return &FvExtHeader->FvName;\r
294}\r
295\r
296/**\r
297 Measure FV image.\r
298\r
299 @param[in] FvBase Base address of FV image.\r
300 @param[in] FvLength Length of FV image.\r
301 @param[in] PcrIndex Index of PCR\r
302\r
303 @retval EFI_SUCCESS Fv image is measured successfully\r
304 or it has been already measured.\r
305 @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event.\r
306 @retval EFI_DEVICE_ERROR The command was unsuccessful.\r
307\r
308**/\r
309EFI_STATUS\r
310EFIAPI\r
311MeasureFvImage (\r
312 IN EFI_PHYSICAL_ADDRESS FvBase,\r
313 IN UINT64 FvLength,\r
314 IN UINT8 PcrIndex\r
315 )\r
316{\r
317 EFI_STATUS Status;\r
318 FV_HANDOFF_TABLE_POINTERS2 FvBlob2;\r
319 VOID *FvName;\r
320\r
321 //\r
322 // Init the log event for FV measurement\r
323 //\r
324 FvBlob2.BlobDescriptionSize = sizeof (FvBlob2.BlobDescription);\r
325 CopyMem (FvBlob2.BlobDescription, FV_HANDOFF_TABLE_DESC, sizeof (FvBlob2.BlobDescription));\r
326 FvName = GetFvName (FvBase, FvLength);\r
327 if (FvName != NULL) {\r
328 AsciiSPrint ((CHAR8 *)FvBlob2.BlobDescription, sizeof (FvBlob2.BlobDescription), "Fv(%g)", FvName);\r
329 }\r
330\r
331 FvBlob2.BlobBase = FvBase;\r
332 FvBlob2.BlobLength = FvLength;\r
333\r
334 Status = TpmMeasureAndLogData (\r
335 1, // PCRIndex\r
336 EV_EFI_PLATFORM_FIRMWARE_BLOB2, // EventType\r
337 (VOID *)&FvBlob2, // EventData\r
338 sizeof (FvBlob2), // EventSize\r
339 (UINT8 *)(UINTN)FvBase, // HashData\r
340 (UINTN)(FvLength) // HashDataLen\r
341 );\r
342\r
343 if (EFI_ERROR (Status)) {\r
344 DEBUG ((DEBUG_ERROR, "The FV which failed to be measured starts at: 0x%x\n", FvBase));\r
345 ASSERT (FALSE);\r
346 }\r
347\r
348 return Status;\r
349}\r