From 4f8bf8c570dadf8044e7f3f260c55e3e22630998 Mon Sep 17 00:00:00 2001 From: Gary Ching-Pang Lin Date: Tue, 3 Mar 2015 16:53:11 +0800 Subject: [PATCH] Uninstall shim protocols at Exit() Shim uninstalls its own protocol at the end of the program. However, if the loaded binary, e.g. grub2, calls Exit(), the uninstall function would never be called, i.e. the shim protocol handle existed even if shim was gone. This already caused crashes on the dell machines with the following steps: 1. boot to grub2 and press 'C' for the grub2 shell 2. type "exit" to quit the shell 3. boot to grub2 again and boot an OS While grub2 uses the shim protocol to verify the OS image, it may get the old dead shim handle and crash the system. This commit adds uninstall_shim_protocols() to the hooked exit function and always hook Exit to clean up the protocol handle. Signed-off-by: Gary Ching-Pang Lin --- replacements.c | 35 ++++++++++++++++++++++++++++------- replacements.h | 1 + shim.c | 5 ++++- 3 files changed, 33 insertions(+), 8 deletions(-) diff --git a/replacements.c b/replacements.c index f7623d9..4d96e57 100644 --- a/replacements.c +++ b/replacements.c @@ -74,6 +74,10 @@ unhook_system_services(void) return; systab->BootServices->Exit = system_exit; + + if (hook_exit_only) + return; + systab->BootServices->LoadImage = system_load_image; systab->BootServices->StartImage = system_start_image; systab->BootServices->ExitBootServices = system_exit_boot_services; @@ -167,10 +171,24 @@ do_exit(EFI_HANDLE ImageHandle, EFI_STATUS ExitStatus, { EFI_STATUS status; unhook_system_services(); + uninstall_shim_protocols(); status = systab->BootServices->Exit(ImageHandle, ExitStatus, ExitDataSize, ExitData); - if (EFI_ERROR(status)) + if (EFI_ERROR(status)) { + EFI_STATUS status2 = install_shim_protocols(); + + if (EFI_ERROR(status2)) { + Print(L"Something has gone seriously wrong: %r\n", + status2); + Print(L"shim cannot continue, sorry.\n"); + systab->BootServices->Stall(5000000); + systab->RuntimeServices->ResetSystem( + EfiResetShutdown, + EFI_SECURITY_VIOLATION, 0, NULL); + } + hook_system_services(systab); + } return status; } @@ -182,6 +200,15 @@ hook_system_services(EFI_SYSTEM_TABLE *local_systab) /* We need to hook various calls to make this work... */ + /* we need to hook Exit() so that we can allow users to quit the + * bootloader and still e.g. start a new one or run an internal + * shell. */ + system_exit = systab->BootServices->Exit; + systab->BootServices->Exit = do_exit; + + if (hook_exit_only) + return; + /* We need LoadImage() hooked so that fallback.c can load shim * without having to fake LoadImage as well. This allows it * to call the system LoadImage(), and have us track the output @@ -201,10 +228,4 @@ hook_system_services(EFI_SYSTEM_TABLE *local_systab) * and b) we can unwrap when we're done. */ system_exit_boot_services = systab->BootServices->ExitBootServices; systab->BootServices->ExitBootServices = exit_boot_services; - - /* we need to hook Exit() so that we can allow users to quit the - * bootloader and still e.g. start a new one or run an internal - * shell. */ - system_exit = systab->BootServices->Exit; - systab->BootServices->Exit = do_exit; } diff --git a/replacements.h b/replacements.h index bd09424..928144d 100644 --- a/replacements.h +++ b/replacements.h @@ -37,6 +37,7 @@ typedef enum { extern verification_method_t verification_method; extern int loader_is_participating; +extern int hook_exit_only; extern void hook_system_services(EFI_SYSTEM_TABLE *local_systab); extern void unhook_system_services(void); diff --git a/shim.c b/shim.c index d46494a..6fbe427 100644 --- a/shim.c +++ b/shim.c @@ -90,6 +90,7 @@ UINT8 *vendor_dbx; */ verification_method_t verification_method; int loader_is_participating; +int exit_only; #define EFI_IMAGE_SECURITY_DATABASE_GUID { 0xd719b2cb, 0x3d3a, 0x4596, { 0xa3, 0xbc, 0xda, 0xd0, 0x0e, 0x67, 0x65, 0x6f }} @@ -2100,6 +2101,7 @@ EFI_STATUS efi_main (EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *passed_systab) /* * Tell the user that we're in insecure mode if necessary */ + hook_exit_only = 1; if (user_insecure_mode) { Print(L"Booting in insecure mode\n"); uefi_call_wrapper(BS->Stall, 1, 2000000); @@ -2110,11 +2112,12 @@ EFI_STATUS efi_main (EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *passed_systab) * that anything it boots has performed some * validation of the next image. */ - hook_system_services(systab); + hook_exit_only = 0; loader_is_participating = 0; } } + hook_system_services(systab); efi_status = install_shim_protocols(); if (EFI_ERROR(efi_status)) return efi_status; -- 2.1.4