Replace unsafe string functions with new added safe string functions. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Zhang Lubo <lubo.zhang@intel.com> Reviewed-by: Fu Siyuan <siyuan.fu@intel.com> Reviewed-by: Qiu Shumin <shumin.qiu@intel.com> Reviewed-by: Jaben Carsey <jaben.carsey@intel.com> git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@17882 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			744 lines
		
	
	
		
			25 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			744 lines
		
	
	
		
			25 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
|   Execute pending TPM2 requests from OS or BIOS.
 | |
| 
 | |
|   Caution: This module requires additional review when modified.
 | |
|   This driver will have external input - variable.
 | |
|   This external input must be validated carefully to avoid security issue.
 | |
| 
 | |
|   TrEEExecutePendingTpmRequest() will receive untrusted input and do validation.
 | |
| 
 | |
| Copyright (c) 2013 - 2015, Intel Corporation. All rights reserved.<BR>
 | |
| This program and the accompanying materials 
 | |
| are licensed and made available under the terms and conditions of the BSD License 
 | |
| which accompanies this distribution.  The full text of the license may be found at 
 | |
| http://opensource.org/licenses/bsd-license.php
 | |
| 
 | |
| THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 
 | |
| WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 | |
| 
 | |
| **/
 | |
| 
 | |
| #include <PiDxe.h>
 | |
| 
 | |
| #include <Protocol/TrEEProtocol.h>
 | |
| #include <Protocol/VariableLock.h>
 | |
| #include <Library/DebugLib.h>
 | |
| #include <Library/BaseMemoryLib.h>
 | |
| #include <Library/UefiRuntimeServicesTableLib.h>
 | |
| #include <Library/UefiDriverEntryPoint.h>
 | |
| #include <Library/UefiBootServicesTableLib.h>
 | |
| #include <Library/UefiLib.h>
 | |
| #include <Library/MemoryAllocationLib.h>
 | |
| #include <Library/PrintLib.h>
 | |
| #include <Library/HiiLib.h>
 | |
| #include <Guid/EventGroup.h>
 | |
| #include <Guid/TrEEPhysicalPresenceData.h>
 | |
| #include <Library/Tpm2CommandLib.h>
 | |
| #include <Library/TrEEPpVendorLib.h>
 | |
| 
 | |
| #define CONFIRM_BUFFER_SIZE         4096
 | |
| 
 | |
| EFI_HII_HANDLE mTrEEPpStringPackHandle;
 | |
| 
 | |
| /**
 | |
|   Get string by string id from HII Interface.
 | |
| 
 | |
|   @param[in] Id          String ID.
 | |
| 
 | |
|   @retval    CHAR16 *    String from ID.
 | |
|   @retval    NULL        If error occurs.
 | |
| 
 | |
| **/
 | |
| CHAR16 *
 | |
| TrEEPhysicalPresenceGetStringById (
 | |
|   IN  EFI_STRING_ID   Id
 | |
|   )
 | |
| {
 | |
|   return HiiGetString (mTrEEPpStringPackHandle, Id, NULL);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Send ClearControl and Clear command to TPM.
 | |
| 
 | |
|   @param[in]  PlatformAuth      platform auth value. NULL means no platform auth change.
 | |
| 
 | |
|   @retval EFI_SUCCESS           Operation completed successfully.
 | |
|   @retval EFI_TIMEOUT           The register can't run into the expected status in time.
 | |
|   @retval EFI_BUFFER_TOO_SMALL  Response data buffer is too small.
 | |
|   @retval EFI_DEVICE_ERROR      Unexpected device behavior.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| TpmCommandClear (
 | |
|   IN TPM2B_AUTH                *PlatformAuth  OPTIONAL
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                Status;
 | |
|   TPMS_AUTH_COMMAND         *AuthSession;
 | |
|   TPMS_AUTH_COMMAND         LocalAuthSession;
 | |
| 
 | |
|   if (PlatformAuth == NULL) {
 | |
|     AuthSession = NULL;
 | |
|   } else {
 | |
|     AuthSession = &LocalAuthSession;
 | |
|     ZeroMem (&LocalAuthSession, sizeof(LocalAuthSession));
 | |
|     LocalAuthSession.sessionHandle = TPM_RS_PW;
 | |
|     LocalAuthSession.hmac.size = PlatformAuth->size;
 | |
|     CopyMem (LocalAuthSession.hmac.buffer, PlatformAuth->buffer, PlatformAuth->size);
 | |
|   }
 | |
| 
 | |
|   DEBUG ((EFI_D_INFO, "Tpm2ClearControl ... \n"));
 | |
|   Status = Tpm2ClearControl (TPM_RH_PLATFORM, AuthSession, NO);
 | |
|   DEBUG ((EFI_D_INFO, "Tpm2ClearControl - %r\n", Status));
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     goto Done;
 | |
|   }
 | |
|   DEBUG ((EFI_D_INFO, "Tpm2Clear ... \n"));
 | |
|   Status = Tpm2Clear (TPM_RH_PLATFORM, AuthSession);
 | |
|   DEBUG ((EFI_D_INFO, "Tpm2Clear - %r\n", Status));
 | |
| 
 | |
| Done:
 | |
|   ZeroMem (&LocalAuthSession.hmac, sizeof(LocalAuthSession.hmac));
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Execute physical presence operation requested by the OS.
 | |
| 
 | |
|   @param[in]      PlatformAuth        platform auth value. NULL means no platform auth change.
 | |
|   @param[in]      CommandCode         Physical presence operation value.
 | |
|   @param[in, out] PpiFlags            The physical presence interface flags.
 | |
|   
 | |
|   @retval TREE_PP_OPERATION_RESPONSE_BIOS_FAILURE  Unknown physical presence operation.
 | |
|   @retval TREE_PP_OPERATION_RESPONSE_BIOS_FAILURE  Error occurred during sending command to TPM or 
 | |
|                                                    receiving response from TPM.
 | |
|   @retval Others                                   Return code from the TPM device after command execution.
 | |
| **/
 | |
| UINT32
 | |
| TrEEExecutePhysicalPresence (
 | |
|   IN      TPM2B_AUTH                       *PlatformAuth,  OPTIONAL
 | |
|   IN      UINT32                           CommandCode,
 | |
|   IN OUT  EFI_TREE_PHYSICAL_PRESENCE_FLAGS *PpiFlags
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
| 
 | |
|   switch (CommandCode) {
 | |
|     case TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR:
 | |
|     case TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR_2:
 | |
|     case TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR_3:
 | |
|     case TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR_4:
 | |
|       Status = TpmCommandClear (PlatformAuth);
 | |
|       if (EFI_ERROR (Status)) {
 | |
|         return TREE_PP_OPERATION_RESPONSE_BIOS_FAILURE;
 | |
|       } else {
 | |
|         return TREE_PP_OPERATION_RESPONSE_SUCCESS;
 | |
|       }
 | |
| 
 | |
|     case TREE_PHYSICAL_PRESENCE_SET_NO_PPI_CLEAR_FALSE:
 | |
|       PpiFlags->PPFlags &= ~TREE_BIOS_TPM_MANAGEMENT_FLAG_NO_PPI_CLEAR;
 | |
|       return TREE_PP_OPERATION_RESPONSE_SUCCESS;
 | |
| 
 | |
|     case TREE_PHYSICAL_PRESENCE_SET_NO_PPI_CLEAR_TRUE:
 | |
|       PpiFlags->PPFlags |= TREE_BIOS_TPM_MANAGEMENT_FLAG_NO_PPI_CLEAR;
 | |
|       return TREE_PP_OPERATION_RESPONSE_SUCCESS;
 | |
| 
 | |
|     default:
 | |
|       if (CommandCode <= TREE_PHYSICAL_PRESENCE_NO_ACTION_MAX) {
 | |
|         return TREE_PP_OPERATION_RESPONSE_SUCCESS;
 | |
|       } else {
 | |
|         return TREE_PP_OPERATION_RESPONSE_BIOS_FAILURE;
 | |
|       }
 | |
|   }
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Read the specified key for user confirmation.
 | |
| 
 | |
|   @param[in]  CautionKey  If true,  F12 is used as confirm key;
 | |
|                           If false, F10 is used as confirm key.
 | |
| 
 | |
|   @retval     TRUE        User confirmed the changes by input.
 | |
|   @retval     FALSE       User discarded the changes.
 | |
| **/
 | |
| BOOLEAN
 | |
| TrEEReadUserKey (
 | |
|   IN     BOOLEAN                    CautionKey
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                        Status;
 | |
|   EFI_INPUT_KEY                     Key;
 | |
|   UINT16                            InputKey;
 | |
|       
 | |
|   InputKey = 0; 
 | |
|   do {
 | |
|     Status = gBS->CheckEvent (gST->ConIn->WaitForKey);
 | |
|     if (!EFI_ERROR (Status)) {
 | |
|       Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
 | |
|       if (Key.ScanCode == SCAN_ESC) {
 | |
|         InputKey = Key.ScanCode;
 | |
|       }
 | |
|       if ((Key.ScanCode == SCAN_F10) && !CautionKey) {
 | |
|         InputKey = Key.ScanCode;
 | |
|       }
 | |
|       if ((Key.ScanCode == SCAN_F12) && CautionKey) {
 | |
|         InputKey = Key.ScanCode;
 | |
|       }
 | |
|     }      
 | |
|   } while (InputKey == 0);
 | |
| 
 | |
|   if (InputKey != SCAN_ESC) {
 | |
|     return TRUE;
 | |
|   }
 | |
|   
 | |
|   return FALSE;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   The constructor function register UNI strings into imageHandle.
 | |
|   
 | |
|   It will ASSERT() if that operation fails and it will always return EFI_SUCCESS. 
 | |
| 
 | |
|   @param  ImageHandle   The firmware allocated handle for the EFI image.
 | |
|   @param  SystemTable   A pointer to the EFI System Table.
 | |
|   
 | |
|   @retval EFI_SUCCESS   The constructor successfully added string package.
 | |
|   @retval Other value   The constructor can't add string package.
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| TrEEPhysicalPresenceLibConstructor (
 | |
|   IN EFI_HANDLE        ImageHandle,
 | |
|   IN EFI_SYSTEM_TABLE  *SystemTable
 | |
|   )
 | |
| {
 | |
|   mTrEEPpStringPackHandle = HiiAddPackages (&gEfiTrEEPhysicalPresenceGuid, ImageHandle, DxeTrEEPhysicalPresenceLibStrings, NULL);
 | |
|   ASSERT (mTrEEPpStringPackHandle != NULL);
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Display the confirm text and get user confirmation.
 | |
| 
 | |
|   @param[in] TpmPpCommand  The requested TPM physical presence command.
 | |
| 
 | |
|   @retval    TRUE          The user has confirmed the changes.
 | |
|   @retval    FALSE         The user doesn't confirm the changes.
 | |
| **/
 | |
| BOOLEAN
 | |
| TrEEUserConfirm (
 | |
|   IN      UINT32                    TpmPpCommand
 | |
|   )
 | |
| {
 | |
|   CHAR16                            *ConfirmText;
 | |
|   CHAR16                            *TmpStr1;
 | |
|   CHAR16                            *TmpStr2; 
 | |
|   UINTN                             BufSize;
 | |
|   BOOLEAN                           CautionKey;
 | |
|   UINT16                            Index;
 | |
|   CHAR16                            DstStr[81];
 | |
|     
 | |
|   TmpStr2     = NULL;
 | |
|   CautionKey  = FALSE;
 | |
|   BufSize     = CONFIRM_BUFFER_SIZE;
 | |
|   ConfirmText = AllocateZeroPool (BufSize);
 | |
|   ASSERT (ConfirmText != NULL);
 | |
| 
 | |
|   switch (TpmPpCommand) {
 | |
| 
 | |
|     case TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR:
 | |
|     case TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR_2:
 | |
|     case TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR_3:
 | |
|     case TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR_4:
 | |
|       CautionKey = TRUE;
 | |
|       TmpStr2 = TrEEPhysicalPresenceGetStringById (STRING_TOKEN (TPM_CLEAR));
 | |
| 
 | |
|       TmpStr1 = TrEEPhysicalPresenceGetStringById (STRING_TOKEN (TPM_HEAD_STR));
 | |
|       UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2);
 | |
|       FreePool (TmpStr1);
 | |
| 
 | |
|       TmpStr1 = TrEEPhysicalPresenceGetStringById (STRING_TOKEN (TPM_WARNING_CLEAR));
 | |
|       StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
 | |
|       StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), L" \n\n", (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
 | |
|       FreePool (TmpStr1);      
 | |
| 
 | |
|       TmpStr1 = TrEEPhysicalPresenceGetStringById (STRING_TOKEN (TPM_CAUTION_KEY));
 | |
|       StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
 | |
|       FreePool (TmpStr1);
 | |
|       break;
 | |
| 
 | |
|     case TREE_PHYSICAL_PRESENCE_SET_NO_PPI_CLEAR_TRUE:
 | |
|       CautionKey = TRUE;
 | |
|       TmpStr2 = TrEEPhysicalPresenceGetStringById (STRING_TOKEN (TPM_CLEAR));
 | |
| 
 | |
|       TmpStr1 = TrEEPhysicalPresenceGetStringById (STRING_TOKEN (TPM_PPI_HEAD_STR));
 | |
|       UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2);
 | |
|       FreePool (TmpStr1);
 | |
| 
 | |
|       TmpStr1 = TrEEPhysicalPresenceGetStringById (STRING_TOKEN (TPM_NOTE_CLEAR));
 | |
|       StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
 | |
|       FreePool (TmpStr1);
 | |
| 
 | |
|       TmpStr1 = TrEEPhysicalPresenceGetStringById (STRING_TOKEN (TPM_WARNING_CLEAR));
 | |
|       StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
 | |
|       StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), L" \n\n", (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
 | |
|       FreePool (TmpStr1); 
 | |
| 
 | |
|       TmpStr1 = TrEEPhysicalPresenceGetStringById (STRING_TOKEN (TPM_CAUTION_KEY));
 | |
|       StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
 | |
|       FreePool (TmpStr1);
 | |
| 
 | |
|       TmpStr1 = TrEEPhysicalPresenceGetStringById (STRING_TOKEN (TPM_NO_PPI_INFO));
 | |
|       StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
 | |
|       FreePool (TmpStr1);
 | |
|       break;
 | |
| 
 | |
|     default:
 | |
|       ;
 | |
|   }
 | |
| 
 | |
|   if (TmpStr2 == NULL) {
 | |
|     FreePool (ConfirmText);
 | |
|     return FALSE;
 | |
|   }
 | |
| 
 | |
|   TmpStr1 = TrEEPhysicalPresenceGetStringById (STRING_TOKEN (TPM_REJECT_KEY));
 | |
|   BufSize -= StrSize (ConfirmText);
 | |
|   UnicodeSPrint (ConfirmText + StrLen (ConfirmText), BufSize, TmpStr1, TmpStr2);
 | |
| 
 | |
|   DstStr[80] = L'\0';
 | |
|   for (Index = 0; Index < StrLen (ConfirmText); Index += 80) {
 | |
|     StrnCpyS(DstStr, sizeof (DstStr) / sizeof (CHAR16), ConfirmText + Index, sizeof (DstStr) / sizeof (CHAR16) - 1);    
 | |
|     Print (DstStr);    
 | |
|   }
 | |
|   
 | |
|   FreePool (TmpStr1);
 | |
|   FreePool (TmpStr2);
 | |
|   FreePool (ConfirmText);
 | |
| 
 | |
|   if (TrEEReadUserKey (CautionKey)) {
 | |
|     return TRUE;
 | |
|   }
 | |
| 
 | |
|   return FALSE;  
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Check if there is a valid physical presence command request. Also updates parameter value 
 | |
|   to whether the requested physical presence command already confirmed by user
 | |
|  
 | |
|    @param[in]  TcgPpData                 EFI TrEE Physical Presence request data. 
 | |
|    @param[in]  Flags                     The physical presence interface flags.
 | |
|    @param[out] RequestConfirmed            If the physical presence operation command required user confirm from UI.
 | |
|                                              True, it indicates the command doesn't require user confirm, or already confirmed 
 | |
|                                                    in last boot cycle by user.
 | |
|                                              False, it indicates the command need user confirm from UI.
 | |
| 
 | |
|    @retval  TRUE        Physical Presence operation command is valid.
 | |
|    @retval  FALSE       Physical Presence operation command is invalid.
 | |
| 
 | |
| **/
 | |
| BOOLEAN
 | |
| TrEEHaveValidTpmRequest  (
 | |
|   IN      EFI_TREE_PHYSICAL_PRESENCE       *TcgPpData,
 | |
|   IN      EFI_TREE_PHYSICAL_PRESENCE_FLAGS Flags,
 | |
|   OUT     BOOLEAN                          *RequestConfirmed
 | |
|   )
 | |
| {
 | |
|   BOOLEAN  IsRequestValid;
 | |
| 
 | |
|   *RequestConfirmed = FALSE;
 | |
| 
 | |
|   switch (TcgPpData->PPRequest) {
 | |
|     case TREE_PHYSICAL_PRESENCE_NO_ACTION:
 | |
|       *RequestConfirmed = TRUE;
 | |
|       return TRUE;
 | |
|     case TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR:
 | |
|     case TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR_2:
 | |
|     case TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR_3:
 | |
|     case TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR_4:
 | |
|       if ((Flags.PPFlags & TREE_BIOS_TPM_MANAGEMENT_FLAG_NO_PPI_CLEAR) != 0) {
 | |
|         *RequestConfirmed = TRUE;
 | |
|       }
 | |
|       break;
 | |
| 
 | |
|     case TREE_PHYSICAL_PRESENCE_SET_NO_PPI_CLEAR_FALSE:
 | |
|       *RequestConfirmed = TRUE;
 | |
|       break;
 | |
| 
 | |
|     case TREE_PHYSICAL_PRESENCE_SET_NO_PPI_CLEAR_TRUE:
 | |
|       break;
 | |
| 
 | |
|     default:
 | |
|       if (TcgPpData->PPRequest >= TREE_PHYSICAL_PRESENCE_VENDOR_SPECIFIC_OPERATION) {
 | |
|         IsRequestValid = TrEEPpVendorLibHasValidRequest (TcgPpData->PPRequest, Flags.PPFlags, RequestConfirmed);
 | |
|         if (!IsRequestValid) {
 | |
|           return FALSE;
 | |
|         } else {
 | |
|           break;
 | |
|         }
 | |
|       } else {
 | |
|         //
 | |
|         // Wrong Physical Presence command
 | |
|         //
 | |
|         return FALSE;
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   if ((Flags.PPFlags & TREE_VENDOR_LIB_FLAG_RESET_TRACK) != 0) {
 | |
|     //
 | |
|     // It had been confirmed in last boot, it doesn't need confirm again.
 | |
|     //
 | |
|     *RequestConfirmed = TRUE;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Physical Presence command is correct
 | |
|   //
 | |
|   return TRUE;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Check and execute the requested physical presence command.
 | |
| 
 | |
|   Caution: This function may receive untrusted input.
 | |
|   TcgPpData variable is external input, so this function will validate
 | |
|   its data structure to be valid value.
 | |
| 
 | |
|   @param[in] PlatformAuth         platform auth value. NULL means no platform auth change.
 | |
|   @param[in] TcgPpData            Point to the physical presence NV variable.
 | |
|   @param[in] Flags                The physical presence interface flags.
 | |
| **/
 | |
| VOID
 | |
| TrEEExecutePendingTpmRequest (
 | |
|   IN      TPM2B_AUTH                       *PlatformAuth,  OPTIONAL
 | |
|   IN      EFI_TREE_PHYSICAL_PRESENCE       *TcgPpData,
 | |
|   IN      EFI_TREE_PHYSICAL_PRESENCE_FLAGS Flags
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                        Status;
 | |
|   UINTN                             DataSize;
 | |
|   BOOLEAN                           RequestConfirmed;
 | |
|   EFI_TREE_PHYSICAL_PRESENCE_FLAGS  NewFlags;
 | |
|   BOOLEAN                           ResetRequired;
 | |
|   UINT32                            NewPPFlags;
 | |
| 
 | |
|   if (TcgPpData->PPRequest == TREE_PHYSICAL_PRESENCE_NO_ACTION) {
 | |
|     //
 | |
|     // No operation request
 | |
|     //
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   if (!TrEEHaveValidTpmRequest(TcgPpData, Flags, &RequestConfirmed)) {
 | |
|     //
 | |
|     // Invalid operation request.
 | |
|     //
 | |
|     if (TcgPpData->PPRequest <= TREE_PHYSICAL_PRESENCE_NO_ACTION_MAX) {
 | |
|       TcgPpData->PPResponse = TREE_PP_OPERATION_RESPONSE_SUCCESS;
 | |
|     } else {
 | |
|       TcgPpData->PPResponse = TREE_PP_OPERATION_RESPONSE_BIOS_FAILURE;
 | |
|     }
 | |
|     TcgPpData->LastPPRequest = TcgPpData->PPRequest;
 | |
|     TcgPpData->PPRequest = TREE_PHYSICAL_PRESENCE_NO_ACTION;
 | |
|     DataSize = sizeof (EFI_TREE_PHYSICAL_PRESENCE);
 | |
|     Status = gRT->SetVariable (
 | |
|                     TREE_PHYSICAL_PRESENCE_VARIABLE,
 | |
|                     &gEfiTrEEPhysicalPresenceGuid,
 | |
|                     EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
 | |
|                     DataSize,
 | |
|                     TcgPpData
 | |
|                     );
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   ResetRequired = FALSE;
 | |
|   if (TcgPpData->PPRequest >= TREE_PHYSICAL_PRESENCE_VENDOR_SPECIFIC_OPERATION) {
 | |
|     NewFlags = Flags;
 | |
|     NewPPFlags = NewFlags.PPFlags;
 | |
|     TcgPpData->PPResponse = TrEEPpVendorLibExecutePendingRequest (PlatformAuth, TcgPpData->PPRequest, &NewPPFlags, &ResetRequired);
 | |
|     NewFlags.PPFlags = (UINT8)NewPPFlags;
 | |
|   } else {
 | |
|     if (!RequestConfirmed) {
 | |
|       //
 | |
|       // Print confirm text and wait for approval. 
 | |
|       //
 | |
|       RequestConfirmed = TrEEUserConfirm (TcgPpData->PPRequest
 | |
|                                           );
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Execute requested physical presence command
 | |
|     //
 | |
|     TcgPpData->PPResponse = TREE_PP_OPERATION_RESPONSE_USER_ABORT;
 | |
|     NewFlags = Flags;
 | |
|     if (RequestConfirmed) {
 | |
|       TcgPpData->PPResponse = TrEEExecutePhysicalPresence (PlatformAuth, TcgPpData->PPRequest, 
 | |
|                                                            &NewFlags);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Save the flags if it is updated.
 | |
|   //
 | |
|   if (CompareMem (&Flags, &NewFlags, sizeof(EFI_TREE_PHYSICAL_PRESENCE_FLAGS)) != 0) {
 | |
|     Status   = gRT->SetVariable (
 | |
|                       TREE_PHYSICAL_PRESENCE_FLAGS_VARIABLE,
 | |
|                       &gEfiTrEEPhysicalPresenceGuid,
 | |
|                       EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
 | |
|                       sizeof (EFI_TREE_PHYSICAL_PRESENCE_FLAGS),
 | |
|                       &NewFlags
 | |
|                       ); 
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Clear request
 | |
|   //
 | |
|   if ((NewFlags.PPFlags & TREE_VENDOR_LIB_FLAG_RESET_TRACK) == 0) {
 | |
|     TcgPpData->LastPPRequest = TcgPpData->PPRequest;
 | |
|     TcgPpData->PPRequest = TREE_PHYSICAL_PRESENCE_NO_ACTION;    
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Save changes
 | |
|   //
 | |
|   DataSize = sizeof (EFI_TREE_PHYSICAL_PRESENCE);
 | |
|   Status = gRT->SetVariable (
 | |
|                   TREE_PHYSICAL_PRESENCE_VARIABLE,
 | |
|                   &gEfiTrEEPhysicalPresenceGuid,
 | |
|                   EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
 | |
|                   DataSize,
 | |
|                   TcgPpData
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   if (TcgPpData->PPResponse == TREE_PP_OPERATION_RESPONSE_USER_ABORT) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Reset system to make new TPM settings in effect
 | |
|   //
 | |
|   switch (TcgPpData->LastPPRequest) {
 | |
|     case TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR:
 | |
|     case TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR_2:
 | |
|     case TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR_3:
 | |
|     case TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR_4:
 | |
|       break;
 | |
|     default:
 | |
|       if (TcgPpData->LastPPRequest >= TREE_PHYSICAL_PRESENCE_VENDOR_SPECIFIC_OPERATION) {
 | |
|         if (ResetRequired) {
 | |
|           break;
 | |
|         } else {
 | |
|           return ;
 | |
|         }
 | |
|       }
 | |
|       if (TcgPpData->PPRequest != TREE_PHYSICAL_PRESENCE_NO_ACTION) {
 | |
|         break;
 | |
|       }
 | |
|       return;
 | |
|   }
 | |
| 
 | |
|   Print (L"Rebooting system to make TPM2 settings in effect\n");
 | |
|   gRT->ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL);
 | |
|   ASSERT (FALSE);  
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Check and execute the pending TPM request.
 | |
| 
 | |
|   The TPM request may come from OS or BIOS. This API will display request information and wait 
 | |
|   for user confirmation if TPM request exists. The TPM request will be sent to TPM device after
 | |
|   the TPM request is confirmed, and one or more reset may be required to make TPM request to 
 | |
|   take effect.
 | |
|   
 | |
|   This API should be invoked after console in and console out are all ready as they are required
 | |
|   to display request information and get user input to confirm the request.  
 | |
| 
 | |
|   @param[in]  PlatformAuth                   platform auth value. NULL means no platform auth change.
 | |
| **/
 | |
| VOID
 | |
| EFIAPI
 | |
| TrEEPhysicalPresenceLibProcessRequest (
 | |
|   IN      TPM2B_AUTH                     *PlatformAuth  OPTIONAL
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                        Status;
 | |
|   UINTN                             DataSize;
 | |
|   EFI_TREE_PHYSICAL_PRESENCE        TcgPpData;
 | |
|   EFI_TREE_PROTOCOL                 *TreeProtocol;
 | |
|   EDKII_VARIABLE_LOCK_PROTOCOL      *VariableLockProtocol;
 | |
|   EFI_TREE_PHYSICAL_PRESENCE_FLAGS  PpiFlags;
 | |
| 
 | |
|   Status = gBS->LocateProtocol (&gEfiTrEEProtocolGuid, NULL, (VOID **) &TreeProtocol);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return ;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Initialize physical presence flags.
 | |
|   //
 | |
|   DataSize = sizeof (EFI_TREE_PHYSICAL_PRESENCE_FLAGS);
 | |
|   Status = gRT->GetVariable (
 | |
|                   TREE_PHYSICAL_PRESENCE_FLAGS_VARIABLE,
 | |
|                   &gEfiTrEEPhysicalPresenceGuid,
 | |
|                   NULL,
 | |
|                   &DataSize,
 | |
|                   &PpiFlags
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     PpiFlags.PPFlags = 0;
 | |
|     Status   = gRT->SetVariable (
 | |
|                       TREE_PHYSICAL_PRESENCE_FLAGS_VARIABLE,
 | |
|                       &gEfiTrEEPhysicalPresenceGuid,
 | |
|                       EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
 | |
|                       sizeof (EFI_TREE_PHYSICAL_PRESENCE_FLAGS),
 | |
|                       &PpiFlags
 | |
|                       );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       DEBUG ((EFI_D_ERROR, "[TPM2] Set physical presence flag failed, Status = %r\n", Status));
 | |
|       return ;
 | |
|     }
 | |
|   }
 | |
|   DEBUG ((EFI_D_INFO, "[TPM2] PpiFlags = %x\n", PpiFlags.PPFlags));
 | |
| 
 | |
|   //
 | |
|   // This flags variable controls whether physical presence is required for TPM command. 
 | |
|   // It should be protected from malicious software. We set it as read-only variable here.
 | |
|   //
 | |
|   Status = gBS->LocateProtocol (&gEdkiiVariableLockProtocolGuid, NULL, (VOID **)&VariableLockProtocol);
 | |
|   if (!EFI_ERROR (Status)) {
 | |
|     Status = VariableLockProtocol->RequestToLock (
 | |
|                                      VariableLockProtocol,
 | |
|                                      TREE_PHYSICAL_PRESENCE_FLAGS_VARIABLE,
 | |
|                                      &gEfiTrEEPhysicalPresenceGuid
 | |
|                                      );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       DEBUG ((EFI_D_ERROR, "[TPM2] Error when lock variable %s, Status = %r\n", TREE_PHYSICAL_PRESENCE_FLAGS_VARIABLE, Status));
 | |
|       ASSERT_EFI_ERROR (Status);
 | |
|     }
 | |
|   }
 | |
|   
 | |
|   //
 | |
|   // Initialize physical presence variable.
 | |
|   //
 | |
|   DataSize = sizeof (EFI_TREE_PHYSICAL_PRESENCE);
 | |
|   Status = gRT->GetVariable (
 | |
|                   TREE_PHYSICAL_PRESENCE_VARIABLE,
 | |
|                   &gEfiTrEEPhysicalPresenceGuid,
 | |
|                   NULL,
 | |
|                   &DataSize,
 | |
|                   &TcgPpData
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     ZeroMem ((VOID*)&TcgPpData, sizeof (TcgPpData));
 | |
|     DataSize = sizeof (EFI_TREE_PHYSICAL_PRESENCE);
 | |
|     Status   = gRT->SetVariable (
 | |
|                       TREE_PHYSICAL_PRESENCE_VARIABLE,
 | |
|                       &gEfiTrEEPhysicalPresenceGuid,
 | |
|                       EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
 | |
|                       DataSize,
 | |
|                       &TcgPpData
 | |
|                       );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       DEBUG ((EFI_D_ERROR, "[TPM2] Set physical presence variable failed, Status = %r\n", Status));
 | |
|       return ;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   DEBUG ((EFI_D_INFO, "[TPM2] Flags=%x, PPRequest=%x (LastPPRequest=%x)\n", PpiFlags.PPFlags, TcgPpData.PPRequest, TcgPpData.LastPPRequest));
 | |
| 
 | |
|   //
 | |
|   // Execute pending TPM request.
 | |
|   //  
 | |
|   TrEEExecutePendingTpmRequest (PlatformAuth, &TcgPpData, PpiFlags);
 | |
|   DEBUG ((EFI_D_INFO, "[TPM2] PPResponse = %x (LastPPRequest=%x, Flags=%x)\n", TcgPpData.PPResponse, TcgPpData.LastPPRequest, PpiFlags.PPFlags));
 | |
| 
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Check if the pending TPM request needs user input to confirm.
 | |
| 
 | |
|   The TPM request may come from OS. This API will check if TPM request exists and need user
 | |
|   input to confirmation.
 | |
|   
 | |
|   @retval    TRUE        TPM needs input to confirm user physical presence.
 | |
|   @retval    FALSE       TPM doesn't need input to confirm user physical presence.
 | |
| 
 | |
| **/
 | |
| BOOLEAN
 | |
| EFIAPI
 | |
| TrEEPhysicalPresenceLibNeedUserConfirm(
 | |
|   VOID
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                        Status;
 | |
|   EFI_TREE_PHYSICAL_PRESENCE        TcgPpData;
 | |
|   UINTN                             DataSize;
 | |
|   BOOLEAN                           RequestConfirmed;
 | |
|   EFI_TREE_PROTOCOL                 *TreeProtocol;
 | |
|   EFI_TREE_PHYSICAL_PRESENCE_FLAGS  PpiFlags;
 | |
| 
 | |
|   Status = gBS->LocateProtocol (&gEfiTrEEProtocolGuid, NULL, (VOID **) &TreeProtocol);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return FALSE;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Check Tpm requests
 | |
|   //
 | |
|   DataSize = sizeof (EFI_TREE_PHYSICAL_PRESENCE);
 | |
|   Status = gRT->GetVariable (
 | |
|                   TREE_PHYSICAL_PRESENCE_VARIABLE,
 | |
|                   &gEfiTrEEPhysicalPresenceGuid,
 | |
|                   NULL,
 | |
|                   &DataSize,
 | |
|                   &TcgPpData
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return FALSE;
 | |
|   }
 | |
| 
 | |
|   DataSize = sizeof (EFI_TREE_PHYSICAL_PRESENCE_FLAGS);
 | |
|   Status = gRT->GetVariable (
 | |
|                   TREE_PHYSICAL_PRESENCE_FLAGS_VARIABLE,
 | |
|                   &gEfiTrEEPhysicalPresenceGuid,
 | |
|                   NULL,
 | |
|                   &DataSize,
 | |
|                   &PpiFlags
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return FALSE;
 | |
|   }
 | |
|   
 | |
|   if (TcgPpData.PPRequest == TREE_PHYSICAL_PRESENCE_NO_ACTION) {
 | |
|     //
 | |
|     // No operation request
 | |
|     //
 | |
|     return FALSE;
 | |
|   }
 | |
| 
 | |
|   if (!TrEEHaveValidTpmRequest(&TcgPpData, PpiFlags, &RequestConfirmed)) {
 | |
|     //
 | |
|     // Invalid operation request.
 | |
|     //
 | |
|     return FALSE;
 | |
|   }
 | |
| 
 | |
|   if (!RequestConfirmed) {
 | |
|     //
 | |
|     // Need UI to confirm
 | |
|     //
 | |
|     return TRUE;
 | |
|   }
 | |
| 
 | |
|   return FALSE;
 | |
| }
 | |
| 
 |