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