DxeBaseSerialPortLibHobConstructor() creates an
EVT_SIGNAL_EXIT_BOOT_SERVICES event so that SerialPortWrite() can stop
touching the UART once the OS owns the hardware. The library comes in
through the DebugLib -> SerialPortLib chain of every DXE driver, so
every driver registers such an event during
ProcessLibraryConstructorList().

Drivers whose entry point returns an error leave that event behind:
_ModuleEntryPoint() runs ProcessLibraryDestructorList() and the DXE
core unloads the image, but this library declares no destructor, so the
ExitBootServices event stays registered with a NotifyFunction pointing
into the freed image. When the OS loader eventually calls
ExitBootServices, the DXE core dispatches the stale event and branches
into whatever now occupies that address.

On the AArch64 chainloaded payload this crashes: GraphicsOutputDxe
fails its entry point (no framebuffer HOB), leaks the event, and
DiskIoDxe is loaded into the freed pages at a slightly higher base. The
stale NotifyFunction then targets DiskIoDxe's PE header page, which
image protection has marked non-executable, and the resulting
instruction abort takes the system down right after "EFI stub: Exiting
boot services...".

Store the event handle in a module-scope variable and add a matching
destructor that closes it. That way an unloaded driver no longer leaves
a dangling ExitBootServices callback behind.

Cc: Benjamin Doron <[email protected]>
Cc: Gua Guo <[email protected]>
Cc: Guo Dong <[email protected]>
Cc: James Lu <[email protected]>
Cc: Sean Rhodes <[email protected]>
Cc: Shuo Liu <[email protected]>
Assisted-by: claude-opus-5
Signed-off-by: Alexander Graf <[email protected]>
---
 .../DxeBaseSerialPortLibHob.c                 | 41 +++++++++++++++++--
 .../DxeBaseSerialPortLibHob.inf               |  1 +
 2 files changed, 39 insertions(+), 3 deletions(-)

diff --git 
a/UefiPayloadPkg/Library/BaseSerialPortLibHob/DxeBaseSerialPortLibHob.c 
b/UefiPayloadPkg/Library/BaseSerialPortLibHob/DxeBaseSerialPortLibHob.c
index 6106e9a933..07811ea267 100644
--- a/UefiPayloadPkg/Library/BaseSerialPortLibHob/DxeBaseSerialPortLibHob.c
+++ b/UefiPayloadPkg/Library/BaseSerialPortLibHob/DxeBaseSerialPortLibHob.c
@@ -9,6 +9,8 @@
 

 extern BOOLEAN  mBaseSerialPortLibHobAtRuntime;

 

+STATIC EFI_EVENT  mBaseSerialPortLibHobExitBootServicesEvent;

+

 /**

   Set mSerialIoUartLibAtRuntime flag as TRUE after ExitBootServices.

 

@@ -44,13 +46,46 @@ DxeBaseSerialPortLibHobConstructor (
   IN EFI_SYSTEM_TABLE  *SystemTable

   )

 {

-  EFI_EVENT  SerialPortLibHobExitBootServicesEvent;

-

   return SystemTable->BootServices->CreateEvent (

                                       EVT_SIGNAL_EXIT_BOOT_SERVICES,

                                       TPL_NOTIFY,

                                       
BaseSerialPortLibHobExitBootServicesEvent,

                                       NULL,

-                                      &SerialPortLibHobExitBootServicesEvent

+                                      
&mBaseSerialPortLibHobExitBootServicesEvent

                                       );

 }

+

+/**

+  The destructor closes the ExitBootServices event.

+

+  A driver that fails its entry point is unloaded again by the DXE core, but

+  this library has already registered its ExitBootServices callback by then.

+  Close the event in the destructor so that a stale notification function

+  pointing into the unloaded image is not left behind.

+

+  @param[in]  ImageHandle   The firmware allocated handle for the EFI image.

+  @param[in]  SystemTable   A pointer to the EFI System Table.

+

+  @retval EFI_SUCCESS   No event was registered, or it was closed.

+  @retval other         CloseEvent () failed.

+**/

+EFI_STATUS

+EFIAPI

+DxeBaseSerialPortLibHobDestructor (

+  IN EFI_HANDLE        ImageHandle,

+  IN EFI_SYSTEM_TABLE  *SystemTable

+  )

+{

+  EFI_STATUS  Status;

+

+  if (mBaseSerialPortLibHobExitBootServicesEvent == NULL) {

+    return EFI_SUCCESS;

+  }

+

+  Status = SystemTable->BootServices->CloseEvent 
(mBaseSerialPortLibHobExitBootServicesEvent);

+  if (!EFI_ERROR (Status)) {

+    mBaseSerialPortLibHobExitBootServicesEvent = NULL;

+  }

+

+  return Status;

+}

diff --git 
a/UefiPayloadPkg/Library/BaseSerialPortLibHob/DxeBaseSerialPortLibHob.inf 
b/UefiPayloadPkg/Library/BaseSerialPortLibHob/DxeBaseSerialPortLibHob.inf
index d79fc5aa70..c0a153462a 100644
--- a/UefiPayloadPkg/Library/BaseSerialPortLibHob/DxeBaseSerialPortLibHob.inf
+++ b/UefiPayloadPkg/Library/BaseSerialPortLibHob/DxeBaseSerialPortLibHob.inf
@@ -14,6 +14,7 @@
   VERSION_STRING                 = 1.0

   LIBRARY_CLASS                  = SerialPortLib|DXE_CORE DXE_DRIVER 
DXE_RUNTIME_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION UEFI_DRIVER

   CONSTRUCTOR                    = DxeBaseSerialPortLibHobConstructor

+  DESTRUCTOR                     = DxeBaseSerialPortLibHobDestructor

 [Packages]

   MdePkg/MdePkg.dec

   MdeModulePkg/MdeModulePkg.dec

-- 
2.47.3



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#122086): https://edk2.groups.io/g/devel/message/122086
Mute This Topic: https://groups.io/mt/120797197/21656
Group Owner: [email protected]
Unsubscribe: https://edk2.groups.io/g/devel/unsub [[email protected]]
-=-=-=-=-=-=-=-=-=-=-=-


Reply via email to