From mboxrd@z Thu Jan 1 00:00:00 1970 Authentication-Results: mx.groups.io; dkim=missing; spf=fail (domain: intel.com, ip: , mailfrom: michael.d.kinney@intel.com) Received: from mga12.intel.com (mga12.intel.com []) by groups.io with SMTP; Wed, 21 Aug 2019 19:36:13 -0700 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga003.jf.intel.com ([10.7.209.27]) by fmsmga106.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 21 Aug 2019 19:36:12 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.64,415,1559545200"; d="scan'208";a="181225532" Received: from unknown (HELO mdkinney-MOBL2.amr.corp.intel.com) ([10.241.98.74]) by orsmga003.jf.intel.com with ESMTP; 21 Aug 2019 19:36:12 -0700 From: "Michael D Kinney" To: devel@edk2.groups.io Cc: Jordan Justen , Ray Ni , Andrew Fish , Tim Lewis Subject: [Patch][edk2-stable201908 1/2] EmulatorPkg/Win/Host: Fix image unload regression Date: Wed, 21 Aug 2019 19:36:09 -0700 Message-Id: <20190822023610.2068-2-michael.d.kinney@intel.com> X-Mailer: git-send-email 2.21.0.windows.1 In-Reply-To: <20190822023610.2068-1-michael.d.kinney@intel.com> References: <20190822023610.2068-1-michael.d.kinney@intel.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit https://bugzilla.tianocore.org/show_bug.cgi?id=2104 When UEFI Applications or UEFI Drivers are unloaded, the PeCoffLoaderUnloadImageExtraAction() needs to unload the image using FreeLibrary() if the image was successfully loaded using LoadLibrrayEx(). This is a regression from the Nt32Pkg that supported unloading applications and drivers as well as loading the same application or driver multiple times. Cc: Jordan Justen Cc: Ray Ni Cc: Andrew Fish Cc: Tim Lewis Signed-off-by: Michael D Kinney --- EmulatorPkg/Win/Host/WinHost.c | 167 +++++++++++++++++++++++++++++++-- 1 file changed, 161 insertions(+), 6 deletions(-) diff --git a/EmulatorPkg/Win/Host/WinHost.c b/EmulatorPkg/Win/Host/WinHost.c index dd52075f98..9c6acac279 100644 --- a/EmulatorPkg/Win/Host/WinHost.c +++ b/EmulatorPkg/Win/Host/WinHost.c @@ -19,6 +19,25 @@ SPDX-License-Identifier: BSD-2-Clause-Patent #define SE_TIME_ZONE_NAME TEXT("SeTimeZonePrivilege") #endif +// +// The growth size for array of module handle entries +// +#define MAX_PDB_NAME_TO_MOD_HANDLE_ARRAY_SIZE 0x100 + +// +// Module handle entry structure +// +typedef struct { + CHAR8 *PdbPointer; + VOID *ModHandle; +} PDB_NAME_TO_MOD_HANDLE; + +// +// An Array to hold the module handles +// +PDB_NAME_TO_MOD_HANDLE *mPdbNameModHandleArray = NULL; +UINTN mPdbNameModHandleArraySize = 0; + // // Default information about where the FD is located. // This array gets filled in with information from PcdWinNtFirmwareVolume @@ -840,6 +859,120 @@ Returns: return Count; } +/** + Store the ModHandle in an array indexed by the Pdb File name. + The ModHandle is needed to unload the image. + @param ImageContext - Input data returned from PE Laoder Library. Used to find the + .PDB file name of the PE Image. + @param ModHandle - Returned from LoadLibraryEx() and stored for call to + FreeLibrary(). + @return return EFI_SUCCESS when ModHandle was stored. +--*/ +EFI_STATUS +AddModHandle ( + IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext, + IN VOID *ModHandle + ) + +{ + UINTN Index; + PDB_NAME_TO_MOD_HANDLE *Array; + UINTN PreviousSize; + PDB_NAME_TO_MOD_HANDLE *TempArray; + HANDLE Handle; + UINTN Size; + + // + // Return EFI_ALREADY_STARTED if this DLL has already been loaded + // + Array = mPdbNameModHandleArray; + for (Index = 0; Index < mPdbNameModHandleArraySize; Index++, Array++) { + if (Array->PdbPointer != NULL && Array->ModHandle == ModHandle) { + return EFI_ALREADY_STARTED; + } + } + + Array = mPdbNameModHandleArray; + for (Index = 0; Index < mPdbNameModHandleArraySize; Index++, Array++) { + if (Array->PdbPointer == NULL) { + // + // Make a copy of the stirng and store the ModHandle + // + Handle = GetProcessHeap (); + Size = AsciiStrLen (ImageContext->PdbPointer) + 1; + Array->PdbPointer = HeapAlloc ( Handle, HEAP_ZERO_MEMORY, Size); + ASSERT (Array->PdbPointer != NULL); + + AsciiStrCpyS (Array->PdbPointer, Size, ImageContext->PdbPointer); + Array->ModHandle = ModHandle; + return EFI_SUCCESS; + } + } + + // + // No free space in mPdbNameModHandleArray so grow it by + // MAX_PDB_NAME_TO_MOD_HANDLE_ARRAY_SIZE entires. + // + PreviousSize = mPdbNameModHandleArraySize * sizeof (PDB_NAME_TO_MOD_HANDLE); + mPdbNameModHandleArraySize += MAX_PDB_NAME_TO_MOD_HANDLE_ARRAY_SIZE; + // + // re-allocate a new buffer and copy the old values to the new locaiton. + // + TempArray = HeapAlloc (GetProcessHeap (), + HEAP_ZERO_MEMORY, + mPdbNameModHandleArraySize * sizeof (PDB_NAME_TO_MOD_HANDLE) + ); + + CopyMem ((VOID *) (UINTN) TempArray, (VOID *) (UINTN)mPdbNameModHandleArray, PreviousSize); + + HeapFree (GetProcessHeap (), 0, mPdbNameModHandleArray); + + mPdbNameModHandleArray = TempArray; + if (mPdbNameModHandleArray == NULL) { + ASSERT (FALSE); + return EFI_OUT_OF_RESOURCES; + } + + return AddModHandle (ImageContext, ModHandle); +} + +/** + Return the ModHandle and delete the entry in the array. + @param ImageContext - Input data returned from PE Laoder Library. Used to find the + .PDB file name of the PE Image. + @return + ModHandle - ModHandle assoicated with ImageContext is returned + NULL - No ModHandle associated with ImageContext +**/ +VOID * +RemoveModHandle ( + IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext + ) +{ + UINTN Index; + PDB_NAME_TO_MOD_HANDLE *Array; + + if (ImageContext->PdbPointer == NULL) { + // + // If no PDB pointer there is no ModHandle so return NULL + // + return NULL; + } + + Array = mPdbNameModHandleArray; + for (Index = 0; Index < mPdbNameModHandleArraySize; Index++, Array++) { + if ((Array->PdbPointer != NULL) && (AsciiStrCmp(Array->PdbPointer, ImageContext->PdbPointer) == 0)) { + // + // If you find a match return it and delete the entry + // + HeapFree (GetProcessHeap (), 0, Array->PdbPointer); + Array->PdbPointer = NULL; + return Array->ModHandle; + } + } + + return NULL; +} VOID EFIAPI @@ -847,6 +980,7 @@ PeCoffLoaderRelocateImageExtraAction ( IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext ) { + EFI_STATUS Status; VOID *DllEntryPoint; CHAR16 *DllFileName; HMODULE Library; @@ -855,7 +989,7 @@ PeCoffLoaderRelocateImageExtraAction ( ASSERT (ImageContext != NULL); // // If we load our own PE COFF images the Windows debugger can not source - // level debug our code. If a valid PDB pointer exists usw it to load + // level debug our code. If a valid PDB pointer exists use it to load // the *.dll file as a library using Windows* APIs. This allows // source level debug. The image is still loaded and relocated // in the Framework memory space like on a real system (by the code above), @@ -913,10 +1047,22 @@ PeCoffLoaderRelocateImageExtraAction ( } if ((Library != NULL) && (DllEntryPoint != NULL)) { - ImageContext->EntryPoint = (EFI_PHYSICAL_ADDRESS) (UINTN) DllEntryPoint; - SecPrint ("LoadLibraryEx (%S,\n NULL, DONT_RESOLVE_DLL_REFERENCES)\n", DllFileName); + Status = AddModHandle (ImageContext, Library); + if (Status == EFI_ALREADY_STARTED) { + // + // If the DLL has already been loaded before, then this instance of the DLL can not be debugged. + // + ImageContext->PdbPointer = NULL; + SecPrint ("WARNING: DLL already loaded. No source level debug %S.\n\r", DllFileName); + } else { + // + // This DLL is not already loaded, so source level debugging is supported. + // + ImageContext->EntryPoint = (EFI_PHYSICAL_ADDRESS) (UINTN) DllEntryPoint; + SecPrint ("LoadLibraryEx (\n\r %S,\n\r NULL, DONT_RESOLVE_DLL_REFERENCES)\n\r", DllFileName); + } } else { - SecPrint ("WARNING: No source level debug %S. \n", DllFileName); + SecPrint ("WARNING: No source level debug %S. \n\r", DllFileName); } free (DllFileName); @@ -926,13 +1072,22 @@ PeCoffLoaderRelocateImageExtraAction ( VOID EFIAPI PeCoffLoaderUnloadImageExtraAction ( - IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext + IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext ) { + VOID *ModHandle; + ASSERT (ImageContext != NULL); + + ModHandle = RemoveModHandle (ImageContext); + if (ModHandle != NULL) { + FreeLibrary (ModHandle); + SecPrint ("FreeLibrary (\n\r %s)\n\r", ImageContext->PdbPointer); + } else { + SecPrint ("WARNING: Unload image without source level debug\n\r"); + } } - VOID _ModuleEntryPoint ( VOID -- 2.21.0.windows.1