In case ShellConvertStringToUint64() fails the Handles are left uninitialized. That can for example happen for Handle2 and Handle3 in case only one parameter was specified on the command line. Which can trigger the ASSERT() in line 185. Reproducer: boot ovmf to efi shell in qemu, using q35 machine type, then try disconnect the sata controller in efi shell. Fix that by explicitly setting them to NULL in that case. While being at it also simplify the logic and avoid pointlessly calling ShellConvertStringToUint64() in case ParamN is NULL. Signed-off-by: Gerd Hoffmann <kraxel@redhat.com> Reviewed-by: Zhichao Gao <zhichao.gao@intel.com>
		
			
				
	
	
		
			216 lines
		
	
	
		
			7.4 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			216 lines
		
	
	
		
			7.4 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
|   Main file for Disconnect shell Driver1 function.
 | |
| 
 | |
|   (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
 | |
|   (C) Copyright 2015 Hewlett-Packard Development Company, L.P.<BR>
 | |
|   Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
 | |
|   SPDX-License-Identifier: BSD-2-Clause-Patent
 | |
| 
 | |
| **/
 | |
| 
 | |
| #include "UefiShellDriver1CommandsLib.h"
 | |
| 
 | |
| STATIC CONST SHELL_PARAM_ITEM  ParamList[] = {
 | |
|   { L"-r",  TypeFlag },
 | |
|   { L"-nc", TypeFlag },
 | |
|   { NULL,   TypeMax  }
 | |
| };
 | |
| 
 | |
| /**
 | |
|   Disconnect everything.
 | |
| 
 | |
|   @retval EFI_SUCCESS     The operation was successful.
 | |
| **/
 | |
| EFI_STATUS
 | |
| DisconnectAll (
 | |
|   VOID
 | |
|   )
 | |
| {
 | |
|   //
 | |
|   // Stolen from UEFI 2.3 spec (May 2009 version)
 | |
|   // Pages 171/172
 | |
|   // Removed gBS local definition
 | |
|   //
 | |
| 
 | |
|   //
 | |
|   // Disconnect All Handles Example
 | |
|   // The following example recusively disconnects all drivers from all
 | |
|   // controllers in a platform.
 | |
|   //
 | |
|   EFI_STATUS  Status;
 | |
|   //  EFI_BOOT_SERVICES *gBS;
 | |
|   UINTN       HandleCount;
 | |
|   EFI_HANDLE  *HandleBuffer;
 | |
|   UINTN       HandleIndex;
 | |
| 
 | |
|   //
 | |
|   // Retrieve the list of all handles from the handle database
 | |
|   //
 | |
|   Status = gBS->LocateHandleBuffer (
 | |
|                   AllHandles,
 | |
|                   NULL,
 | |
|                   NULL,
 | |
|                   &HandleCount,
 | |
|                   &HandleBuffer
 | |
|                   );
 | |
|   if (!EFI_ERROR (Status)) {
 | |
|     for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++) {
 | |
|       Status = gBS->DisconnectController (
 | |
|                       HandleBuffer[HandleIndex],
 | |
|                       NULL,
 | |
|                       NULL
 | |
|                       );
 | |
|     }
 | |
| 
 | |
|     gBS->FreePool (HandleBuffer);
 | |
|     //
 | |
|     // end of stealing
 | |
|     //
 | |
|   }
 | |
| 
 | |
|   return (EFI_SUCCESS);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Function for 'disconnect' command.
 | |
| 
 | |
|   @param[in] ImageHandle  Handle to the Image (NULL if Internal).
 | |
|   @param[in] SystemTable  Pointer to the System Table (NULL if Internal).
 | |
| **/
 | |
| SHELL_STATUS
 | |
| EFIAPI
 | |
| ShellCommandRunDisconnect (
 | |
|   IN EFI_HANDLE        ImageHandle,
 | |
|   IN EFI_SYSTEM_TABLE  *SystemTable
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS    Status;
 | |
|   LIST_ENTRY    *Package;
 | |
|   CHAR16        *ProblemParam;
 | |
|   SHELL_STATUS  ShellStatus;
 | |
|   CONST CHAR16  *Param1;
 | |
|   CONST CHAR16  *Param2;
 | |
|   CONST CHAR16  *Param3;
 | |
|   EFI_HANDLE    Handle1;
 | |
|   EFI_HANDLE    Handle2;
 | |
|   EFI_HANDLE    Handle3;
 | |
|   UINT64        Intermediate1;
 | |
|   UINT64        Intermediate2;
 | |
|   UINT64        Intermediate3;
 | |
| 
 | |
|   ShellStatus = SHELL_SUCCESS;
 | |
| 
 | |
|   //
 | |
|   // initialize the shell lib (we must be in non-auto-init...)
 | |
|   //
 | |
|   Status = ShellInitialize ();
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
|   Status = CommandInit ();
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
|   //
 | |
|   // parse the command line
 | |
|   //
 | |
|   Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     if ((Status == EFI_VOLUME_CORRUPTED) && (ProblemParam != NULL)) {
 | |
|       ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellDriver1HiiHandle, L"disconnect", ProblemParam);
 | |
|       FreePool (ProblemParam);
 | |
|       ShellStatus = SHELL_INVALID_PARAMETER;
 | |
|     } else {
 | |
|       ASSERT (FALSE);
 | |
|     }
 | |
|   } else {
 | |
|     if (ShellCommandLineGetFlag (Package, L"-r")) {
 | |
|       if (ShellCommandLineGetCount (Package) > 1) {
 | |
|         ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellDriver1HiiHandle, L"disconnect");
 | |
|         ShellStatus = SHELL_INVALID_PARAMETER;
 | |
|       } else if (ShellCommandLineGetCount (Package) < 1) {
 | |
|         ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellDriver1HiiHandle, L"disconnect");
 | |
|         ShellStatus = SHELL_INVALID_PARAMETER;
 | |
|       } else {
 | |
|         Status = DisconnectAll ();
 | |
|         //
 | |
|         // Reconnect all consoles if -nc is not provided
 | |
|         //
 | |
|         if (!ShellCommandLineGetFlag (Package, L"-nc")) {
 | |
|           ShellConnectFromDevPaths (L"ConInDev");
 | |
|           ShellConnectFromDevPaths (L"ConOutDev");
 | |
|           ShellConnectFromDevPaths (L"ErrOutDev");
 | |
|           ShellConnectFromDevPaths (L"ErrOut");
 | |
|           ShellConnectFromDevPaths (L"ConIn");
 | |
|           ShellConnectFromDevPaths (L"ConOut");
 | |
|         }
 | |
|       }
 | |
|     } else if (ShellCommandLineGetFlag (Package, L"-nc")) {
 | |
|       ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellDriver1HiiHandle, L"disconnect");
 | |
|       ShellStatus = SHELL_INVALID_PARAMETER;
 | |
|     } else {
 | |
|       if (ShellCommandLineGetCount (Package) > 4) {
 | |
|         ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellDriver1HiiHandle, L"disconnect");
 | |
|         ShellStatus = SHELL_INVALID_PARAMETER;
 | |
|       } else if (ShellCommandLineGetCount (Package) < 2) {
 | |
|         ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellDriver1HiiHandle, L"disconnect");
 | |
|         ShellStatus = SHELL_INVALID_PARAMETER;
 | |
|       } else {
 | |
|         //
 | |
|         // must have between 1 and 3 handles passed in ...
 | |
|         //
 | |
|         Param1 = ShellCommandLineGetRawValue (Package, 1);
 | |
|         Param2 = ShellCommandLineGetRawValue (Package, 2);
 | |
|         Param3 = ShellCommandLineGetRawValue (Package, 3);
 | |
| 
 | |
|         if (Param1 && !EFI_ERROR (ShellConvertStringToUint64 (Param1, &Intermediate1, TRUE, FALSE))) {
 | |
|           Handle1 = ConvertHandleIndexToHandle ((UINTN)Intermediate1);
 | |
|         } else {
 | |
|           Handle1 = NULL;
 | |
|         }
 | |
| 
 | |
|         if (Param2 && !EFI_ERROR (ShellConvertStringToUint64 (Param2, &Intermediate2, TRUE, FALSE))) {
 | |
|           Handle2 = ConvertHandleIndexToHandle ((UINTN)Intermediate2);
 | |
|         } else {
 | |
|           Handle2 = NULL;
 | |
|         }
 | |
| 
 | |
|         if (Param3 && !EFI_ERROR (ShellConvertStringToUint64 (Param3, &Intermediate3, TRUE, FALSE))) {
 | |
|           Handle3 = ConvertHandleIndexToHandle ((UINTN)Intermediate3);
 | |
|         } else {
 | |
|           Handle3 = NULL;
 | |
|         }
 | |
| 
 | |
|         if ((Param1 != NULL) && (Handle1 == NULL)) {
 | |
|           ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_INV_HANDLE), gShellDriver1HiiHandle, L"disconnect", Param1);
 | |
|           ShellStatus = SHELL_INVALID_PARAMETER;
 | |
|         } else if ((Param2 != NULL) && (Handle2 == NULL)) {
 | |
|           ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_INV_HANDLE), gShellDriver1HiiHandle, L"disconnect", Param2);
 | |
|           ShellStatus = SHELL_INVALID_PARAMETER;
 | |
|         } else if ((Param3 != NULL) && (Handle3 == NULL)) {
 | |
|           ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_INV_HANDLE), gShellDriver1HiiHandle, L"disconnect", Param3);
 | |
|           ShellStatus = SHELL_INVALID_PARAMETER;
 | |
|         } else if ((Handle2 != NULL) && EFI_ERROR (gBS->OpenProtocol (Handle2, &gEfiDriverBindingProtocolGuid, NULL, gImageHandle, NULL, EFI_OPEN_PROTOCOL_TEST_PROTOCOL))) {
 | |
|           ASSERT (Param2 != NULL);
 | |
|           ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_HANDLE_NOT), gShellDriver1HiiHandle, L"disconnect", ShellStrToUintn (Param2), L"driver handle");
 | |
|           ShellStatus = SHELL_INVALID_PARAMETER;
 | |
|         } else {
 | |
|           ASSERT (Param1 != NULL);
 | |
|           Status = gBS->DisconnectController (Handle1, Handle2, Handle3);
 | |
|           ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_3P_RESULT), gShellDriver1HiiHandle, L"Disconnect", (UINTN)Intermediate1, (UINTN)Intermediate2, (UINTN)Intermediate3, Status);
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (ShellStatus == SHELL_SUCCESS) {
 | |
|     if (Status == EFI_SECURITY_VIOLATION) {
 | |
|       ShellStatus = SHELL_SECURITY_VIOLATION;
 | |
|     } else if (Status == EFI_INVALID_PARAMETER) {
 | |
|       ShellStatus = SHELL_INVALID_PARAMETER;
 | |
|     } else if (EFI_ERROR (Status)) {
 | |
|       ShellStatus = SHELL_NOT_FOUND;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return (ShellStatus);
 | |
| }
 |