From 0d39b369ff35c44d7340a27b0f12a5454ca10b3b Mon Sep 17 00:00:00 2001 From: Colin Watson Date: Tue, 29 Jan 2013 06:12:13 +0000 Subject: [PATCH] Automatically call linuxefi from linux if secure boot is enabled and the kernel is signed, to hand over to the kernel without calling ExitBootServices. Otherwise, linux will fall through to previous code, call ExitBootServices itself, and boot the kernel normally. --- debian/changelog | 4 + debian/patches/linuxefi_non_sb_fallback.patch | 87 +++++++++++++++++++ debian/patches/series | 1 + grub-core/loader/i386/efi/linux.c | 2 +- grub-core/loader/i386/linux.c | 43 +++++++++ 5 files changed, 136 insertions(+), 1 deletion(-) create mode 100644 debian/patches/linuxefi_non_sb_fallback.patch diff --git a/debian/changelog b/debian/changelog index ebb49879b..94c623721 100644 --- a/debian/changelog +++ b/debian/changelog @@ -15,6 +15,10 @@ grub2 (2.00-13) UNRELEASED; urgency=low with EFI handover patches, avoiding ExitBootServices. - Temporarily make linuxefi refuse to validate kernels in the absence of a shim, until we get some other details worked out. + - Automatically call linuxefi from linux if secure boot is enabled and + the kernel is signed, to hand over to the kernel without calling + ExitBootServices. Otherwise, linux will fall through to previous + code, call ExitBootServices itself, and boot the kernel normally. -- Colin Watson Mon, 28 Jan 2013 11:08:07 +0000 diff --git a/debian/patches/linuxefi_non_sb_fallback.patch b/debian/patches/linuxefi_non_sb_fallback.patch new file mode 100644 index 000000000..e743ef776 --- /dev/null +++ b/debian/patches/linuxefi_non_sb_fallback.patch @@ -0,0 +1,87 @@ +Description: If running under UEFI secure boot, attempt to use linuxefi loader +Author: Colin Watson +Author: Steve Langasek +Forwarded: no +Last-Update: 2012-10-05 + +Index: b/grub-core/loader/i386/efi/linux.c +=================================================================== +--- a/grub-core/loader/i386/efi/linux.c ++++ b/grub-core/loader/i386/efi/linux.c +@@ -234,7 +234,7 @@ + + if (! grub_linuxefi_secure_validate (kernel, filelen)) + { +- grub_error (GRUB_ERR_INVALID_COMMAND, N_("%s has invalid signature"), argv[0]); ++ grub_error (GRUB_ERR_ACCESS_DENIED, N_("%s has invalid signature"), argv[0]); + grub_free (kernel); + goto fail; + } +Index: b/grub-core/loader/i386/linux.c +=================================================================== +--- a/grub-core/loader/i386/linux.c ++++ b/grub-core/loader/i386/linux.c +@@ -75,6 +75,8 @@ + static struct linux_kernel_params linux_params; + static char *linux_cmdline; + #ifdef GRUB_MACHINE_EFI ++static int using_linuxefi; ++static grub_command_t initrdefi_cmd; + static grub_efi_uintn_t efi_mmap_size; + #else + static const grub_size_t efi_mmap_size = 0; +@@ -684,6 +686,41 @@ + + grub_dl_ref (my_mod); + ++#ifdef GRUB_MACHINE_EFI ++ using_linuxefi = 0; ++ if (grub_efi_secure_boot ()) ++ { ++ /* Try linuxefi first, which will require a successful signature check ++ and then hand over to the kernel without calling ExitBootServices. ++ If that fails, however, fall back to calling ExitBootServices ++ ourselves and then booting an unsigned kernel. */ ++ grub_dl_t mod; ++ grub_command_t linuxefi_cmd; ++ ++ grub_dprintf ("linux", "Secure Boot enabled: trying linuxefi\n"); ++ ++ mod = grub_dl_load ("linuxefi"); ++ if (mod) ++ { ++ grub_dl_ref (mod); ++ linuxefi_cmd = grub_command_find ("linuxefi"); ++ initrdefi_cmd = grub_command_find ("initrdefi"); ++ if (linuxefi_cmd && initrdefi_cmd) ++ { ++ (linuxefi_cmd->func) (linuxefi_cmd, argc, argv); ++ if (grub_errno == GRUB_ERR_NONE) ++ { ++ grub_dprintf ("linux", "Handing off to linuxefi\n"); ++ using_linuxefi = 1; ++ return GRUB_ERR_NONE; ++ } ++ grub_dprintf ("linux", "linuxefi failed (%d)\n", grub_errno); ++ grub_errno = GRUB_ERR_NONE; ++ } ++ } ++ } ++#endif ++ + if (argc == 0) + { + grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); +@@ -1050,6 +1087,12 @@ + int nfiles = 0; + grub_uint8_t *ptr; + ++#ifdef GRUB_MACHINE_EFI ++ /* If we're using linuxefi, just forward to initrdefi. */ ++ if (using_linuxefi && initrdefi_cmd) ++ return (initrdefi_cmd->func) (initrdefi_cmd, argc, argv); ++#endif ++ + if (argc == 0) + { + grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); diff --git a/debian/patches/series b/debian/patches/series index 928253e72..2741bea82 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -40,3 +40,4 @@ linuxefi.patch linuxefi_amd64_only.patch linuxefi_debug.patch linuxefi_require_shim.patch +linuxefi_non_sb_fallback.patch diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c index 26a958c43..eb4ba9608 100644 --- a/grub-core/loader/i386/efi/linux.c +++ b/grub-core/loader/i386/efi/linux.c @@ -234,7 +234,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), if (! grub_linuxefi_secure_validate (kernel, filelen)) { - grub_error (GRUB_ERR_INVALID_COMMAND, N_("%s has invalid signature"), argv[0]); + grub_error (GRUB_ERR_ACCESS_DENIED, N_("%s has invalid signature"), argv[0]); grub_free (kernel); goto fail; } diff --git a/grub-core/loader/i386/linux.c b/grub-core/loader/i386/linux.c index bee01a632..7228e7e6b 100644 --- a/grub-core/loader/i386/linux.c +++ b/grub-core/loader/i386/linux.c @@ -75,6 +75,8 @@ static grub_size_t maximal_cmdline_size; static struct linux_kernel_params linux_params; static char *linux_cmdline; #ifdef GRUB_MACHINE_EFI +static int using_linuxefi; +static grub_command_t initrdefi_cmd; static grub_efi_uintn_t efi_mmap_size; #else static const grub_size_t efi_mmap_size = 0; @@ -684,6 +686,41 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), grub_dl_ref (my_mod); +#ifdef GRUB_MACHINE_EFI + using_linuxefi = 0; + if (grub_efi_secure_boot ()) + { + /* Try linuxefi first, which will require a successful signature check + and then hand over to the kernel without calling ExitBootServices. + If that fails, however, fall back to calling ExitBootServices + ourselves and then booting an unsigned kernel. */ + grub_dl_t mod; + grub_command_t linuxefi_cmd; + + grub_dprintf ("linux", "Secure Boot enabled: trying linuxefi\n"); + + mod = grub_dl_load ("linuxefi"); + if (mod) + { + grub_dl_ref (mod); + linuxefi_cmd = grub_command_find ("linuxefi"); + initrdefi_cmd = grub_command_find ("initrdefi"); + if (linuxefi_cmd && initrdefi_cmd) + { + (linuxefi_cmd->func) (linuxefi_cmd, argc, argv); + if (grub_errno == GRUB_ERR_NONE) + { + grub_dprintf ("linux", "Handing off to linuxefi\n"); + using_linuxefi = 1; + return GRUB_ERR_NONE; + } + grub_dprintf ("linux", "linuxefi failed (%d)\n", grub_errno); + grub_errno = GRUB_ERR_NONE; + } + } + } +#endif + if (argc == 0) { grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); @@ -1050,6 +1087,12 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), int nfiles = 0; grub_uint8_t *ptr; +#ifdef GRUB_MACHINE_EFI + /* If we're using linuxefi, just forward to initrdefi. */ + if (using_linuxefi && initrdefi_cmd) + return (initrdefi_cmd->func) (initrdefi_cmd, argc, argv); +#endif + if (argc == 0) { grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));