]> git.proxmox.com Git - mirror_edk2.git/blobdiff - SecurityPkg/Library/DxeTcgPhysicalPresenceLib/DxeTcgPhysicalPresenceLib.c
Add Physical Presence request UI detection logic. Refine UIConfirm ReadKey logic
[mirror_edk2.git] / SecurityPkg / Library / DxeTcgPhysicalPresenceLib / DxeTcgPhysicalPresenceLib.c
index 4b99ab840d4086f197cc07d84ef471c1eb797b64..2130b2b43c706fcb9d815f71d6713abad1b0e06f 100644 (file)
@@ -440,7 +440,7 @@ ExecutePhysicalPresence (
                           If false, F10 is used as confirm key.\r
 \r
   @retval     TRUE        User confirmed the changes by input.\r
-  @retval     FALSE       User discarded the changes.\r
+  @retval     FALSE       User discarded the changes or device error.\r
 \r
 **/\r
 BOOLEAN\r
@@ -451,22 +451,29 @@ ReadUserKey (
   EFI_STATUS                        Status;\r
   EFI_INPUT_KEY                     Key;\r
   UINT16                            InputKey;\r
-      \r
+  UINTN                             Index;\r
+\r
   InputKey = 0; \r
   do {\r
-    Status = gBS->CheckEvent (gST->ConIn->WaitForKey);\r
-    if (!EFI_ERROR (Status)) {\r
-      Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
-      if (Key.ScanCode == SCAN_ESC) {\r
-        InputKey = Key.ScanCode;\r
-      }\r
-      if ((Key.ScanCode == SCAN_F10) && !CautionKey) {\r
-        InputKey = Key.ScanCode;\r
-      }\r
-      if ((Key.ScanCode == SCAN_F12) && CautionKey) {\r
-        InputKey = Key.ScanCode;\r
-      }\r
-    }      \r
+    Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
+    if (Status == EFI_NOT_READY) {\r
+      gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &Index);\r
+      continue;\r
+    }\r
+\r
+    if (Status == EFI_DEVICE_ERROR) {\r
+      return FALSE;\r
+    }\r
+\r
+    if (Key.ScanCode == SCAN_ESC) {\r
+      InputKey = Key.ScanCode;\r
+    }\r
+    if ((Key.ScanCode == SCAN_F10) && !CautionKey) {\r
+      InputKey = Key.ScanCode;\r
+    }\r
+    if ((Key.ScanCode == SCAN_F12) && CautionKey) {\r
+      InputKey = Key.ScanCode;\r
+    }\r
   } while (InputKey == 0);\r
 \r
   if (InputKey != SCAN_ESC) {\r
@@ -886,32 +893,34 @@ UserConfirm (
 }\r
 \r
 /**\r
-  Check and execute the requested physical presence command.\r
-\r
-  Caution: This function may receive untrusted input.\r
-  TcgPpData variable is external input, so this function will validate\r
-  its data structure to be valid value.\r
-\r
-  @param[in] TcgProtocol          EFI TCG Protocol instance. \r
-  @param[in] TcgPpData            Point to the physical presence NV variable.\r
+  Check if there is a valid physical presence command request. Also updates parameter value \r
+  to whether the requested physical presence command already confirmed by user\r
\r
+   @param[in]  TcgProtocol                 EFI TCG Protocol instance. \r
+   @param[out] RequestConfirmed            If the physical presence operation command required user confirm from UI.\r
+                                             True, it indicates the command doesn't require user confirm, or already confirmed \r
+                                                   in last boot cycle by user.\r
+                                             False, it indicates the command need user confirm from UI.\r
+\r
+   @retval  TRUE        Physical Presence operation command is valid.\r
+   @retval  FALSE       Physical Presence operation command is invalid.\r
 \r
 **/\r
-VOID\r
-ExecutePendingTpmRequest (\r
-  IN      EFI_TCG_PROTOCOL          *TcgProtocol,\r
-  IN      EFI_PHYSICAL_PRESENCE     *TcgPpData\r
+BOOLEAN\r
+HaveValidTpmRequest  (\r
+  IN      EFI_PHYSICAL_PRESENCE     *TcgPpData,\r
+  OUT     BOOLEAN                   *RequestConfirmed\r
   )\r
 {\r
-  EFI_STATUS                        Status;\r
-  UINTN                             DataSize;\r
   UINT8                             Flags;\r
-  BOOLEAN                           RequestConfirmed;\r
+  \r
+  Flags = TcgPpData->Flags;\r
+  *RequestConfirmed = FALSE;\r
 \r
-  Flags            = TcgPpData->Flags;\r
-  RequestConfirmed = FALSE;  \r
   switch (TcgPpData->PPRequest) {\r
     case PHYSICAL_PRESENCE_NO_ACTION:\r
-      return;\r
+      *RequestConfirmed = TRUE;\r
+      return TRUE;\r
     case PHYSICAL_PRESENCE_ENABLE:\r
     case PHYSICAL_PRESENCE_DISABLE:\r
     case PHYSICAL_PRESENCE_ACTIVATE:\r
@@ -924,64 +933,106 @@ ExecutePendingTpmRequest (
     case PHYSICAL_PRESENCE_DEACTIVATE_DISABLE_OWNER_FALSE:\r
     case PHYSICAL_PRESENCE_SET_OPERATOR_AUTH:\r
       if ((Flags & FLAG_NO_PPI_PROVISION) != 0) {\r
-        RequestConfirmed = TRUE;\r
+        *RequestConfirmed = TRUE;\r
       }\r
       break;\r
 \r
     case PHYSICAL_PRESENCE_CLEAR:\r
     case PHYSICAL_PRESENCE_ENABLE_ACTIVATE_CLEAR:\r
       if ((Flags & FLAG_NO_PPI_CLEAR) != 0) {\r
-        RequestConfirmed = TRUE;\r
+        *RequestConfirmed = TRUE;\r
       }\r
       break;\r
 \r
     case PHYSICAL_PRESENCE_DEFERRED_PP_UNOWNERED_FIELD_UPGRADE:\r
       if ((Flags & FLAG_NO_PPI_MAINTENANCE) != 0) {\r
-        RequestConfirmed = TRUE;\r
+        *RequestConfirmed = TRUE;\r
       }\r
       break;\r
 \r
     case PHYSICAL_PRESENCE_CLEAR_ENABLE_ACTIVATE:\r
     case PHYSICAL_PRESENCE_ENABLE_ACTIVATE_CLEAR_ENABLE_ACTIVATE:\r
       if ((Flags & FLAG_NO_PPI_CLEAR) != 0 && (Flags & FLAG_NO_PPI_PROVISION) != 0) {\r
-        RequestConfirmed = TRUE;\r
+        *RequestConfirmed = TRUE;\r
       }\r
-      break;  \r
+      break;\r
 \r
     case PHYSICAL_PRESENCE_SET_NO_PPI_PROVISION_FALSE:\r
     case PHYSICAL_PRESENCE_SET_NO_PPI_CLEAR_FALSE:\r
     case PHYSICAL_PRESENCE_SET_NO_PPI_MAINTENANCE_FALSE:\r
-      RequestConfirmed = TRUE;\r
+      *RequestConfirmed = TRUE;\r
       break;\r
-      \r
+\r
     case PHYSICAL_PRESENCE_SET_NO_PPI_PROVISION_TRUE:\r
     case PHYSICAL_PRESENCE_SET_NO_PPI_CLEAR_TRUE:\r
     case PHYSICAL_PRESENCE_SET_NO_PPI_MAINTENANCE_TRUE:\r
       break;\r
-      \r
+\r
     default:\r
       //\r
-      // Invalid operation request.\r
+      // Wrong Physical Presence command\r
       //\r
-      TcgPpData->PPResponse = TPM_PP_BIOS_FAILURE;\r
-      TcgPpData->LastPPRequest = TcgPpData->PPRequest;\r
-      TcgPpData->PPRequest = PHYSICAL_PRESENCE_NO_ACTION;\r
-      DataSize = sizeof (EFI_PHYSICAL_PRESENCE);\r
-      Status = gRT->SetVariable (\r
-                      PHYSICAL_PRESENCE_VARIABLE,\r
-                      &gEfiPhysicalPresenceGuid,\r
-                      EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
-                      DataSize,\r
-                      TcgPpData\r
-                      );\r
-      return;\r
+      return FALSE;\r
   }\r
 \r
   if ((Flags & FLAG_RESET_TRACK) != 0) {\r
     //\r
     // It had been confirmed in last boot, it doesn't need confirm again.\r
     //\r
-    RequestConfirmed = TRUE;\r
+    *RequestConfirmed = TRUE;\r
+  }\r
+\r
+  //\r
+  // Physical Presence command is correct\r
+  //\r
+  return TRUE;\r
+}\r
+\r
+\r
+/**\r
+  Check and execute the requested physical presence command.\r
+\r
+  Caution: This function may receive untrusted input.\r
+  TcgPpData variable is external input, so this function will validate\r
+  its data structure to be valid value.\r
+\r
+  @param[in] TcgProtocol          EFI TCG Protocol instance. \r
+  @param[in] TcgPpData            Point to the physical presence NV variable.\r
+\r
+**/\r
+VOID\r
+ExecutePendingTpmRequest (\r
+  IN      EFI_TCG_PROTOCOL          *TcgProtocol,\r
+  IN      EFI_PHYSICAL_PRESENCE     *TcgPpData\r
+  )\r
+{\r
+  EFI_STATUS                        Status;\r
+  UINTN                             DataSize;\r
+  BOOLEAN                           RequestConfirmed;\r
+\r
+  if (TcgPpData->PPRequest == PHYSICAL_PRESENCE_NO_ACTION) {\r
+    //\r
+    // No operation request\r
+    //\r
+    return;\r
+  }\r
+\r
+  if (!HaveValidTpmRequest(TcgPpData, &RequestConfirmed)) {\r
+    //\r
+    // Invalid operation request.\r
+    //\r
+    TcgPpData->PPResponse = TPM_PP_BIOS_FAILURE;\r
+    TcgPpData->LastPPRequest = TcgPpData->PPRequest;\r
+    TcgPpData->PPRequest = PHYSICAL_PRESENCE_NO_ACTION;\r
+    DataSize = sizeof (EFI_PHYSICAL_PRESENCE);\r
+    Status = gRT->SetVariable (\r
+                    PHYSICAL_PRESENCE_VARIABLE,\r
+                    &gEfiPhysicalPresenceGuid,\r
+                    EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
+                    DataSize,\r
+                    TcgPpData\r
+                    );\r
+    return;\r
   }\r
 \r
   if (!RequestConfirmed) {\r
@@ -1149,3 +1200,88 @@ TcgPhysicalPresenceLibProcessRequest (
   TpmPhysicalPresence (TcgProtocol, TPM_PHYSICAL_PRESENCE_NOTPRESENT | TPM_PHYSICAL_PRESENCE_LOCK);\r
 }\r
 \r
+/**\r
+  Check if the pending TPM request needs user input to confirm.\r
+\r
+  The TPM request may come from OS. This API will check if TPM request exists and need user\r
+  input to confirmation.\r
+  \r
+  @retval    TRUE        TPM needs input to confirm user physical presence.\r
+  @retval    FALSE       TPM doesn't need input to confirm user physical presence.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+TcgPhysicalPresenceLibNeedUserConfirm(\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  EFI_PHYSICAL_PRESENCE   TcgPpData;\r
+  UINTN                   DataSize;\r
+  BOOLEAN                 RequestConfirmed;\r
+  BOOLEAN                 LifetimeLock;\r
+  BOOLEAN                 CmdEnable;\r
+  EFI_TCG_PROTOCOL        *TcgProtocol;\r
+\r
+  Status = gBS->LocateProtocol (&gEfiTcgProtocolGuid, NULL, (VOID **)&TcgProtocol);\r
+  if (EFI_ERROR (Status)) {\r
+    return FALSE;\r
+  }\r
+\r
+  //\r
+  // Check Tpm requests\r
+  //\r
+  DataSize = sizeof (EFI_PHYSICAL_PRESENCE);\r
+  Status = gRT->GetVariable (\r
+                  PHYSICAL_PRESENCE_VARIABLE,\r
+                  &gEfiPhysicalPresenceGuid,\r
+                  NULL,\r
+                  &DataSize,\r
+                  &TcgPpData\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return FALSE;\r
+  }\r
+\r
+  if (TcgPpData.PPRequest == PHYSICAL_PRESENCE_NO_ACTION) {\r
+    //\r
+    // No operation request\r
+    //\r
+    return FALSE;\r
+  }\r
+\r
+  if (!HaveValidTpmRequest(&TcgPpData, &RequestConfirmed)) {\r
+    //\r
+    // Invalid operation request.\r
+    //\r
+    return FALSE;\r
+  }\r
+\r
+  //\r
+  // Check Tpm Capability\r
+  //\r
+  Status = GetTpmCapability (TcgProtocol, &LifetimeLock, &CmdEnable);\r
+  if (EFI_ERROR (Status)) {\r
+    return FALSE;\r
+  }\r
+\r
+  if (!CmdEnable) {\r
+    if (LifetimeLock) {\r
+      //\r
+      // physicalPresenceCMDEnable is locked, can't execute physical presence command.\r
+      //\r
+      return FALSE;\r
+    }\r
+  }\r
+\r
+  if (!RequestConfirmed) {\r
+    //\r
+    // Need UI to confirm\r
+    //\r
+    return TRUE;\r
+  }\r
+\r
+  return FALSE;\r
+}\r
+\r