1 /** @file
2   Execute pending TPM2 requests from OS or BIOS.
3 
4   Caution: This module requires additional review when modified.
5   This driver will have external input - variable.
6   This external input must be validated carefully to avoid security issue.
7 
8   TrEEExecutePendingTpmRequest() will receive untrusted input and do validation.
9 
10 Copyright (c) 2013 - 2015, Intel Corporation. All rights reserved.<BR>
11 This program and the accompanying materials
12 are licensed and made available under the terms and conditions of the BSD License
13 which accompanies this distribution.  The full text of the license may be found at
14 http://opensource.org/licenses/bsd-license.php
15 
16 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
17 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 
19 **/
20 
21 #include <PiDxe.h>
22 
23 #include <Protocol/TrEEProtocol.h>
24 #include <Protocol/VariableLock.h>
25 #include <Library/DebugLib.h>
26 #include <Library/BaseMemoryLib.h>
27 #include <Library/UefiRuntimeServicesTableLib.h>
28 #include <Library/UefiDriverEntryPoint.h>
29 #include <Library/UefiBootServicesTableLib.h>
30 #include <Library/UefiLib.h>
31 #include <Library/MemoryAllocationLib.h>
32 #include <Library/PrintLib.h>
33 #include <Library/HiiLib.h>
34 #include <Guid/EventGroup.h>
35 #include <Guid/TrEEPhysicalPresenceData.h>
36 #include <Library/Tpm2CommandLib.h>
37 #include <Library/TrEEPpVendorLib.h>
38 
39 #define CONFIRM_BUFFER_SIZE         4096
40 
41 EFI_HII_HANDLE mTrEEPpStringPackHandle;
42 
43 /**
44   Get string by string id from HII Interface.
45 
46   @param[in] Id          String ID.
47 
48   @retval    CHAR16 *    String from ID.
49   @retval    NULL        If error occurs.
50 
51 **/
52 CHAR16 *
TrEEPhysicalPresenceGetStringById(IN EFI_STRING_ID Id)53 TrEEPhysicalPresenceGetStringById (
54   IN  EFI_STRING_ID   Id
55   )
56 {
57   return HiiGetString (mTrEEPpStringPackHandle, Id, NULL);
58 }
59 
60 /**
61   Send ClearControl and Clear command to TPM.
62 
63   @param[in]  PlatformAuth      platform auth value. NULL means no platform auth change.
64 
65   @retval EFI_SUCCESS           Operation completed successfully.
66   @retval EFI_TIMEOUT           The register can't run into the expected status in time.
67   @retval EFI_BUFFER_TOO_SMALL  Response data buffer is too small.
68   @retval EFI_DEVICE_ERROR      Unexpected device behavior.
69 
70 **/
71 EFI_STATUS
72 EFIAPI
TpmCommandClear(IN TPM2B_AUTH * PlatformAuth OPTIONAL)73 TpmCommandClear (
74   IN TPM2B_AUTH                *PlatformAuth  OPTIONAL
75   )
76 {
77   EFI_STATUS                Status;
78   TPMS_AUTH_COMMAND         *AuthSession;
79   TPMS_AUTH_COMMAND         LocalAuthSession;
80 
81   if (PlatformAuth == NULL) {
82     AuthSession = NULL;
83   } else {
84     AuthSession = &LocalAuthSession;
85     ZeroMem (&LocalAuthSession, sizeof(LocalAuthSession));
86     LocalAuthSession.sessionHandle = TPM_RS_PW;
87     LocalAuthSession.hmac.size = PlatformAuth->size;
88     CopyMem (LocalAuthSession.hmac.buffer, PlatformAuth->buffer, PlatformAuth->size);
89   }
90 
91   DEBUG ((EFI_D_INFO, "Tpm2ClearControl ... \n"));
92   Status = Tpm2ClearControl (TPM_RH_PLATFORM, AuthSession, NO);
93   DEBUG ((EFI_D_INFO, "Tpm2ClearControl - %r\n", Status));
94   if (EFI_ERROR (Status)) {
95     goto Done;
96   }
97   DEBUG ((EFI_D_INFO, "Tpm2Clear ... \n"));
98   Status = Tpm2Clear (TPM_RH_PLATFORM, AuthSession);
99   DEBUG ((EFI_D_INFO, "Tpm2Clear - %r\n", Status));
100 
101 Done:
102   ZeroMem (&LocalAuthSession.hmac, sizeof(LocalAuthSession.hmac));
103   return Status;
104 }
105 
106 /**
107   Execute physical presence operation requested by the OS.
108 
109   @param[in]      PlatformAuth        platform auth value. NULL means no platform auth change.
110   @param[in]      CommandCode         Physical presence operation value.
111   @param[in, out] PpiFlags            The physical presence interface flags.
112 
113   @retval TREE_PP_OPERATION_RESPONSE_BIOS_FAILURE  Unknown physical presence operation.
114   @retval TREE_PP_OPERATION_RESPONSE_BIOS_FAILURE  Error occurred during sending command to TPM or
115                                                    receiving response from TPM.
116   @retval Others                                   Return code from the TPM device after command execution.
117 **/
118 UINT32
TrEEExecutePhysicalPresence(IN TPM2B_AUTH * PlatformAuth,OPTIONAL IN UINT32 CommandCode,IN OUT EFI_TREE_PHYSICAL_PRESENCE_FLAGS * PpiFlags)119 TrEEExecutePhysicalPresence (
120   IN      TPM2B_AUTH                       *PlatformAuth,  OPTIONAL
121   IN      UINT32                           CommandCode,
122   IN OUT  EFI_TREE_PHYSICAL_PRESENCE_FLAGS *PpiFlags
123   )
124 {
125   EFI_STATUS  Status;
126 
127   switch (CommandCode) {
128     case TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR:
129     case TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR_2:
130     case TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR_3:
131     case TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR_4:
132       Status = TpmCommandClear (PlatformAuth);
133       if (EFI_ERROR (Status)) {
134         return TREE_PP_OPERATION_RESPONSE_BIOS_FAILURE;
135       } else {
136         return TREE_PP_OPERATION_RESPONSE_SUCCESS;
137       }
138 
139     case TREE_PHYSICAL_PRESENCE_SET_NO_PPI_CLEAR_FALSE:
140       PpiFlags->PPFlags &= ~TREE_BIOS_TPM_MANAGEMENT_FLAG_NO_PPI_CLEAR;
141       return TREE_PP_OPERATION_RESPONSE_SUCCESS;
142 
143     case TREE_PHYSICAL_PRESENCE_SET_NO_PPI_CLEAR_TRUE:
144       PpiFlags->PPFlags |= TREE_BIOS_TPM_MANAGEMENT_FLAG_NO_PPI_CLEAR;
145       return TREE_PP_OPERATION_RESPONSE_SUCCESS;
146 
147     default:
148       if (CommandCode <= TREE_PHYSICAL_PRESENCE_NO_ACTION_MAX) {
149         return TREE_PP_OPERATION_RESPONSE_SUCCESS;
150       } else {
151         return TREE_PP_OPERATION_RESPONSE_BIOS_FAILURE;
152       }
153   }
154 }
155 
156 
157 /**
158   Read the specified key for user confirmation.
159 
160   @param[in]  CautionKey  If true,  F12 is used as confirm key;
161                           If false, F10 is used as confirm key.
162 
163   @retval     TRUE        User confirmed the changes by input.
164   @retval     FALSE       User discarded the changes.
165 **/
166 BOOLEAN
TrEEReadUserKey(IN BOOLEAN CautionKey)167 TrEEReadUserKey (
168   IN     BOOLEAN                    CautionKey
169   )
170 {
171   EFI_STATUS                        Status;
172   EFI_INPUT_KEY                     Key;
173   UINT16                            InputKey;
174 
175   InputKey = 0;
176   do {
177     Status = gBS->CheckEvent (gST->ConIn->WaitForKey);
178     if (!EFI_ERROR (Status)) {
179       Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
180       if (Key.ScanCode == SCAN_ESC) {
181         InputKey = Key.ScanCode;
182       }
183       if ((Key.ScanCode == SCAN_F10) && !CautionKey) {
184         InputKey = Key.ScanCode;
185       }
186       if ((Key.ScanCode == SCAN_F12) && CautionKey) {
187         InputKey = Key.ScanCode;
188       }
189     }
190   } while (InputKey == 0);
191 
192   if (InputKey != SCAN_ESC) {
193     return TRUE;
194   }
195 
196   return FALSE;
197 }
198 
199 /**
200   The constructor function register UNI strings into imageHandle.
201 
202   It will ASSERT() if that operation fails and it will always return EFI_SUCCESS.
203 
204   @param  ImageHandle   The firmware allocated handle for the EFI image.
205   @param  SystemTable   A pointer to the EFI System Table.
206 
207   @retval EFI_SUCCESS   The constructor successfully added string package.
208   @retval Other value   The constructor can't add string package.
209 **/
210 EFI_STATUS
211 EFIAPI
TrEEPhysicalPresenceLibConstructor(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)212 TrEEPhysicalPresenceLibConstructor (
213   IN EFI_HANDLE        ImageHandle,
214   IN EFI_SYSTEM_TABLE  *SystemTable
215   )
216 {
217   mTrEEPpStringPackHandle = HiiAddPackages (&gEfiTrEEPhysicalPresenceGuid, ImageHandle, DxeTrEEPhysicalPresenceLibStrings, NULL);
218   ASSERT (mTrEEPpStringPackHandle != NULL);
219 
220   return EFI_SUCCESS;
221 }
222 
223 /**
224   Display the confirm text and get user confirmation.
225 
226   @param[in] TpmPpCommand  The requested TPM physical presence command.
227 
228   @retval    TRUE          The user has confirmed the changes.
229   @retval    FALSE         The user doesn't confirm the changes.
230 **/
231 BOOLEAN
TrEEUserConfirm(IN UINT32 TpmPpCommand)232 TrEEUserConfirm (
233   IN      UINT32                    TpmPpCommand
234   )
235 {
236   CHAR16                            *ConfirmText;
237   CHAR16                            *TmpStr1;
238   CHAR16                            *TmpStr2;
239   UINTN                             BufSize;
240   BOOLEAN                           CautionKey;
241   UINT16                            Index;
242   CHAR16                            DstStr[81];
243 
244   TmpStr2     = NULL;
245   CautionKey  = FALSE;
246   BufSize     = CONFIRM_BUFFER_SIZE;
247   ConfirmText = AllocateZeroPool (BufSize);
248   ASSERT (ConfirmText != NULL);
249 
250   switch (TpmPpCommand) {
251 
252     case TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR:
253     case TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR_2:
254     case TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR_3:
255     case TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR_4:
256       CautionKey = TRUE;
257       TmpStr2 = TrEEPhysicalPresenceGetStringById (STRING_TOKEN (TPM_CLEAR));
258 
259       TmpStr1 = TrEEPhysicalPresenceGetStringById (STRING_TOKEN (TPM_HEAD_STR));
260       UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2);
261       FreePool (TmpStr1);
262 
263       TmpStr1 = TrEEPhysicalPresenceGetStringById (STRING_TOKEN (TPM_WARNING_CLEAR));
264       StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
265       StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), L" \n\n", (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
266       FreePool (TmpStr1);
267 
268       TmpStr1 = TrEEPhysicalPresenceGetStringById (STRING_TOKEN (TPM_CAUTION_KEY));
269       StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
270       FreePool (TmpStr1);
271       break;
272 
273     case TREE_PHYSICAL_PRESENCE_SET_NO_PPI_CLEAR_TRUE:
274       CautionKey = TRUE;
275       TmpStr2 = TrEEPhysicalPresenceGetStringById (STRING_TOKEN (TPM_CLEAR));
276 
277       TmpStr1 = TrEEPhysicalPresenceGetStringById (STRING_TOKEN (TPM_PPI_HEAD_STR));
278       UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2);
279       FreePool (TmpStr1);
280 
281       TmpStr1 = TrEEPhysicalPresenceGetStringById (STRING_TOKEN (TPM_NOTE_CLEAR));
282       StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
283       FreePool (TmpStr1);
284 
285       TmpStr1 = TrEEPhysicalPresenceGetStringById (STRING_TOKEN (TPM_WARNING_CLEAR));
286       StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
287       StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), L" \n\n", (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
288       FreePool (TmpStr1);
289 
290       TmpStr1 = TrEEPhysicalPresenceGetStringById (STRING_TOKEN (TPM_CAUTION_KEY));
291       StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
292       FreePool (TmpStr1);
293 
294       TmpStr1 = TrEEPhysicalPresenceGetStringById (STRING_TOKEN (TPM_NO_PPI_INFO));
295       StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
296       FreePool (TmpStr1);
297       break;
298 
299     default:
300       ;
301   }
302 
303   if (TmpStr2 == NULL) {
304     FreePool (ConfirmText);
305     return FALSE;
306   }
307 
308   TmpStr1 = TrEEPhysicalPresenceGetStringById (STRING_TOKEN (TPM_REJECT_KEY));
309   BufSize -= StrSize (ConfirmText);
310   UnicodeSPrint (ConfirmText + StrLen (ConfirmText), BufSize, TmpStr1, TmpStr2);
311 
312   DstStr[80] = L'\0';
313   for (Index = 0; Index < StrLen (ConfirmText); Index += 80) {
314     StrnCpyS(DstStr, sizeof (DstStr) / sizeof (CHAR16), ConfirmText + Index, sizeof (DstStr) / sizeof (CHAR16) - 1);
315     Print (DstStr);
316   }
317 
318   FreePool (TmpStr1);
319   FreePool (TmpStr2);
320   FreePool (ConfirmText);
321 
322   if (TrEEReadUserKey (CautionKey)) {
323     return TRUE;
324   }
325 
326   return FALSE;
327 }
328 
329 /**
330   Check if there is a valid physical presence command request. Also updates parameter value
331   to whether the requested physical presence command already confirmed by user
332 
333    @param[in]  TcgPpData                 EFI TrEE Physical Presence request data.
334    @param[in]  Flags                     The physical presence interface flags.
335    @param[out] RequestConfirmed            If the physical presence operation command required user confirm from UI.
336                                              True, it indicates the command doesn't require user confirm, or already confirmed
337                                                    in last boot cycle by user.
338                                              False, it indicates the command need user confirm from UI.
339 
340    @retval  TRUE        Physical Presence operation command is valid.
341    @retval  FALSE       Physical Presence operation command is invalid.
342 
343 **/
344 BOOLEAN
TrEEHaveValidTpmRequest(IN EFI_TREE_PHYSICAL_PRESENCE * TcgPpData,IN EFI_TREE_PHYSICAL_PRESENCE_FLAGS Flags,OUT BOOLEAN * RequestConfirmed)345 TrEEHaveValidTpmRequest  (
346   IN      EFI_TREE_PHYSICAL_PRESENCE       *TcgPpData,
347   IN      EFI_TREE_PHYSICAL_PRESENCE_FLAGS Flags,
348   OUT     BOOLEAN                          *RequestConfirmed
349   )
350 {
351   BOOLEAN  IsRequestValid;
352 
353   *RequestConfirmed = FALSE;
354 
355   switch (TcgPpData->PPRequest) {
356     case TREE_PHYSICAL_PRESENCE_NO_ACTION:
357       *RequestConfirmed = TRUE;
358       return TRUE;
359     case TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR:
360     case TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR_2:
361     case TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR_3:
362     case TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR_4:
363       if ((Flags.PPFlags & TREE_BIOS_TPM_MANAGEMENT_FLAG_NO_PPI_CLEAR) != 0) {
364         *RequestConfirmed = TRUE;
365       }
366       break;
367 
368     case TREE_PHYSICAL_PRESENCE_SET_NO_PPI_CLEAR_FALSE:
369       *RequestConfirmed = TRUE;
370       break;
371 
372     case TREE_PHYSICAL_PRESENCE_SET_NO_PPI_CLEAR_TRUE:
373       break;
374 
375     default:
376       if (TcgPpData->PPRequest >= TREE_PHYSICAL_PRESENCE_VENDOR_SPECIFIC_OPERATION) {
377         IsRequestValid = TrEEPpVendorLibHasValidRequest (TcgPpData->PPRequest, Flags.PPFlags, RequestConfirmed);
378         if (!IsRequestValid) {
379           return FALSE;
380         } else {
381           break;
382         }
383       } else {
384         //
385         // Wrong Physical Presence command
386         //
387         return FALSE;
388       }
389   }
390 
391   if ((Flags.PPFlags & TREE_VENDOR_LIB_FLAG_RESET_TRACK) != 0) {
392     //
393     // It had been confirmed in last boot, it doesn't need confirm again.
394     //
395     *RequestConfirmed = TRUE;
396   }
397 
398   //
399   // Physical Presence command is correct
400   //
401   return TRUE;
402 }
403 
404 
405 /**
406   Check and execute the requested physical presence command.
407 
408   Caution: This function may receive untrusted input.
409   TcgPpData variable is external input, so this function will validate
410   its data structure to be valid value.
411 
412   @param[in] PlatformAuth         platform auth value. NULL means no platform auth change.
413   @param[in] TcgPpData            Point to the physical presence NV variable.
414   @param[in] Flags                The physical presence interface flags.
415 **/
416 VOID
TrEEExecutePendingTpmRequest(IN TPM2B_AUTH * PlatformAuth,OPTIONAL IN EFI_TREE_PHYSICAL_PRESENCE * TcgPpData,IN EFI_TREE_PHYSICAL_PRESENCE_FLAGS Flags)417 TrEEExecutePendingTpmRequest (
418   IN      TPM2B_AUTH                       *PlatformAuth,  OPTIONAL
419   IN      EFI_TREE_PHYSICAL_PRESENCE       *TcgPpData,
420   IN      EFI_TREE_PHYSICAL_PRESENCE_FLAGS Flags
421   )
422 {
423   EFI_STATUS                        Status;
424   UINTN                             DataSize;
425   BOOLEAN                           RequestConfirmed;
426   EFI_TREE_PHYSICAL_PRESENCE_FLAGS  NewFlags;
427   BOOLEAN                           ResetRequired;
428   UINT32                            NewPPFlags;
429 
430   if (TcgPpData->PPRequest == TREE_PHYSICAL_PRESENCE_NO_ACTION) {
431     //
432     // No operation request
433     //
434     return;
435   }
436 
437   if (!TrEEHaveValidTpmRequest(TcgPpData, Flags, &RequestConfirmed)) {
438     //
439     // Invalid operation request.
440     //
441     if (TcgPpData->PPRequest <= TREE_PHYSICAL_PRESENCE_NO_ACTION_MAX) {
442       TcgPpData->PPResponse = TREE_PP_OPERATION_RESPONSE_SUCCESS;
443     } else {
444       TcgPpData->PPResponse = TREE_PP_OPERATION_RESPONSE_BIOS_FAILURE;
445     }
446     TcgPpData->LastPPRequest = TcgPpData->PPRequest;
447     TcgPpData->PPRequest = TREE_PHYSICAL_PRESENCE_NO_ACTION;
448     DataSize = sizeof (EFI_TREE_PHYSICAL_PRESENCE);
449     Status = gRT->SetVariable (
450                     TREE_PHYSICAL_PRESENCE_VARIABLE,
451                     &gEfiTrEEPhysicalPresenceGuid,
452                     EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
453                     DataSize,
454                     TcgPpData
455                     );
456     return;
457   }
458 
459   ResetRequired = FALSE;
460   if (TcgPpData->PPRequest >= TREE_PHYSICAL_PRESENCE_VENDOR_SPECIFIC_OPERATION) {
461     NewFlags = Flags;
462     NewPPFlags = NewFlags.PPFlags;
463     TcgPpData->PPResponse = TrEEPpVendorLibExecutePendingRequest (PlatformAuth, TcgPpData->PPRequest, &NewPPFlags, &ResetRequired);
464     NewFlags.PPFlags = (UINT8)NewPPFlags;
465   } else {
466     if (!RequestConfirmed) {
467       //
468       // Print confirm text and wait for approval.
469       //
470       RequestConfirmed = TrEEUserConfirm (TcgPpData->PPRequest
471                                           );
472     }
473 
474     //
475     // Execute requested physical presence command
476     //
477     TcgPpData->PPResponse = TREE_PP_OPERATION_RESPONSE_USER_ABORT;
478     NewFlags = Flags;
479     if (RequestConfirmed) {
480       TcgPpData->PPResponse = TrEEExecutePhysicalPresence (PlatformAuth, TcgPpData->PPRequest,
481                                                            &NewFlags);
482     }
483   }
484 
485   //
486   // Save the flags if it is updated.
487   //
488   if (CompareMem (&Flags, &NewFlags, sizeof(EFI_TREE_PHYSICAL_PRESENCE_FLAGS)) != 0) {
489     Status   = gRT->SetVariable (
490                       TREE_PHYSICAL_PRESENCE_FLAGS_VARIABLE,
491                       &gEfiTrEEPhysicalPresenceGuid,
492                       EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
493                       sizeof (EFI_TREE_PHYSICAL_PRESENCE_FLAGS),
494                       &NewFlags
495                       );
496   }
497 
498   //
499   // Clear request
500   //
501   if ((NewFlags.PPFlags & TREE_VENDOR_LIB_FLAG_RESET_TRACK) == 0) {
502     TcgPpData->LastPPRequest = TcgPpData->PPRequest;
503     TcgPpData->PPRequest = TREE_PHYSICAL_PRESENCE_NO_ACTION;
504   }
505 
506   //
507   // Save changes
508   //
509   DataSize = sizeof (EFI_TREE_PHYSICAL_PRESENCE);
510   Status = gRT->SetVariable (
511                   TREE_PHYSICAL_PRESENCE_VARIABLE,
512                   &gEfiTrEEPhysicalPresenceGuid,
513                   EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
514                   DataSize,
515                   TcgPpData
516                   );
517   if (EFI_ERROR (Status)) {
518     return;
519   }
520 
521   if (TcgPpData->PPResponse == TREE_PP_OPERATION_RESPONSE_USER_ABORT) {
522     return;
523   }
524 
525   //
526   // Reset system to make new TPM settings in effect
527   //
528   switch (TcgPpData->LastPPRequest) {
529     case TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR:
530     case TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR_2:
531     case TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR_3:
532     case TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR_4:
533       break;
534     default:
535       if (TcgPpData->LastPPRequest >= TREE_PHYSICAL_PRESENCE_VENDOR_SPECIFIC_OPERATION) {
536         if (ResetRequired) {
537           break;
538         } else {
539           return ;
540         }
541       }
542       if (TcgPpData->PPRequest != TREE_PHYSICAL_PRESENCE_NO_ACTION) {
543         break;
544       }
545       return;
546   }
547 
548   Print (L"Rebooting system to make TPM2 settings in effect\n");
549   gRT->ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL);
550   ASSERT (FALSE);
551 }
552 
553 /**
554   Check and execute the pending TPM request.
555 
556   The TPM request may come from OS or BIOS. This API will display request information and wait
557   for user confirmation if TPM request exists. The TPM request will be sent to TPM device after
558   the TPM request is confirmed, and one or more reset may be required to make TPM request to
559   take effect.
560 
561   This API should be invoked after console in and console out are all ready as they are required
562   to display request information and get user input to confirm the request.
563 
564   @param[in]  PlatformAuth                   platform auth value. NULL means no platform auth change.
565 **/
566 VOID
567 EFIAPI
TrEEPhysicalPresenceLibProcessRequest(IN TPM2B_AUTH * PlatformAuth OPTIONAL)568 TrEEPhysicalPresenceLibProcessRequest (
569   IN      TPM2B_AUTH                     *PlatformAuth  OPTIONAL
570   )
571 {
572   EFI_STATUS                        Status;
573   UINTN                             DataSize;
574   EFI_TREE_PHYSICAL_PRESENCE        TcgPpData;
575   EFI_TREE_PROTOCOL                 *TreeProtocol;
576   EDKII_VARIABLE_LOCK_PROTOCOL      *VariableLockProtocol;
577   EFI_TREE_PHYSICAL_PRESENCE_FLAGS  PpiFlags;
578 
579   Status = gBS->LocateProtocol (&gEfiTrEEProtocolGuid, NULL, (VOID **) &TreeProtocol);
580   if (EFI_ERROR (Status)) {
581     return ;
582   }
583 
584   //
585   // Initialize physical presence flags.
586   //
587   DataSize = sizeof (EFI_TREE_PHYSICAL_PRESENCE_FLAGS);
588   Status = gRT->GetVariable (
589                   TREE_PHYSICAL_PRESENCE_FLAGS_VARIABLE,
590                   &gEfiTrEEPhysicalPresenceGuid,
591                   NULL,
592                   &DataSize,
593                   &PpiFlags
594                   );
595   if (EFI_ERROR (Status)) {
596     PpiFlags.PPFlags = 0;
597     Status   = gRT->SetVariable (
598                       TREE_PHYSICAL_PRESENCE_FLAGS_VARIABLE,
599                       &gEfiTrEEPhysicalPresenceGuid,
600                       EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
601                       sizeof (EFI_TREE_PHYSICAL_PRESENCE_FLAGS),
602                       &PpiFlags
603                       );
604     if (EFI_ERROR (Status)) {
605       DEBUG ((EFI_D_ERROR, "[TPM2] Set physical presence flag failed, Status = %r\n", Status));
606       return ;
607     }
608   }
609   DEBUG ((EFI_D_INFO, "[TPM2] PpiFlags = %x\n", PpiFlags.PPFlags));
610 
611   //
612   // This flags variable controls whether physical presence is required for TPM command.
613   // It should be protected from malicious software. We set it as read-only variable here.
614   //
615   Status = gBS->LocateProtocol (&gEdkiiVariableLockProtocolGuid, NULL, (VOID **)&VariableLockProtocol);
616   if (!EFI_ERROR (Status)) {
617     Status = VariableLockProtocol->RequestToLock (
618                                      VariableLockProtocol,
619                                      TREE_PHYSICAL_PRESENCE_FLAGS_VARIABLE,
620                                      &gEfiTrEEPhysicalPresenceGuid
621                                      );
622     if (EFI_ERROR (Status)) {
623       DEBUG ((EFI_D_ERROR, "[TPM2] Error when lock variable %s, Status = %r\n", TREE_PHYSICAL_PRESENCE_FLAGS_VARIABLE, Status));
624       ASSERT_EFI_ERROR (Status);
625     }
626   }
627 
628   //
629   // Initialize physical presence variable.
630   //
631   DataSize = sizeof (EFI_TREE_PHYSICAL_PRESENCE);
632   Status = gRT->GetVariable (
633                   TREE_PHYSICAL_PRESENCE_VARIABLE,
634                   &gEfiTrEEPhysicalPresenceGuid,
635                   NULL,
636                   &DataSize,
637                   &TcgPpData
638                   );
639   if (EFI_ERROR (Status)) {
640     ZeroMem ((VOID*)&TcgPpData, sizeof (TcgPpData));
641     DataSize = sizeof (EFI_TREE_PHYSICAL_PRESENCE);
642     Status   = gRT->SetVariable (
643                       TREE_PHYSICAL_PRESENCE_VARIABLE,
644                       &gEfiTrEEPhysicalPresenceGuid,
645                       EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
646                       DataSize,
647                       &TcgPpData
648                       );
649     if (EFI_ERROR (Status)) {
650       DEBUG ((EFI_D_ERROR, "[TPM2] Set physical presence variable failed, Status = %r\n", Status));
651       return ;
652     }
653   }
654 
655   DEBUG ((EFI_D_INFO, "[TPM2] Flags=%x, PPRequest=%x (LastPPRequest=%x)\n", PpiFlags.PPFlags, TcgPpData.PPRequest, TcgPpData.LastPPRequest));
656 
657   //
658   // Execute pending TPM request.
659   //
660   TrEEExecutePendingTpmRequest (PlatformAuth, &TcgPpData, PpiFlags);
661   DEBUG ((EFI_D_INFO, "[TPM2] PPResponse = %x (LastPPRequest=%x, Flags=%x)\n", TcgPpData.PPResponse, TcgPpData.LastPPRequest, PpiFlags.PPFlags));
662 
663 }
664 
665 /**
666   Check if the pending TPM request needs user input to confirm.
667 
668   The TPM request may come from OS. This API will check if TPM request exists and need user
669   input to confirmation.
670 
671   @retval    TRUE        TPM needs input to confirm user physical presence.
672   @retval    FALSE       TPM doesn't need input to confirm user physical presence.
673 
674 **/
675 BOOLEAN
676 EFIAPI
TrEEPhysicalPresenceLibNeedUserConfirm(VOID)677 TrEEPhysicalPresenceLibNeedUserConfirm(
678   VOID
679   )
680 {
681   EFI_STATUS                        Status;
682   EFI_TREE_PHYSICAL_PRESENCE        TcgPpData;
683   UINTN                             DataSize;
684   BOOLEAN                           RequestConfirmed;
685   EFI_TREE_PROTOCOL                 *TreeProtocol;
686   EFI_TREE_PHYSICAL_PRESENCE_FLAGS  PpiFlags;
687 
688   Status = gBS->LocateProtocol (&gEfiTrEEProtocolGuid, NULL, (VOID **) &TreeProtocol);
689   if (EFI_ERROR (Status)) {
690     return FALSE;
691   }
692 
693   //
694   // Check Tpm requests
695   //
696   DataSize = sizeof (EFI_TREE_PHYSICAL_PRESENCE);
697   Status = gRT->GetVariable (
698                   TREE_PHYSICAL_PRESENCE_VARIABLE,
699                   &gEfiTrEEPhysicalPresenceGuid,
700                   NULL,
701                   &DataSize,
702                   &TcgPpData
703                   );
704   if (EFI_ERROR (Status)) {
705     return FALSE;
706   }
707 
708   DataSize = sizeof (EFI_TREE_PHYSICAL_PRESENCE_FLAGS);
709   Status = gRT->GetVariable (
710                   TREE_PHYSICAL_PRESENCE_FLAGS_VARIABLE,
711                   &gEfiTrEEPhysicalPresenceGuid,
712                   NULL,
713                   &DataSize,
714                   &PpiFlags
715                   );
716   if (EFI_ERROR (Status)) {
717     return FALSE;
718   }
719 
720   if (TcgPpData.PPRequest == TREE_PHYSICAL_PRESENCE_NO_ACTION) {
721     //
722     // No operation request
723     //
724     return FALSE;
725   }
726 
727   if (!TrEEHaveValidTpmRequest(&TcgPpData, PpiFlags, &RequestConfirmed)) {
728     //
729     // Invalid operation request.
730     //
731     return FALSE;
732   }
733 
734   if (!RequestConfirmed) {
735     //
736     // Need UI to confirm
737     //
738     return TRUE;
739   }
740 
741   return FALSE;
742 }
743 
744