From e72920ec617ba1fceb114b3bb2a587a8e836734b Mon Sep 17 00:00:00 2001 From: Aaron Antone Date: Mon, 8 Apr 2019 11:03:26 +0800 Subject: [PATCH] MdePkg/UefiDebugLibStdErr: Make it runtime safe REF: https://bugzilla.tianocore.org/show_bug.cgi?id=1416 After ExitBootServices, some pointer would be invalid such as the Protocol pointer and gST. The function depend on those should be prevent. So disable the related function while after ExitBootServices. Change the gST to a internal one, because there will be a cycle consume between UefiBootServicesTableLib and DebugLib due to the library constructors. Also remove the SMM support for this instance. Cc: Michael D Kinney Cc: Liming Gao Cc: Sean Brogan Cc: Michael Turner Cc: Bret Barkelew Signed-off-by: Zhichao Gao Reviewed-by: Liming Gao --- MdePkg/Library/UefiDebugLibStdErr/DebugLib.c | 113 +++++++++--------- .../UefiDebugLibStdErr/DebugLibConstructor.c | 77 ++++++++++++ .../UefiDebugLibStdErr/UefiDebugLibStdErr.inf | 12 +- 3 files changed, 145 insertions(+), 57 deletions(-) create mode 100644 MdePkg/Library/UefiDebugLibStdErr/DebugLibConstructor.c diff --git a/MdePkg/Library/UefiDebugLibStdErr/DebugLib.c b/MdePkg/Library/UefiDebugLibStdErr/DebugLib.c index 29f93cf3e3..40eb697e7e 100644 --- a/MdePkg/Library/UefiDebugLibStdErr/DebugLib.c +++ b/MdePkg/Library/UefiDebugLibStdErr/DebugLib.c @@ -10,7 +10,6 @@ #include #include -#include #include #include #include @@ -29,6 +28,8 @@ // VA_LIST mVaListNull; +extern BOOLEAN mPostEBS; +extern EFI_SYSTEM_TABLE *mDebugST; /** Prints a debug message to the debug output device if the specified error level is enabled. @@ -88,32 +89,34 @@ DebugPrintMarker ( { CHAR16 Buffer[MAX_DEBUG_MESSAGE_LENGTH]; - // - // If Format is NULL, then ASSERT(). - // - ASSERT (Format != NULL); - - // - // Check driver debug mask value and global mask - // - if ((ErrorLevel & GetDebugPrintErrorLevel ()) == 0) { - return; - } - - // - // Convert the DEBUG() message to a Unicode String - // - if (BaseListMarker == NULL) { - UnicodeVSPrintAsciiFormat (Buffer, MAX_DEBUG_MESSAGE_LENGTH, Format, VaListMarker); - } else { - UnicodeBSPrintAsciiFormat (Buffer, MAX_DEBUG_MESSAGE_LENGTH, Format, BaseListMarker); - } - - // - // Send the print string to the Standard Error device - // - if ((gST != NULL) && (gST->StdErr != NULL)) { - gST->StdErr->OutputString (gST->StdErr, Buffer); + if (!mPostEBS) { + // + // If Format is NULL, then ASSERT(). + // + ASSERT (Format != NULL); + + // + // Check driver debug mask value and global mask + // + if ((ErrorLevel & GetDebugPrintErrorLevel ()) == 0) { + return; + } + + // + // Convert the DEBUG() message to a Unicode String + // + if (BaseListMarker == NULL) { + UnicodeVSPrintAsciiFormat (Buffer, MAX_DEBUG_MESSAGE_LENGTH, Format, VaListMarker); + } else { + UnicodeBSPrintAsciiFormat (Buffer, MAX_DEBUG_MESSAGE_LENGTH, Format, BaseListMarker); + } + + // + // Send the print string to the Standard Error device + // + if ((mDebugST != NULL) && (mDebugST->StdErr != NULL)) { + mDebugST->StdErr->OutputString (mDebugST->StdErr, Buffer); + } } } @@ -207,33 +210,35 @@ DebugAssert ( { CHAR16 Buffer[MAX_DEBUG_MESSAGE_LENGTH]; - // - // Generate the ASSERT() message in Unicode format - // - UnicodeSPrintAsciiFormat ( - Buffer, - sizeof (Buffer), - "ASSERT [%a] %a(%d): %a\n", - gEfiCallerBaseName, - FileName, - LineNumber, - Description - ); - - // - // Send the print string to the Standard Error device - // - if ((gST != NULL) && (gST->StdErr != NULL)) { - gST->StdErr->OutputString (gST->StdErr, Buffer); - } - - // - // Generate a Breakpoint, DeadLoop, or NOP based on PCD settings - // - if ((PcdGet8(PcdDebugPropertyMask) & DEBUG_PROPERTY_ASSERT_BREAKPOINT_ENABLED) != 0) { - CpuBreakpoint (); - } else if ((PcdGet8(PcdDebugPropertyMask) & DEBUG_PROPERTY_ASSERT_DEADLOOP_ENABLED) != 0) { - CpuDeadLoop (); + if (!mPostEBS) { + // + // Generate the ASSERT() message in Unicode format + // + UnicodeSPrintAsciiFormat ( + Buffer, + sizeof (Buffer), + "ASSERT [%a] %a(%d): %a\n", + gEfiCallerBaseName, + FileName, + LineNumber, + Description + ); + + // + // Send the print string to the Standard Error device + // + if ((mDebugST != NULL) && (mDebugST->StdErr != NULL)) { + mDebugST->StdErr->OutputString (mDebugST->StdErr, Buffer); + } + + // + // Generate a Breakpoint, DeadLoop, or NOP based on PCD settings + // + if ((PcdGet8(PcdDebugPropertyMask) & DEBUG_PROPERTY_ASSERT_BREAKPOINT_ENABLED) != 0) { + CpuBreakpoint (); + } else if ((PcdGet8(PcdDebugPropertyMask) & DEBUG_PROPERTY_ASSERT_DEADLOOP_ENABLED) != 0) { + CpuDeadLoop (); + } } } diff --git a/MdePkg/Library/UefiDebugLibStdErr/DebugLibConstructor.c b/MdePkg/Library/UefiDebugLibStdErr/DebugLibConstructor.c new file mode 100644 index 0000000000..d4fdfbab55 --- /dev/null +++ b/MdePkg/Library/UefiDebugLibStdErr/DebugLibConstructor.c @@ -0,0 +1,77 @@ +/** @file + UEFI Dxe DebugLib constructor that prevent some debug service after ExitBootServices event, + because some pointer is nulled at that phase. + + Copyright (c) 2018, Microsoft Corporation + Copyright (c) 2015 - 2019, Intel Corporation. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include +#include +#include + +// +// BOOLEAN value to indicate if it is at the post ExitBootServices pahse +// +BOOLEAN mPostEBS = FALSE; + +EFI_EVENT mExitBootServicesEvent; + +// +// Pointer to SystemTable +// This library instance may have a cycle consume with UefiBootServicesTableLib +// because of the constructors. +// +EFI_SYSTEM_TABLE *mDebugST; + +/** + This routine sets the mPostEBS for exit boot servies true + to prevent DebugPort protocol dereferences when the pointer is nulled. + + @param Event Event whose notification function is being invoked. + @param Context Pointer to the notification function's context. + +**/ +VOID +EFIAPI +ExitBootServicesCallback ( + EFI_EVENT Event, + VOID* Context + ) +{ + mPostEBS = TRUE; + return; +} + +/** + The constructor gets the pointers to the system table. + And create a event to indicate it is after ExitBootServices. + + @param ImageHandle The firmware allocated handle for the EFI image. + @param SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS. + +**/ +EFI_STATUS +EFIAPI +DxeDebugLibConstructor( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + mDebugST = SystemTable; + + SystemTable->BootServices->CreateEventEx ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + ExitBootServicesCallback, + NULL, + &gEfiEventExitBootServicesGuid, + &mExitBootServicesEvent + ); + + return EFI_SUCCESS; +} diff --git a/MdePkg/Library/UefiDebugLibStdErr/UefiDebugLibStdErr.inf b/MdePkg/Library/UefiDebugLibStdErr/UefiDebugLibStdErr.inf index 865cc98753..deaa3427f6 100644 --- a/MdePkg/Library/UefiDebugLibStdErr/UefiDebugLibStdErr.inf +++ b/MdePkg/Library/UefiDebugLibStdErr/UefiDebugLibStdErr.inf @@ -3,7 +3,9 @@ # # Debug Lib that sends messages to the the Standard Error Device in the EFI System Table. # -# Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.
+# Copyright (c) 2018, Microsoft Corporation +# +# Copyright (c) 2007 - 2019, Intel Corporation. All rights reserved.
# # SPDX-License-Identifier: BSD-2-Clause-Patent # @@ -17,8 +19,9 @@ FILE_GUID = b57a1df6-ffdb-4247-a3df-3a562176751a MODULE_TYPE = UEFI_DRIVER VERSION_STRING = 1.0 - LIBRARY_CLASS = DebugLib|DXE_CORE DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION UEFI_DRIVER + LIBRARY_CLASS = DebugLib|DXE_CORE DXE_DRIVER DXE_RUNTIME_DRIVER UEFI_APPLICATION UEFI_DRIVER + CONSTRUCTOR = DxeDebugLibConstructor # # VALID_ARCHITECTURES = IA32 X64 EBC @@ -26,6 +29,7 @@ [Sources] DebugLib.c + DebugLibConstructor.c [Packages] @@ -37,9 +41,11 @@ BaseLib PcdLib PrintLib - UefiBootServicesTableLib DebugPrintErrorLevelLib +[Guids] + gEfiEventExitBootServicesGuid ## CONSUMES + [Pcd] gEfiMdePkgTokenSpaceGuid.PcdDebugClearMemoryValue ## SOMETIMES_CONSUMES gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask ## CONSUMES -- 2.39.2