Skip to content

Commit

Permalink
x86/efi: Make the deprecated EFI handover protocol optional
Browse files Browse the repository at this point in the history
The EFI handover protocol permits a bootloader to invoke the kernel as a
EFI PE/COFF application, while passing a bootparams struct as a third
argument to the entrypoint function call.

This has no basis in the UEFI specification, and there are better ways
to pass additional data to a UEFI application (UEFI configuration
tables, UEFI variables, UEFI protocols) than going around the
StartImage() boot service and jumping to a fixed offset in the loaded
image, just to call a different function that takes a third parameter.

The reason for handling struct bootparams in the bootloader was that the
EFI stub could only load initrd images from the EFI system partition,
and so passing it via struct bootparams was needed for loaders like
GRUB, which pass the initrd in memory, and may load it from anywhere,
including from the network. Another motivation was EFI mixed mode, which
could not use the initrd loader in the EFI stub at all due to 32/64 bit
incompatibilities (which will be fixed shortly [0]), and could not
invoke the ordinary PE/COFF entry point either, for the same reasons.

Given that loaders such as GRUB already carried the bootparams handling
in order to implement non-EFI boot, retaining that code and just passing
bootparams to the EFI stub was a reasonable choice (although defining an
alternate entrypoint could have been avoided.) However, the GRUB side
changes never made it upstream, and are only shipped by some of the
distros in their downstream versions.

In the meantime, EFI support has been added to other Linux architecture
ports, as well as to U-boot and systemd, including arch-agnostic methods
for passing initrd images in memory [1], and for doing mixed mode boot
[2], none of them requiring anything like the EFI handover protocol. So
given that only out-of-tree distro GRUB relies on this, let's permit it
to be omitted from the build, in preparation for retiring it completely
at a later date. (Note that systemd-boot does have an implementation as
well, but only uses it as a fallback for booting images that do not
implement the LoadFile2 based initrd loading method, i.e., v5.8 or older)

[0] https://lore.kernel.org/all/20220927085842.2860715-1-ardb@kernel.org/
[1] ec93fc3 ("efi/libstub: Add support for loading the initrd from a device path")
[2] 97aa276 ("efi/x86: Add true mixed mode entry point into .compat section")

Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Signed-off-by: Borislav Petkov <bp@suse.de>
Link: https://lore.kernel.org/r/20221122161017.2426828-18-ardb@kernel.org
  • Loading branch information
ardbiesheuvel authored and Borislav Petkov committed Nov 24, 2022
1 parent 61de13d commit cc3fdda
Show file tree
Hide file tree
Showing 4 changed files with 23 additions and 2 deletions.
17 changes: 17 additions & 0 deletions arch/x86/Kconfig
Expand Up @@ -1980,6 +1980,23 @@ config EFI_STUB

See Documentation/admin-guide/efi-stub.rst for more information.

config EFI_HANDOVER_PROTOCOL
bool "EFI handover protocol (DEPRECATED)"
depends on EFI_STUB
default y
help
Select this in order to include support for the deprecated EFI
handover protocol, which defines alternative entry points into the
EFI stub. This is a practice that has no basis in the UEFI
specification, and requires a priori knowledge on the part of the
bootloader about Linux/x86 specific ways of passing the command line
and initrd, and where in memory those assets may be loaded.

If in doubt, say Y. Even though the corresponding support is not
present in upstream GRUB or other bootloaders, most distros build
GRUB with numerous downstream patches applied, and may rely on the
handover protocol as as result.

config EFI_MIXED
bool "EFI mixed-mode support"
depends on EFI_STUB && X86_64
Expand Down
4 changes: 3 additions & 1 deletion arch/x86/boot/compressed/head_64.S
Expand Up @@ -286,7 +286,7 @@ SYM_FUNC_START(startup_32)
lret
SYM_FUNC_END(startup_32)

#ifdef CONFIG_EFI_MIXED
#if IS_ENABLED(CONFIG_EFI_MIXED) && IS_ENABLED(CONFIG_EFI_HANDOVER_PROTOCOL)
.org 0x190
SYM_FUNC_START(efi32_stub_entry)
add $0x4, %esp /* Discard return address */
Expand Down Expand Up @@ -516,7 +516,9 @@ trampoline_return:
SYM_CODE_END(startup_64)

#ifdef CONFIG_EFI_STUB
#ifdef CONFIG_EFI_HANDOVER_PROTOCOL
.org 0x390
#endif
SYM_FUNC_START(efi64_stub_entry)
and $~0xf, %rsp /* realign the stack */
movq %rdx, %rbx /* save boot_params pointer */
Expand Down
2 changes: 1 addition & 1 deletion arch/x86/boot/header.S
Expand Up @@ -406,7 +406,7 @@ xloadflags:
# define XLF1 0
#endif

#ifdef CONFIG_EFI_STUB
#ifdef CONFIG_EFI_HANDOVER_PROTOCOL
# ifdef CONFIG_EFI_MIXED
# define XLF23 (XLF_EFI_HANDOVER_32|XLF_EFI_HANDOVER_64)
# else
Expand Down
2 changes: 2 additions & 0 deletions arch/x86/boot/tools/build.c
Expand Up @@ -290,6 +290,7 @@ static void efi_stub_entry_update(void)
{
unsigned long addr = efi32_stub_entry;

#ifdef CONFIG_EFI_HANDOVER_PROTOCOL
#ifdef CONFIG_X86_64
/* Yes, this is really how we defined it :( */
addr = efi64_stub_entry - 0x200;
Expand All @@ -298,6 +299,7 @@ static void efi_stub_entry_update(void)
#ifdef CONFIG_EFI_MIXED
if (efi32_stub_entry != addr)
die("32-bit and 64-bit EFI entry points do not match\n");
#endif
#endif
put_unaligned_le32(addr, &buf[0x264]);
}
Expand Down

0 comments on commit cc3fdda

Please sign in to comment.