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]] -=-=-=-=-=-=-=-=-=-=-=-
