From e6995a5e2478b5c89893c5fc9631a7472411e1dc Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Tue, 15 Aug 2023 14:37:36 +0800 Subject: [PATCH] uefi-services: Return event in init As mentioned in https://github.com/rust-osdev/uefi-rs/issues/917 If the app built with uefi-services exits before ExitBootServices, UEFI will call `UnloadImage` on it. Then the callback function is not in memory anymore and when ExitBootServices runs, invalid memory is accessed. QEMU will crash like this when the Linux EFISTUB calls ExitBootServices: ``` !!!! X64 Exception Type - 06(#UD - Invalid Opcode) CPU Apic ID - 00000000 !!!! RIP - 000000003E13F018, CS - 0000000000000038, RFLAGS - 0000000000210246 RAX - 0000000000000000, RCX - 000000003E191E98, RDX - 0000000000000000 RBX - 0000000000000004, RSP - 000000003FF0FD08, RBP - 000000003FF28740 RSI - 000000003E167518, RDI - 000000003FF6A5E0 R8 - 000000003FF27140, R9 - 000000003F4807A0, R10 - 0000000000000001 R11 - 00000000000000E1, R12 - 000000003E191EE0, R13 - 0000000000000100 R14 - 000000003FF28840, R15 - 000000003E191E98 DS - 0000000000000030, ES - 0000000000000030, FS - 0000000000000030 GS - 0000000000000030, SS - 0000000000000030 CR0 - 0000000080010033, CR2 - 0000000000000000, CR3 - 000000003FC01000 CR4 - 0000000000000668, CR8 - 0000000000000000 DR0 - 0000000000000000, DR1 - 0000000000000000, DR2 - 0000000000000000 DR3 - 0000000000000000, DR6 - 00000000FFFF0FF0, DR7 - 0000000000000400 GDTR - 000000003F9DE000 0000000000000047, LDTR - 0000000000000000 IDTR - 000000003F471018 0000000000000FFF, TR - 0000000000000000 FXSAVE_STATE - 000000003FF0F960 !!!! Find image based on IP(0x3E13F018) (No PDB) (ImageBase=000000003DF1E000, EntryPoint=000000003DF1F000) !!!! ``` To avoid the crash, the user should close the event before the app exits. ```rs fn main(image_handle: Handle, mut system_table: SystemTable) -> Status { let event: Option = uefi_services::init(&mut system_table).unwrap(); let boot_services = system_table.boot_services(); println!("Hello World"); if let Some(event) = event { // Will creash when Linux boots if we don't call this boot_services.close_event(event).unwrap(); } Status::SUCCESS } ``` It would be nice to have this happen automatically by a Drop implementation but this already lets users do it on their own, if they need. Signed-off-by: Daniel Schaefer --- uefi-services/src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/uefi-services/src/lib.rs b/uefi-services/src/lib.rs index 0b715b181..ef6009f43 100644 --- a/uefi-services/src/lib.rs +++ b/uefi-services/src/lib.rs @@ -78,11 +78,11 @@ pub fn system_table() -> NonNull> { /// /// This must be called as early as possible, /// before trying to use logging or memory allocation capabilities. -pub fn init(st: &mut SystemTable) -> Result { +pub fn init(st: &mut SystemTable) -> Result> { unsafe { // Avoid double initialization. if SYSTEM_TABLE.is_some() { - return Status::SUCCESS.to_result(); + return Status::SUCCESS.to_result_with_val(|| None); } // Setup the system table singleton @@ -104,7 +104,7 @@ pub fn init(st: &mut SystemTable) -> Result { Some(exit_boot_services), None, ) - .map(|_| ()) + .map(Some) } }