/** @file Handle TPM 2.0 physical presence requests from OS. This library will handle TPM 2.0 physical presence request from OS. 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. Tcg2PhysicalPresenceLibSubmitRequestToPreOSFunction() and Tcg2PhysicalPresenceLibGetUserConfirmationStatusFunction() will receive untrusted input and do validation. Copyright (c) 2015 - 2020, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include #include #include #include #include #include #include #include #define PP_INF_VERSION_1_2 "1.2" EFI_SMM_VARIABLE_PROTOCOL *mTcg2PpSmmVariable; BOOLEAN mIsTcg2PPVerLowerThan_1_3 = FALSE; UINT32 mTcg2PhysicalPresenceFlags; /** The handler for TPM physical presence function: Return TPM Operation Response to OS Environment. This API should be invoked in OS runtime phase to interface with ACPI method. @param[out] MostRecentRequest Most recent operation request. @param[out] Response Response to the most recent operation request. @return Return Code for Return TPM Operation Response to OS Environment. **/ UINT32 EFIAPI Tcg2PhysicalPresenceLibReturnOperationResponseToOsFunction ( OUT UINT32 *MostRecentRequest, OUT UINT32 *Response ) { EFI_STATUS Status; UINTN DataSize; EFI_TCG2_PHYSICAL_PRESENCE PpData; DEBUG ((EFI_D_INFO, "[TPM2] ReturnOperationResponseToOsFunction\n")); // // Get the Physical Presence variable // DataSize = sizeof (EFI_TCG2_PHYSICAL_PRESENCE); Status = mTcg2PpSmmVariable->SmmGetVariable ( TCG2_PHYSICAL_PRESENCE_VARIABLE, &gEfiTcg2PhysicalPresenceGuid, NULL, &DataSize, &PpData ); if (EFI_ERROR (Status)) { *MostRecentRequest = 0; *Response = 0; DEBUG ((EFI_D_ERROR, "[TPM2] Get PP variable failure! Status = %r\n", Status)); return TCG_PP_RETURN_TPM_OPERATION_RESPONSE_FAILURE; } *MostRecentRequest = PpData.LastPPRequest; *Response = PpData.PPResponse; return TCG_PP_RETURN_TPM_OPERATION_RESPONSE_SUCCESS; } /** The handler for TPM physical presence function: Submit TPM Operation Request to Pre-OS Environment and Submit TPM Operation Request to Pre-OS Environment 2. This API should be invoked in OS runtime phase to interface with ACPI method. Caution: This function may receive untrusted input. @param[in, out] Pointer to OperationRequest TPM physical presence operation request. @param[in, out] Pointer to RequestParameter TPM physical presence operation request parameter. @return Return Code for Submit TPM Operation Request to Pre-OS Environment and Submit TPM Operation Request to Pre-OS Environment 2. **/ UINT32 Tcg2PhysicalPresenceLibSubmitRequestToPreOSFunctionEx ( IN OUT UINT32 *OperationRequest, IN OUT UINT32 *RequestParameter ) { EFI_STATUS Status; UINT32 ReturnCode; UINTN DataSize; EFI_TCG2_PHYSICAL_PRESENCE PpData; EFI_TCG2_PHYSICAL_PRESENCE_FLAGS Flags; DEBUG ((EFI_D_INFO, "[TPM2] SubmitRequestToPreOSFunction, Request = %x, %x\n", *OperationRequest, *RequestParameter)); ReturnCode = TCG_PP_SUBMIT_REQUEST_TO_PREOS_SUCCESS; // // Get the Physical Presence variable // DataSize = sizeof (EFI_TCG2_PHYSICAL_PRESENCE); Status = mTcg2PpSmmVariable->SmmGetVariable ( TCG2_PHYSICAL_PRESENCE_VARIABLE, &gEfiTcg2PhysicalPresenceGuid, NULL, &DataSize, &PpData ); if (EFI_ERROR (Status)) { DEBUG ((EFI_D_ERROR, "[TPM2] Get PP variable failure! Status = %r\n", Status)); ReturnCode = TCG_PP_SUBMIT_REQUEST_TO_PREOS_GENERAL_FAILURE; goto EXIT; } if ((*OperationRequest > TCG2_PHYSICAL_PRESENCE_NO_ACTION_MAX) && (*OperationRequest < TCG2_PHYSICAL_PRESENCE_STORAGE_MANAGEMENT_BEGIN) ) { ReturnCode = TCG_PP_SUBMIT_REQUEST_TO_PREOS_NOT_IMPLEMENTED; goto EXIT; } if ((PpData.PPRequest != *OperationRequest) || (PpData.PPRequestParameter != *RequestParameter)) { PpData.PPRequest = (UINT8)*OperationRequest; PpData.PPRequestParameter = *RequestParameter; DataSize = sizeof (EFI_TCG2_PHYSICAL_PRESENCE); Status = mTcg2PpSmmVariable->SmmSetVariable ( TCG2_PHYSICAL_PRESENCE_VARIABLE, &gEfiTcg2PhysicalPresenceGuid, EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, DataSize, &PpData ); if (EFI_ERROR (Status)) { DEBUG ((EFI_D_ERROR, "[TPM2] Set PP variable failure! Status = %r\n", Status)); ReturnCode = TCG_PP_SUBMIT_REQUEST_TO_PREOS_GENERAL_FAILURE; goto EXIT; } } if (*OperationRequest >= TCG2_PHYSICAL_PRESENCE_VENDOR_SPECIFIC_OPERATION) { DataSize = sizeof (EFI_TCG2_PHYSICAL_PRESENCE_FLAGS); Status = mTcg2PpSmmVariable->SmmGetVariable ( TCG2_PHYSICAL_PRESENCE_FLAGS_VARIABLE, &gEfiTcg2PhysicalPresenceGuid, NULL, &DataSize, &Flags ); if (EFI_ERROR (Status)) { Flags.PPFlags = mTcg2PhysicalPresenceFlags; } ReturnCode = Tcg2PpVendorLibSubmitRequestToPreOSFunction (*OperationRequest, Flags.PPFlags, *RequestParameter); } EXIT: // // Sync PPRQ/PPRM from PP Variable if PP submission fails // if (ReturnCode != TCG_PP_SUBMIT_REQUEST_TO_PREOS_SUCCESS) { DEBUG ((EFI_D_ERROR, "[TPM2] Submit PP Request failure! Sync PPRQ/PPRM with PP variable.\n", Status)); DataSize = sizeof (EFI_TCG2_PHYSICAL_PRESENCE); ZeroMem(&PpData, DataSize); Status = mTcg2PpSmmVariable->SmmGetVariable ( TCG2_PHYSICAL_PRESENCE_VARIABLE, &gEfiTcg2PhysicalPresenceGuid, NULL, &DataSize, &PpData ); *OperationRequest = (UINT32)PpData.PPRequest; *RequestParameter = PpData.PPRequestParameter; } return ReturnCode; } /** The handler for TPM physical presence function: Submit TPM Operation Request to Pre-OS Environment and Submit TPM Operation Request to Pre-OS Environment 2. This API should be invoked in OS runtime phase to interface with ACPI method. Caution: This function may receive untrusted input. @param[in] OperationRequest TPM physical presence operation request. @param[in] RequestParameter TPM physical presence operation request parameter. @return Return Code for Submit TPM Operation Request to Pre-OS Environment and Submit TPM Operation Request to Pre-OS Environment 2. **/ UINT32 EFIAPI Tcg2PhysicalPresenceLibSubmitRequestToPreOSFunction ( IN UINT32 OperationRequest, IN UINT32 RequestParameter ) { UINT32 TempOperationRequest; UINT32 TempRequestParameter; TempOperationRequest = OperationRequest; TempRequestParameter = RequestParameter; return Tcg2PhysicalPresenceLibSubmitRequestToPreOSFunctionEx(&TempOperationRequest, &TempRequestParameter); } /** The handler for TPM physical presence function: Get User Confirmation Status for Operation. This API should be invoked in OS runtime phase to interface with ACPI method. Caution: This function may receive untrusted input. @param[in] OperationRequest TPM physical presence operation request. @return Return Code for Get User Confirmation Status for Operation. **/ UINT32 EFIAPI Tcg2PhysicalPresenceLibGetUserConfirmationStatusFunction ( IN UINT32 OperationRequest ) { EFI_STATUS Status; UINTN DataSize; EFI_TCG2_PHYSICAL_PRESENCE PpData; EFI_TCG2_PHYSICAL_PRESENCE_FLAGS Flags; BOOLEAN RequestConfirmed; DEBUG ((EFI_D_INFO, "[TPM2] GetUserConfirmationStatusFunction, Request = %x\n", OperationRequest)); // // Get the Physical Presence variable // DataSize = sizeof (EFI_TCG2_PHYSICAL_PRESENCE); Status = mTcg2PpSmmVariable->SmmGetVariable ( TCG2_PHYSICAL_PRESENCE_VARIABLE, &gEfiTcg2PhysicalPresenceGuid, NULL, &DataSize, &PpData ); if (EFI_ERROR (Status)) { DEBUG ((EFI_D_ERROR, "[TPM2] Get PP variable failure! Status = %r\n", Status)); return TCG_PP_GET_USER_CONFIRMATION_BLOCKED_BY_BIOS_CONFIGURATION; } // // Get the Physical Presence flags // DataSize = sizeof (EFI_TCG2_PHYSICAL_PRESENCE_FLAGS); Status = mTcg2PpSmmVariable->SmmGetVariable ( TCG2_PHYSICAL_PRESENCE_FLAGS_VARIABLE, &gEfiTcg2PhysicalPresenceGuid, NULL, &DataSize, &Flags ); if (EFI_ERROR (Status)) { DEBUG ((EFI_D_ERROR, "[TPM2] Get PP flags failure! Status = %r\n", Status)); return TCG_PP_GET_USER_CONFIRMATION_BLOCKED_BY_BIOS_CONFIGURATION; } RequestConfirmed = FALSE; switch (OperationRequest) { case TCG2_PHYSICAL_PRESENCE_CLEAR: case TCG2_PHYSICAL_PRESENCE_ENABLE_CLEAR: case TCG2_PHYSICAL_PRESENCE_ENABLE_CLEAR_2: case TCG2_PHYSICAL_PRESENCE_ENABLE_CLEAR_3: if ((Flags.PPFlags & TCG2_BIOS_TPM_MANAGEMENT_FLAG_PP_REQUIRED_FOR_CLEAR) == 0) { RequestConfirmed = TRUE; } break; case TCG2_PHYSICAL_PRESENCE_NO_ACTION: case TCG2_PHYSICAL_PRESENCE_SET_PP_REQUIRED_FOR_CLEAR_TRUE: RequestConfirmed = TRUE; break; case TCG2_PHYSICAL_PRESENCE_SET_PP_REQUIRED_FOR_CLEAR_FALSE: break; case TCG2_PHYSICAL_PRESENCE_SET_PCR_BANKS: if ((Flags.PPFlags & TCG2_BIOS_TPM_MANAGEMENT_FLAG_PP_REQUIRED_FOR_CHANGE_PCRS) == 0) { RequestConfirmed = TRUE; } break; case TCG2_PHYSICAL_PRESENCE_CHANGE_EPS: if ((Flags.PPFlags & TCG2_BIOS_TPM_MANAGEMENT_FLAG_PP_REQUIRED_FOR_CHANGE_EPS) == 0) { RequestConfirmed = TRUE; } break; case TCG2_PHYSICAL_PRESENCE_LOG_ALL_DIGESTS: RequestConfirmed = TRUE; break; case TCG2_PHYSICAL_PRESENCE_ENABLE_BLOCK_SID: if ((Flags.PPFlags & TCG2_BIOS_STORAGE_MANAGEMENT_FLAG_PP_REQUIRED_FOR_ENABLE_BLOCK_SID) == 0) { RequestConfirmed = TRUE; } break; case TCG2_PHYSICAL_PRESENCE_DISABLE_BLOCK_SID: if ((Flags.PPFlags & TCG2_BIOS_STORAGE_MANAGEMENT_FLAG_PP_REQUIRED_FOR_DISABLE_BLOCK_SID) == 0) { RequestConfirmed = TRUE; } break; case TCG2_PHYSICAL_PRESENCE_SET_PP_REQUIRED_FOR_ENABLE_BLOCK_SID_FUNC_TRUE: case TCG2_PHYSICAL_PRESENCE_SET_PP_REQUIRED_FOR_DISABLE_BLOCK_SID_FUNC_TRUE: RequestConfirmed = TRUE; break; case TCG2_PHYSICAL_PRESENCE_SET_PP_REQUIRED_FOR_ENABLE_BLOCK_SID_FUNC_FALSE: case TCG2_PHYSICAL_PRESENCE_SET_PP_REQUIRED_FOR_DISABLE_BLOCK_SID_FUNC_FALSE: break; default: if (!mIsTcg2PPVerLowerThan_1_3) { if (OperationRequest < TCG2_PHYSICAL_PRESENCE_VENDOR_SPECIFIC_OPERATION) { // // TCG2 PP1.3 spec defined operations that are reserved or un-implemented // return TCG_PP_GET_USER_CONFIRMATION_NOT_IMPLEMENTED; } } else { // // TCG PP lower than 1.3. (1.0, 1.1, 1.2) // if (OperationRequest <= TCG2_PHYSICAL_PRESENCE_NO_ACTION_MAX) { RequestConfirmed = TRUE; } else if (OperationRequest < TCG2_PHYSICAL_PRESENCE_VENDOR_SPECIFIC_OPERATION) { return TCG_PP_GET_USER_CONFIRMATION_NOT_IMPLEMENTED; } } break; } if (OperationRequest >= TCG2_PHYSICAL_PRESENCE_VENDOR_SPECIFIC_OPERATION) { return Tcg2PpVendorLibGetUserConfirmationStatusFunction (OperationRequest, Flags.PPFlags); } if (RequestConfirmed) { return TCG_PP_GET_USER_CONFIRMATION_ALLOWED_AND_PPUSER_NOT_REQUIRED; } else { return TCG_PP_GET_USER_CONFIRMATION_ALLOWED_AND_PPUSER_REQUIRED; } } /** The constructor function locates SmmVariable protocol. 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 Tcg2PhysicalPresenceLibConstructor ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { EFI_STATUS Status; if (AsciiStrnCmp(PP_INF_VERSION_1_2, (CHAR8 *)PcdGetPtr(PcdTcgPhysicalPresenceInterfaceVer), sizeof(PP_INF_VERSION_1_2) - 1) <= 0) { mIsTcg2PPVerLowerThan_1_3 = TRUE; } // // Locate SmmVariableProtocol. // Status = gSmst->SmmLocateProtocol (&gEfiSmmVariableProtocolGuid, NULL, (VOID**)&mTcg2PpSmmVariable); ASSERT_EFI_ERROR (Status); mTcg2PhysicalPresenceFlags = PcdGet32(PcdTcg2PhysicalPresenceFlags); return EFI_SUCCESS; }