1 /** @file
2   Handle TPM 2.0 physical presence requests from OS.
3 
4   This library will handle TPM 2.0 physical presence request from OS.
5 
6   Caution: This module requires additional review when modified.
7   This driver will have external input - variable.
8   This external input must be validated carefully to avoid security issue.
9 
10   Tcg2PhysicalPresenceLibSubmitRequestToPreOSFunction() and Tcg2PhysicalPresenceLibGetUserConfirmationStatusFunction()
11   will receive untrusted input and do validation.
12 
13 Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
14 This program and the accompanying materials
15 are licensed and made available under the terms and conditions of the BSD License
16 which accompanies this distribution.  The full text of the license may be found at
17 http://opensource.org/licenses/bsd-license.php
18 
19 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
20 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
21 
22 **/
23 
24 #include <PiSmm.h>
25 
26 #include <Guid/Tcg2PhysicalPresenceData.h>
27 
28 #include <Protocol/SmmVariable.h>
29 
30 #include <Library/DebugLib.h>
31 #include <Library/BaseMemoryLib.h>
32 #include <Library/Tcg2PpVendorLib.h>
33 #include <Library/SmmServicesTableLib.h>
34 
35 EFI_SMM_VARIABLE_PROTOCOL  *mTcg2PpSmmVariable;
36 
37 /**
38   The handler for TPM physical presence function:
39   Return TPM Operation Response to OS Environment.
40 
41   This API should be invoked in OS runtime phase to interface with ACPI method.
42 
43   @param[out]     MostRecentRequest Most recent operation request.
44   @param[out]     Response          Response to the most recent operation request.
45 
46   @return Return Code for Return TPM Operation Response to OS Environment.
47 **/
48 UINT32
49 EFIAPI
Tcg2PhysicalPresenceLibReturnOperationResponseToOsFunction(OUT UINT32 * MostRecentRequest,OUT UINT32 * Response)50 Tcg2PhysicalPresenceLibReturnOperationResponseToOsFunction (
51   OUT UINT32                *MostRecentRequest,
52   OUT UINT32                *Response
53   )
54 {
55   EFI_STATUS                        Status;
56   UINTN                             DataSize;
57   EFI_TCG2_PHYSICAL_PRESENCE        PpData;
58 
59   DEBUG ((EFI_D_INFO, "[TPM2] ReturnOperationResponseToOsFunction\n"));
60 
61   //
62   // Get the Physical Presence variable
63   //
64   DataSize = sizeof (EFI_TCG2_PHYSICAL_PRESENCE);
65   Status = mTcg2PpSmmVariable->SmmGetVariable (
66                                  TCG2_PHYSICAL_PRESENCE_VARIABLE,
67                                  &gEfiTcg2PhysicalPresenceGuid,
68                                  NULL,
69                                  &DataSize,
70                                  &PpData
71                                  );
72   if (EFI_ERROR (Status)) {
73     *MostRecentRequest = 0;
74     *Response          = 0;
75     DEBUG ((EFI_D_ERROR, "[TPM2] Get PP variable failure! Status = %r\n", Status));
76     return TCG_PP_RETURN_TPM_OPERATION_RESPONSE_FAILURE;
77   }
78 
79   *MostRecentRequest = PpData.LastPPRequest;
80   *Response          = PpData.PPResponse;
81 
82   return TCG_PP_RETURN_TPM_OPERATION_RESPONSE_SUCCESS;
83 }
84 
85 /**
86   The handler for TPM physical presence function:
87   Submit TPM Operation Request to Pre-OS Environment and
88   Submit TPM Operation Request to Pre-OS Environment 2.
89 
90   This API should be invoked in OS runtime phase to interface with ACPI method.
91 
92   Caution: This function may receive untrusted input.
93 
94   @param[in, out]  Pointer to OperationRequest TPM physical presence operation request.
95   @param[in, out]  Pointer to RequestParameter TPM physical presence operation request parameter.
96 
97   @return Return Code for Submit TPM Operation Request to Pre-OS Environment and
98         Submit TPM Operation Request to Pre-OS Environment 2.
99   **/
100 UINT32
Tcg2PhysicalPresenceLibSubmitRequestToPreOSFunctionEx(IN OUT UINT32 * OperationRequest,IN OUT UINT32 * RequestParameter)101 Tcg2PhysicalPresenceLibSubmitRequestToPreOSFunctionEx (
102   IN OUT UINT32               *OperationRequest,
103   IN OUT UINT32               *RequestParameter
104   )
105 {
106   EFI_STATUS                        Status;
107   UINT32                            ReturnCode;
108   UINTN                             DataSize;
109   EFI_TCG2_PHYSICAL_PRESENCE        PpData;
110   EFI_TCG2_PHYSICAL_PRESENCE_FLAGS  Flags;
111 
112   DEBUG ((EFI_D_INFO, "[TPM2] SubmitRequestToPreOSFunction, Request = %x, %x\n", *OperationRequest, *RequestParameter));
113   ReturnCode = TCG_PP_SUBMIT_REQUEST_TO_PREOS_SUCCESS;
114 
115   //
116   // Get the Physical Presence variable
117   //
118   DataSize = sizeof (EFI_TCG2_PHYSICAL_PRESENCE);
119   Status = mTcg2PpSmmVariable->SmmGetVariable (
120                                  TCG2_PHYSICAL_PRESENCE_VARIABLE,
121                                  &gEfiTcg2PhysicalPresenceGuid,
122                                  NULL,
123                                  &DataSize,
124                                  &PpData
125                                  );
126   if (EFI_ERROR (Status)) {
127     DEBUG ((EFI_D_ERROR, "[TPM2] Get PP variable failure! Status = %r\n", Status));
128     ReturnCode = TCG_PP_SUBMIT_REQUEST_TO_PREOS_GENERAL_FAILURE;
129     goto EXIT;
130   }
131 
132   if ((*OperationRequest > TCG2_PHYSICAL_PRESENCE_NO_ACTION_MAX) &&
133       (*OperationRequest < TCG2_PHYSICAL_PRESENCE_STORAGE_MANAGEMENT_BEGIN) ) {
134     ReturnCode = TCG_PP_SUBMIT_REQUEST_TO_PREOS_NOT_IMPLEMENTED;
135     goto EXIT;
136   }
137 
138   if ((PpData.PPRequest != *OperationRequest) ||
139       (PpData.PPRequestParameter != *RequestParameter)) {
140     PpData.PPRequest = (UINT8)*OperationRequest;
141     PpData.PPRequestParameter = *RequestParameter;
142     DataSize = sizeof (EFI_TCG2_PHYSICAL_PRESENCE);
143     Status = mTcg2PpSmmVariable->SmmSetVariable (
144                                    TCG2_PHYSICAL_PRESENCE_VARIABLE,
145                                    &gEfiTcg2PhysicalPresenceGuid,
146                                    EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
147                                    DataSize,
148                                    &PpData
149                                    );
150     if (EFI_ERROR (Status)) {
151       DEBUG ((EFI_D_ERROR, "[TPM2] Set PP variable failure! Status = %r\n", Status));
152       ReturnCode = TCG_PP_SUBMIT_REQUEST_TO_PREOS_GENERAL_FAILURE;
153       goto EXIT;
154     }
155   }
156 
157   if (*OperationRequest >= TCG2_PHYSICAL_PRESENCE_VENDOR_SPECIFIC_OPERATION) {
158     DataSize = sizeof (EFI_TCG2_PHYSICAL_PRESENCE_FLAGS);
159     Status = mTcg2PpSmmVariable->SmmGetVariable (
160                                    TCG2_PHYSICAL_PRESENCE_FLAGS_VARIABLE,
161                                    &gEfiTcg2PhysicalPresenceGuid,
162                                    NULL,
163                                    &DataSize,
164                                    &Flags
165                                    );
166     if (EFI_ERROR (Status)) {
167       Flags.PPFlags = TCG2_BIOS_TPM_MANAGEMENT_FLAG_DEFAULT | TCG2_BIOS_STORAGE_MANAGEMENT_FLAG_DEFAULT;
168     }
169     ReturnCode = Tcg2PpVendorLibSubmitRequestToPreOSFunction (*OperationRequest, Flags.PPFlags, *RequestParameter);
170   }
171 
172 EXIT:
173   //
174   // Sync PPRQ/PPRM from PP Variable if PP submission fails
175   //
176   if (ReturnCode != TCG_PP_SUBMIT_REQUEST_TO_PREOS_SUCCESS) {
177     DEBUG ((EFI_D_ERROR, "[TPM2] Submit PP Request failure! Sync PPRQ/PPRM with PP variable.\n", Status));
178     DataSize = sizeof (EFI_TCG2_PHYSICAL_PRESENCE);
179     ZeroMem(&PpData, DataSize);
180     Status = mTcg2PpSmmVariable->SmmGetVariable (
181                                    TCG2_PHYSICAL_PRESENCE_VARIABLE,
182                                    &gEfiTcg2PhysicalPresenceGuid,
183                                    NULL,
184                                    &DataSize,
185                                    &PpData
186                                    );
187     *OperationRequest = (UINT32)PpData.PPRequest;
188     *RequestParameter = PpData.PPRequestParameter;
189   }
190 
191   return ReturnCode;
192 }
193 
194 /**
195   The handler for TPM physical presence function:
196   Submit TPM Operation Request to Pre-OS Environment and
197   Submit TPM Operation Request to Pre-OS Environment 2.
198 
199   This API should be invoked in OS runtime phase to interface with ACPI method.
200 
201   Caution: This function may receive untrusted input.
202 
203   @param[in]      OperationRequest TPM physical presence operation request.
204   @param[in]      RequestParameter TPM physical presence operation request parameter.
205 
206   @return Return Code for Submit TPM Operation Request to Pre-OS Environment and
207           Submit TPM Operation Request to Pre-OS Environment 2.
208 **/
209 UINT32
210 EFIAPI
Tcg2PhysicalPresenceLibSubmitRequestToPreOSFunction(IN UINT32 OperationRequest,IN UINT32 RequestParameter)211 Tcg2PhysicalPresenceLibSubmitRequestToPreOSFunction (
212   IN UINT32                 OperationRequest,
213   IN UINT32                 RequestParameter
214   )
215 {
216   UINT32                 TempOperationRequest;
217   UINT32                 TempRequestParameter;
218 
219   TempOperationRequest = OperationRequest;
220   TempRequestParameter = RequestParameter;
221 
222   return Tcg2PhysicalPresenceLibSubmitRequestToPreOSFunctionEx(&TempOperationRequest, &TempRequestParameter);
223 }
224 
225 /**
226   The handler for TPM physical presence function:
227   Get User Confirmation Status for Operation.
228 
229   This API should be invoked in OS runtime phase to interface with ACPI method.
230 
231   Caution: This function may receive untrusted input.
232 
233   @param[in]      OperationRequest TPM physical presence operation request.
234 
235   @return Return Code for Get User Confirmation Status for Operation.
236 **/
237 UINT32
238 EFIAPI
Tcg2PhysicalPresenceLibGetUserConfirmationStatusFunction(IN UINT32 OperationRequest)239 Tcg2PhysicalPresenceLibGetUserConfirmationStatusFunction (
240   IN UINT32                 OperationRequest
241   )
242 {
243   EFI_STATUS                        Status;
244   UINTN                             DataSize;
245   EFI_TCG2_PHYSICAL_PRESENCE        PpData;
246   EFI_TCG2_PHYSICAL_PRESENCE_FLAGS  Flags;
247   BOOLEAN                           RequestConfirmed;
248 
249   DEBUG ((EFI_D_INFO, "[TPM2] GetUserConfirmationStatusFunction, Request = %x\n", OperationRequest));
250 
251   //
252   // Get the Physical Presence variable
253   //
254   DataSize = sizeof (EFI_TCG2_PHYSICAL_PRESENCE);
255   Status = mTcg2PpSmmVariable->SmmGetVariable (
256                                  TCG2_PHYSICAL_PRESENCE_VARIABLE,
257                                  &gEfiTcg2PhysicalPresenceGuid,
258                                  NULL,
259                                  &DataSize,
260                                  &PpData
261                                  );
262   if (EFI_ERROR (Status)) {
263     DEBUG ((EFI_D_ERROR, "[TPM2] Get PP variable failure! Status = %r\n", Status));
264     return TCG_PP_GET_USER_CONFIRMATION_BLOCKED_BY_BIOS_CONFIGURATION;
265   }
266   //
267   // Get the Physical Presence flags
268   //
269   DataSize = sizeof (EFI_TCG2_PHYSICAL_PRESENCE_FLAGS);
270   Status = mTcg2PpSmmVariable->SmmGetVariable (
271                                  TCG2_PHYSICAL_PRESENCE_FLAGS_VARIABLE,
272                                  &gEfiTcg2PhysicalPresenceGuid,
273                                  NULL,
274                                  &DataSize,
275                                  &Flags
276                                  );
277   if (EFI_ERROR (Status)) {
278     DEBUG ((EFI_D_ERROR, "[TPM2] Get PP flags failure! Status = %r\n", Status));
279     return TCG_PP_GET_USER_CONFIRMATION_BLOCKED_BY_BIOS_CONFIGURATION;
280   }
281 
282   RequestConfirmed = FALSE;
283 
284   switch (OperationRequest) {
285     case TCG2_PHYSICAL_PRESENCE_CLEAR:
286     case TCG2_PHYSICAL_PRESENCE_ENABLE_CLEAR:
287     case TCG2_PHYSICAL_PRESENCE_ENABLE_CLEAR_2:
288     case TCG2_PHYSICAL_PRESENCE_ENABLE_CLEAR_3:
289       if ((Flags.PPFlags & TCG2_BIOS_TPM_MANAGEMENT_FLAG_PP_REQUIRED_FOR_CLEAR) == 0) {
290         RequestConfirmed = TRUE;
291       }
292       break;
293 
294     case TCG2_PHYSICAL_PRESENCE_SET_PP_REQUIRED_FOR_CLEAR_TRUE:
295       RequestConfirmed = TRUE;
296       break;
297 
298     case TCG2_PHYSICAL_PRESENCE_SET_PP_REQUIRED_FOR_CLEAR_FALSE:
299       break;
300 
301     case TCG2_PHYSICAL_PRESENCE_SET_PCR_BANKS:
302       if ((Flags.PPFlags & TCG2_BIOS_TPM_MANAGEMENT_FLAG_PP_REQUIRED_FOR_CHANGE_PCRS) == 0) {
303         RequestConfirmed = TRUE;
304       }
305       break;
306 
307     case TCG2_PHYSICAL_PRESENCE_CHANGE_EPS:
308       if ((Flags.PPFlags & TCG2_BIOS_TPM_MANAGEMENT_FLAG_PP_REQUIRED_FOR_CHANGE_EPS) == 0) {
309         RequestConfirmed = TRUE;
310       }
311       break;
312 
313     case TCG2_PHYSICAL_PRESENCE_LOG_ALL_DIGESTS:
314       RequestConfirmed = TRUE;
315       break;
316 
317     case TCG2_PHYSICAL_PRESENCE_ENABLE_BLOCK_SID:
318       if ((Flags.PPFlags & TCG2_BIOS_STORAGE_MANAGEMENT_FLAG_PP_REQUIRED_FOR_ENABLE_BLOCK_SID) == 0) {
319         RequestConfirmed = TRUE;
320       }
321       break;
322 
323     case TCG2_PHYSICAL_PRESENCE_DISABLE_BLOCK_SID:
324       if ((Flags.PPFlags & TCG2_BIOS_STORAGE_MANAGEMENT_FLAG_PP_REQUIRED_FOR_DISABLE_BLOCK_SID) == 0) {
325         RequestConfirmed = TRUE;
326       }
327       break;
328 
329     case TCG2_PHYSICAL_PRESENCE_SET_PP_REQUIRED_FOR_ENABLE_BLOCK_SID_FUNC_TRUE:
330     case TCG2_PHYSICAL_PRESENCE_SET_PP_REQUIRED_FOR_DISABLE_BLOCK_SID_FUNC_TRUE:
331       RequestConfirmed = TRUE;
332       break;
333 
334     case TCG2_PHYSICAL_PRESENCE_SET_PP_REQUIRED_FOR_ENABLE_BLOCK_SID_FUNC_FALSE:
335     case TCG2_PHYSICAL_PRESENCE_SET_PP_REQUIRED_FOR_DISABLE_BLOCK_SID_FUNC_FALSE:
336       break;
337 
338     default:
339       if (OperationRequest <= TCG2_PHYSICAL_PRESENCE_NO_ACTION_MAX) {
340         RequestConfirmed = TRUE;
341       } else {
342         if (OperationRequest < TCG2_PHYSICAL_PRESENCE_VENDOR_SPECIFIC_OPERATION) {
343           return TCG_PP_GET_USER_CONFIRMATION_NOT_IMPLEMENTED;
344         }
345       }
346       break;
347   }
348 
349   if (OperationRequest >= TCG2_PHYSICAL_PRESENCE_VENDOR_SPECIFIC_OPERATION) {
350     return Tcg2PpVendorLibGetUserConfirmationStatusFunction (OperationRequest, Flags.PPFlags);
351   }
352 
353   if (RequestConfirmed) {
354     return TCG_PP_GET_USER_CONFIRMATION_ALLOWED_AND_PPUSER_NOT_REQUIRED;
355   } else {
356     return TCG_PP_GET_USER_CONFIRMATION_ALLOWED_AND_PPUSER_REQUIRED;
357   }
358 }
359 
360 /**
361   The constructor function locates SmmVariable protocol.
362 
363   It will ASSERT() if that operation fails and it will always return EFI_SUCCESS.
364 
365   @param  ImageHandle   The firmware allocated handle for the EFI image.
366   @param  SystemTable   A pointer to the EFI System Table.
367 
368   @retval EFI_SUCCESS   The constructor successfully added string package.
369   @retval Other value   The constructor can't add string package.
370 **/
371 EFI_STATUS
372 EFIAPI
Tcg2PhysicalPresenceLibConstructor(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)373 Tcg2PhysicalPresenceLibConstructor (
374   IN EFI_HANDLE        ImageHandle,
375   IN EFI_SYSTEM_TABLE  *SystemTable
376   )
377 {
378   EFI_STATUS  Status;
379 
380   //
381   // Locate SmmVariableProtocol.
382   //
383   Status = gSmst->SmmLocateProtocol (&gEfiSmmVariableProtocolGuid, NULL, (VOID**)&mTcg2PpSmmVariable);
384   ASSERT_EFI_ERROR (Status);
385 
386   return EFI_SUCCESS;
387 }
388