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"));