]> git.proxmox.com Git - mirror_edk2.git/blob - SecurityPkg/Tcg/TrEESmm/TrEESmm.c
1683dedc8ab1bbfa2cd634e77faa54e69a25c97e
[mirror_edk2.git] / SecurityPkg / Tcg / TrEESmm / TrEESmm.c
1 /** @file
2 It updates TPM2 items in ACPI table and registers SMI2 callback
3 functions for TrEE physical presence, ClearMemory, and sample
4 for dTPM StartMethod.
5
6 Caution: This module requires additional review when modified.
7 This driver will have external input - variable and ACPINvs data in SMM mode.
8 This external input must be validated carefully to avoid security issue.
9
10 PhysicalPresenceCallback() and MemoryClearCallback() will receive untrusted input and do some check.
11
12 Copyright (c) 2013 - 2017, Intel Corporation. All rights reserved.<BR>
13 This program and the accompanying materials
14 are licensed and made available under the terms and conditions of the BSD License
15 which accompanies this distribution. The full text of the license may be found at
16 http://opensource.org/licenses/bsd-license.php
17
18 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
19 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
20
21 **/
22
23 #include "TrEESmm.h"
24
25 EFI_TPM2_ACPI_TABLE mTpm2AcpiTemplate = {
26 {
27 EFI_ACPI_5_0_TRUSTED_COMPUTING_PLATFORM_2_TABLE_SIGNATURE,
28 sizeof (mTpm2AcpiTemplate),
29 EFI_TPM2_ACPI_TABLE_REVISION_3,
30 //
31 // Compiler initializes the remaining bytes to 0
32 // These fields should be filled in in production
33 //
34 },
35 0, // Flags
36 0, // Control Area
37 EFI_TPM2_ACPI_TABLE_START_METHOD_TIS, // StartMethod
38 };
39
40 EFI_SMM_VARIABLE_PROTOCOL *mSmmVariable;
41 TCG_NVS *mTcgNvs;
42
43 /**
44 Software SMI callback for TPM physical presence which is called from ACPI method.
45
46 Caution: This function may receive untrusted input.
47 Variable and ACPINvs are external input, so this function will validate
48 its data structure to be valid value.
49
50 @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
51 @param[in] Context Points to an optional handler context which was specified when the
52 handler was registered.
53 @param[in, out] CommBuffer A pointer to a collection of data in memory that will
54 be conveyed from a non-SMM environment into an SMM environment.
55 @param[in, out] CommBufferSize The size of the CommBuffer.
56
57 @retval EFI_SUCCESS The interrupt was handled successfully.
58
59 **/
60 EFI_STATUS
61 EFIAPI
62 PhysicalPresenceCallback (
63 IN EFI_HANDLE DispatchHandle,
64 IN CONST VOID *Context,
65 IN OUT VOID *CommBuffer,
66 IN OUT UINTN *CommBufferSize
67 )
68 {
69 EFI_STATUS Status;
70 UINTN DataSize;
71 EFI_TREE_PHYSICAL_PRESENCE PpData;
72 EFI_TREE_PHYSICAL_PRESENCE_FLAGS Flags;
73 BOOLEAN RequestConfirmed;
74
75 //
76 // Get the Physical Presence variable
77 //
78 DataSize = sizeof (EFI_TREE_PHYSICAL_PRESENCE);
79 Status = mSmmVariable->SmmGetVariable (
80 TREE_PHYSICAL_PRESENCE_VARIABLE,
81 &gEfiTrEEPhysicalPresenceGuid,
82 NULL,
83 &DataSize,
84 &PpData
85 );
86
87 DEBUG ((EFI_D_INFO, "[TPM2] PP callback, Parameter = %x, Request = %x\n", mTcgNvs->PhysicalPresence.Parameter, mTcgNvs->PhysicalPresence.Request));
88
89 if (mTcgNvs->PhysicalPresence.Parameter == ACPI_FUNCTION_RETURN_REQUEST_RESPONSE_TO_OS) {
90 if (EFI_ERROR (Status)) {
91 mTcgNvs->PhysicalPresence.ReturnCode = PP_RETURN_TPM_OPERATION_RESPONSE_FAILURE;
92 mTcgNvs->PhysicalPresence.LastRequest = 0;
93 mTcgNvs->PhysicalPresence.Response = 0;
94 DEBUG ((EFI_D_ERROR, "[TPM2] Get PP variable failure! Status = %r\n", Status));
95 return EFI_SUCCESS;
96 }
97 mTcgNvs->PhysicalPresence.ReturnCode = PP_RETURN_TPM_OPERATION_RESPONSE_SUCCESS;
98 mTcgNvs->PhysicalPresence.LastRequest = PpData.LastPPRequest;
99 mTcgNvs->PhysicalPresence.Response = PpData.PPResponse;
100 } else if ((mTcgNvs->PhysicalPresence.Parameter == ACPI_FUNCTION_SUBMIT_REQUEST_TO_BIOS)
101 || (mTcgNvs->PhysicalPresence.Parameter == ACPI_FUNCTION_SUBMIT_REQUEST_TO_BIOS_2)) {
102 if (EFI_ERROR (Status)) {
103 mTcgNvs->PhysicalPresence.ReturnCode = TREE_PP_SUBMIT_REQUEST_TO_PREOS_GENERAL_FAILURE;
104 DEBUG ((EFI_D_ERROR, "[TPM2] Get PP variable failure! Status = %r\n", Status));
105 return EFI_SUCCESS;
106 }
107 if ((mTcgNvs->PhysicalPresence.Request > TREE_PHYSICAL_PRESENCE_NO_ACTION_MAX) &&
108 (mTcgNvs->PhysicalPresence.Request < TREE_PHYSICAL_PRESENCE_VENDOR_SPECIFIC_OPERATION) ) {
109 //
110 // This command requires UI to prompt user for Auth data.
111 //
112 mTcgNvs->PhysicalPresence.ReturnCode = TREE_PP_SUBMIT_REQUEST_TO_PREOS_NOT_IMPLEMENTED;
113 return EFI_SUCCESS;
114 }
115
116 if (PpData.PPRequest != mTcgNvs->PhysicalPresence.Request) {
117 PpData.PPRequest = (UINT8) mTcgNvs->PhysicalPresence.Request;
118 DataSize = sizeof (EFI_TREE_PHYSICAL_PRESENCE);
119 Status = mSmmVariable->SmmSetVariable (
120 TREE_PHYSICAL_PRESENCE_VARIABLE,
121 &gEfiTrEEPhysicalPresenceGuid,
122 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
123 DataSize,
124 &PpData
125 );
126 }
127
128 if (EFI_ERROR (Status)) {
129 mTcgNvs->PhysicalPresence.ReturnCode = TREE_PP_SUBMIT_REQUEST_TO_PREOS_GENERAL_FAILURE;
130 DEBUG ((EFI_D_ERROR, "[TPM2] Set PP variable failure! Status = %r\n", Status));
131 return EFI_SUCCESS;
132 }
133 mTcgNvs->PhysicalPresence.ReturnCode = TREE_PP_SUBMIT_REQUEST_TO_PREOS_SUCCESS;
134
135 if (mTcgNvs->PhysicalPresence.Request >= TREE_PHYSICAL_PRESENCE_VENDOR_SPECIFIC_OPERATION) {
136 DataSize = sizeof (EFI_TREE_PHYSICAL_PRESENCE_FLAGS);
137 Status = mSmmVariable->SmmGetVariable (
138 TREE_PHYSICAL_PRESENCE_FLAGS_VARIABLE,
139 &gEfiTrEEPhysicalPresenceGuid,
140 NULL,
141 &DataSize,
142 &Flags
143 );
144 if (EFI_ERROR (Status)) {
145 Flags.PPFlags = 0;
146 }
147 mTcgNvs->PhysicalPresence.ReturnCode = TrEEPpVendorLibSubmitRequestToPreOSFunction (mTcgNvs->PhysicalPresence.Request, Flags.PPFlags);
148 }
149 } else if (mTcgNvs->PhysicalPresence.Parameter == ACPI_FUNCTION_GET_USER_CONFIRMATION_STATUS_FOR_REQUEST) {
150 if (EFI_ERROR (Status)) {
151 mTcgNvs->PhysicalPresence.ReturnCode = TREE_PP_GET_USER_CONFIRMATION_BLOCKED_BY_BIOS_CONFIGURATION;
152 DEBUG ((EFI_D_ERROR, "[TPM2] Get PP variable failure! Status = %r\n", Status));
153 return EFI_SUCCESS;
154 }
155 //
156 // Get the Physical Presence flags
157 //
158 DataSize = sizeof (EFI_TREE_PHYSICAL_PRESENCE_FLAGS);
159 Status = mSmmVariable->SmmGetVariable (
160 TREE_PHYSICAL_PRESENCE_FLAGS_VARIABLE,
161 &gEfiTrEEPhysicalPresenceGuid,
162 NULL,
163 &DataSize,
164 &Flags
165 );
166 if (EFI_ERROR (Status)) {
167 mTcgNvs->PhysicalPresence.ReturnCode = TREE_PP_GET_USER_CONFIRMATION_BLOCKED_BY_BIOS_CONFIGURATION;
168 DEBUG ((EFI_D_ERROR, "[TPM2] Get PP flags failure! Status = %r\n", Status));
169 return EFI_SUCCESS;
170 }
171
172 RequestConfirmed = FALSE;
173
174 switch (mTcgNvs->PhysicalPresence.Request) {
175
176 case TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR:
177 case TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR_2:
178 case TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR_3:
179 case TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR_4:
180 if ((Flags.PPFlags & TREE_BIOS_TPM_MANAGEMENT_FLAG_NO_PPI_CLEAR) != 0) {
181 RequestConfirmed = TRUE;
182 }
183 break;
184
185 case TREE_PHYSICAL_PRESENCE_SET_NO_PPI_CLEAR_FALSE:
186 RequestConfirmed = TRUE;
187 break;
188
189 case TREE_PHYSICAL_PRESENCE_SET_NO_PPI_CLEAR_TRUE:
190 break;
191
192 default:
193 if (mTcgNvs->PhysicalPresence.Request <= TREE_PHYSICAL_PRESENCE_NO_ACTION_MAX) {
194 RequestConfirmed = TRUE;
195 } else {
196 if (mTcgNvs->PhysicalPresence.Request < TREE_PHYSICAL_PRESENCE_VENDOR_SPECIFIC_OPERATION) {
197 mTcgNvs->PhysicalPresence.ReturnCode = TREE_PP_GET_USER_CONFIRMATION_NOT_IMPLEMENTED;
198 return EFI_SUCCESS;
199 }
200 }
201 break;
202 }
203
204 if (RequestConfirmed) {
205 mTcgNvs->PhysicalPresence.ReturnCode = TREE_PP_GET_USER_CONFIRMATION_ALLOWED_AND_PPUSER_NOT_REQUIRED;
206 } else {
207 mTcgNvs->PhysicalPresence.ReturnCode = TREE_PP_GET_USER_CONFIRMATION_ALLOWED_AND_PPUSER_REQUIRED;
208 }
209 if (mTcgNvs->PhysicalPresence.Request >= TREE_PHYSICAL_PRESENCE_VENDOR_SPECIFIC_OPERATION) {
210 mTcgNvs->PhysicalPresence.ReturnCode = TrEEPpVendorLibGetUserConfirmationStatusFunction (mTcgNvs->PhysicalPresence.Request, Flags.PPFlags);
211 }
212 }
213
214 return EFI_SUCCESS;
215 }
216
217
218 /**
219 Software SMI callback for MemoryClear which is called from ACPI method.
220
221 Caution: This function may receive untrusted input.
222 Variable and ACPINvs are external input, so this function will validate
223 its data structure to be valid value.
224
225 @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
226 @param[in] Context Points to an optional handler context which was specified when the
227 handler was registered.
228 @param[in, out] CommBuffer A pointer to a collection of data in memory that will
229 be conveyed from a non-SMM environment into an SMM environment.
230 @param[in, out] CommBufferSize The size of the CommBuffer.
231
232 @retval EFI_SUCCESS The interrupt was handled successfully.
233
234 **/
235 EFI_STATUS
236 EFIAPI
237 MemoryClearCallback (
238 IN EFI_HANDLE DispatchHandle,
239 IN CONST VOID *Context,
240 IN OUT VOID *CommBuffer,
241 IN OUT UINTN *CommBufferSize
242 )
243 {
244 EFI_STATUS Status;
245 UINTN DataSize;
246 UINT8 MorControl;
247
248 mTcgNvs->MemoryClear.ReturnCode = MOR_REQUEST_SUCCESS;
249 if (mTcgNvs->MemoryClear.Parameter == ACPI_FUNCTION_DSM_MEMORY_CLEAR_INTERFACE) {
250 MorControl = (UINT8) mTcgNvs->MemoryClear.Request;
251 } else if (mTcgNvs->MemoryClear.Parameter == ACPI_FUNCTION_PTS_CLEAR_MOR_BIT) {
252 DataSize = sizeof (UINT8);
253 Status = mSmmVariable->SmmGetVariable (
254 MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME,
255 &gEfiMemoryOverwriteControlDataGuid,
256 NULL,
257 &DataSize,
258 &MorControl
259 );
260 if (EFI_ERROR (Status)) {
261 mTcgNvs->MemoryClear.ReturnCode = MOR_REQUEST_GENERAL_FAILURE;
262 DEBUG ((EFI_D_ERROR, "[TPM] Get MOR variable failure! Status = %r\n", Status));
263 return EFI_SUCCESS;
264 }
265
266 if (MOR_CLEAR_MEMORY_VALUE (MorControl) == 0x0) {
267 return EFI_SUCCESS;
268 }
269 MorControl &= ~MOR_CLEAR_MEMORY_BIT_MASK;
270 }
271
272 DataSize = sizeof (UINT8);
273 Status = mSmmVariable->SmmSetVariable (
274 MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME,
275 &gEfiMemoryOverwriteControlDataGuid,
276 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
277 DataSize,
278 &MorControl
279 );
280 if (EFI_ERROR (Status)) {
281 mTcgNvs->MemoryClear.ReturnCode = MOR_REQUEST_GENERAL_FAILURE;
282 DEBUG ((EFI_D_ERROR, "[TPM] Set MOR variable failure! Status = %r\n", Status));
283 }
284
285 return EFI_SUCCESS;
286 }
287
288 /**
289 Find the operation region in TCG ACPI table by given Name and Size,
290 and initialize it if the region is found.
291
292 @param[in, out] Table The TPM item in ACPI table.
293 @param[in] Name The name string to find in TPM table.
294 @param[in] Size The size of the region to find.
295
296 @return The allocated address for the found region.
297
298 **/
299 VOID *
300 AssignOpRegion (
301 EFI_ACPI_DESCRIPTION_HEADER *Table,
302 UINT32 Name,
303 UINT16 Size
304 )
305 {
306 EFI_STATUS Status;
307 AML_OP_REGION_32_8 *OpRegion;
308 EFI_PHYSICAL_ADDRESS MemoryAddress;
309
310 MemoryAddress = SIZE_4GB - 1;
311
312 //
313 // Patch some pointers for the ASL code before loading the SSDT.
314 //
315 for (OpRegion = (AML_OP_REGION_32_8 *) (Table + 1);
316 OpRegion <= (AML_OP_REGION_32_8 *) ((UINT8 *) Table + Table->Length);
317 OpRegion = (AML_OP_REGION_32_8 *) ((UINT8 *) OpRegion + 1)) {
318 if ((OpRegion->OpRegionOp == AML_EXT_REGION_OP) &&
319 (OpRegion->NameString == Name) &&
320 (OpRegion->DWordPrefix == AML_DWORD_PREFIX) &&
321 (OpRegion->BytePrefix == AML_BYTE_PREFIX)) {
322
323 Status = gBS->AllocatePages(AllocateMaxAddress, EfiACPIMemoryNVS, EFI_SIZE_TO_PAGES (Size), &MemoryAddress);
324 ASSERT_EFI_ERROR (Status);
325 ZeroMem ((VOID *)(UINTN)MemoryAddress, Size);
326 OpRegion->RegionOffset = (UINT32) (UINTN) MemoryAddress;
327 OpRegion->RegionLen = (UINT8) Size;
328 break;
329 }
330 }
331
332 return (VOID *) (UINTN) MemoryAddress;
333 }
334
335 /**
336 Initialize and publish TPM items in ACPI table.
337
338 @retval EFI_SUCCESS The TCG ACPI table is published successfully.
339 @retval Others The TCG ACPI table is not published.
340
341 **/
342 EFI_STATUS
343 PublishAcpiTable (
344 VOID
345 )
346 {
347 EFI_STATUS Status;
348 EFI_ACPI_TABLE_PROTOCOL *AcpiTable;
349 UINTN TableKey;
350 EFI_ACPI_DESCRIPTION_HEADER *Table;
351 UINTN TableSize;
352
353 Status = GetSectionFromFv (
354 &gEfiCallerIdGuid,
355 EFI_SECTION_RAW,
356 0,
357 (VOID **) &Table,
358 &TableSize
359 );
360 ASSERT_EFI_ERROR (Status);
361
362
363 //
364 // Measure to PCR[0] with event EV_POST_CODE ACPI DATA
365 //
366 TpmMeasureAndLogData(
367 0,
368 EV_POST_CODE,
369 EV_POSTCODE_INFO_ACPI_DATA,
370 ACPI_DATA_LEN,
371 Table,
372 TableSize
373 );
374
375
376 ASSERT (Table->OemTableId == SIGNATURE_64 ('T', 'p', 'm', '2', 'T', 'a', 'b', 'l'));
377 CopyMem (Table->OemId, PcdGetPtr (PcdAcpiDefaultOemId), sizeof (Table->OemId) );
378 mTcgNvs = AssignOpRegion (Table, SIGNATURE_32 ('T', 'N', 'V', 'S'), (UINT16) sizeof (TCG_NVS));
379 ASSERT (mTcgNvs != NULL);
380
381 //
382 // Publish the TPM ACPI table
383 //
384 Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &AcpiTable);
385 ASSERT_EFI_ERROR (Status);
386
387 TableKey = 0;
388 Status = AcpiTable->InstallAcpiTable (
389 AcpiTable,
390 Table,
391 TableSize,
392 &TableKey
393 );
394 ASSERT_EFI_ERROR (Status);
395
396 return Status;
397 }
398
399 /**
400 Publish TPM2 ACPI table
401
402 @retval EFI_SUCCESS The TPM2 ACPI table is published successfully.
403 @retval Others The TPM2 ACPI table is not published.
404
405 **/
406 EFI_STATUS
407 PublishTpm2 (
408 VOID
409 )
410 {
411 EFI_STATUS Status;
412 EFI_ACPI_TABLE_PROTOCOL *AcpiTable;
413 UINTN TableKey;
414 UINT64 OemTableId;
415
416 //
417 // Measure to PCR[0] with event EV_POST_CODE ACPI DATA
418 //
419 TpmMeasureAndLogData(
420 0,
421 EV_POST_CODE,
422 EV_POSTCODE_INFO_ACPI_DATA,
423 ACPI_DATA_LEN,
424 &mTpm2AcpiTemplate,
425 sizeof(mTpm2AcpiTemplate)
426 );
427
428 CopyMem (mTpm2AcpiTemplate.Header.OemId, PcdGetPtr (PcdAcpiDefaultOemId), sizeof (mTpm2AcpiTemplate.Header.OemId));
429 OemTableId = PcdGet64 (PcdAcpiDefaultOemTableId);
430 CopyMem (&mTpm2AcpiTemplate.Header.OemTableId, &OemTableId, sizeof (UINT64));
431 mTpm2AcpiTemplate.Header.OemRevision = PcdGet32 (PcdAcpiDefaultOemRevision);
432 mTpm2AcpiTemplate.Header.CreatorId = PcdGet32 (PcdAcpiDefaultCreatorId);
433 mTpm2AcpiTemplate.Header.CreatorRevision = PcdGet32 (PcdAcpiDefaultCreatorRevision);
434
435 //
436 // Construct ACPI table
437 //
438 Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &AcpiTable);
439 ASSERT_EFI_ERROR (Status);
440
441 Status = AcpiTable->InstallAcpiTable (
442 AcpiTable,
443 &mTpm2AcpiTemplate,
444 sizeof(mTpm2AcpiTemplate),
445 &TableKey
446 );
447 ASSERT_EFI_ERROR (Status);
448
449 return Status;
450 }
451
452 /**
453 The driver's entry point.
454
455 It install callbacks for TPM physical presence and MemoryClear, and locate
456 SMM variable to be used in the callback function.
457
458 @param[in] ImageHandle The firmware allocated handle for the EFI image.
459 @param[in] SystemTable A pointer to the EFI System Table.
460
461 @retval EFI_SUCCESS The entry point is executed successfully.
462 @retval Others Some error occurs when executing this entry point.
463
464 **/
465 EFI_STATUS
466 EFIAPI
467 InitializeTcgSmm (
468 IN EFI_HANDLE ImageHandle,
469 IN EFI_SYSTEM_TABLE *SystemTable
470 )
471 {
472 EFI_STATUS Status;
473 EFI_SMM_SW_DISPATCH2_PROTOCOL *SwDispatch;
474 EFI_SMM_SW_REGISTER_CONTEXT SwContext;
475 EFI_HANDLE SwHandle;
476
477 if (!CompareGuid (PcdGetPtr(PcdTpmInstanceGuid), &gEfiTpmDeviceInstanceTpm20DtpmGuid)){
478 DEBUG ((EFI_D_ERROR, "No TPM2 DTPM instance required!\n"));
479 return EFI_UNSUPPORTED;
480 }
481
482 Status = PublishAcpiTable ();
483 ASSERT_EFI_ERROR (Status);
484
485 //
486 // Get the Sw dispatch protocol and register SMI callback functions.
487 //
488 Status = gSmst->SmmLocateProtocol (&gEfiSmmSwDispatch2ProtocolGuid, NULL, (VOID**)&SwDispatch);
489 ASSERT_EFI_ERROR (Status);
490 SwContext.SwSmiInputValue = (UINTN) -1;
491 Status = SwDispatch->Register (SwDispatch, PhysicalPresenceCallback, &SwContext, &SwHandle);
492 ASSERT_EFI_ERROR (Status);
493 if (EFI_ERROR (Status)) {
494 return Status;
495 }
496 mTcgNvs->PhysicalPresence.SoftwareSmi = (UINT8) SwContext.SwSmiInputValue;
497
498 SwContext.SwSmiInputValue = (UINTN) -1;
499 Status = SwDispatch->Register (SwDispatch, MemoryClearCallback, &SwContext, &SwHandle);
500 ASSERT_EFI_ERROR (Status);
501 if (EFI_ERROR (Status)) {
502 return Status;
503 }
504 mTcgNvs->MemoryClear.SoftwareSmi = (UINT8) SwContext.SwSmiInputValue;
505
506 //
507 // Locate SmmVariableProtocol.
508 //
509 Status = gSmst->SmmLocateProtocol (&gEfiSmmVariableProtocolGuid, NULL, (VOID**)&mSmmVariable);
510 ASSERT_EFI_ERROR (Status);
511
512 //
513 // Set TPM2 ACPI table
514 //
515 Status = PublishTpm2 ();
516 ASSERT_EFI_ERROR (Status);
517
518
519 return EFI_SUCCESS;
520 }
521