mbox series

[00/17] x86/boot: Rework PE header generation

Message ID 20230818134422.380032-1-ardb@kernel.org
Headers show
Series x86/boot: Rework PE header generation | expand

Message

Ard Biesheuvel Aug. 18, 2023, 1:44 p.m. UTC
Now that the EFI stub boot flow no longer relies on memory that is
executable and writable at the same time, we can reorganize the PE/COFF
view of the kernel image and expose the decompressor binary's code and
r/o data as a .text section and data/bss as a .data section, using 4k
alignment and limited permissions.

Doing so is necessary for compatibility with hardening measures that are
being rolled out on x86 PCs built to run Windows (i.e., the majority of
them). The EFI boot environment that the Linux EFI stub executes in is
especially sensitive to safety issues, given that a vulnerability in the
loader of one OS can be abused to attack another.

In true x86 fashion, this is more complicated than on other
architectures, which have implemented this code/data split with 4k
alignment from the beginning. The complicating factor here is that the
boot image consists of two different parts, which are stitched together
and fixed up using a special build tool.

The first three patches simplify the x86 EFI stub code so it does not
even bother reading the setup header from the image - passing arguments
this way is not supported by EFI boot anyway.

Then, the bzImage is simplified and reorganized, primarily by:
- dropping the ancient 'bugger off' message occupying much of the header
  space
- using a fixed size of 16k for the setup block
- setting header values from asm instead of via the build tool

Finally, the payload is split into .text and .data, and the section and
file alignment increased to 4k/512 respectively.

The only remaining task performed by the build tool is generating the
CRC-32 that is fundamentally broken in practice and never used, so that
is dropped entirely at the end.

This supersedes the work proposed by Evgeniy last year, which did a
major rewrite of the build tool in order to clean it up, before updating
it to generate the new 4k aligned image layout. As this series proves,
the build tool is mostly unnecessary, and we have too many of those
already.

Cc: Evgeniy Baskov <baskov@ispras.ru>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Dave Hansen <dave.hansen@linux.intel.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Peter Jones <pjones@redhat.com>
Cc: Matthew Garrett <mjg59@srcf.ucam.org>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Cc: Kees Cook <keescook@chromium.org>
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: Marvin Häuser <mhaeuser@posteo.de>

Ard Biesheuvel (17):
  x86/efi: Drop EFI stub .bss from .data section
  x86/efi: Disregard setup header of loaded image
  x86/efi: Drop alignment flags from PE section headers
  x86/boot: Remove the 'bugger off' message
  x86/boot: Omit compression buffer from PE/COFF image memory footprint
  x86/boot: Drop redundant code setting the root device
  x86/boot: Grab kernel_info offset from zoffset header directly
  x86/boot: Drop references to startup_64
  x86/boot: Set EFI handover offset directly in header asm
  x86/boot: Drop workaround for binutils 2.14 in linker script ASSERTs
  x86/boot: Use fixed size of 16k for setup block
  x86/boot: Derive file size from _edata symbol
  x86/boot: Construct PE/COFF .text section from assembler
  x86/boot: Drop PE/COFF .reloc section
  x86/boot: Split off PE/COFF .data section
  x86/boot: Increase section and file alignment to 4k/512
  x86/boot: Drop CRC-32 checksum and the build tool that generates it

 Documentation/arch/x86/boot.rst         |  10 -
 arch/x86/boot/Makefile                  |  12 +-
 arch/x86/boot/compressed/vmlinux.lds.S  |   5 +-
 arch/x86/boot/header.S                  | 217 ++++-----
 arch/x86/boot/setup.ld                  |  21 +-
 arch/x86/boot/tools/.gitignore          |   2 -
 arch/x86/boot/tools/build.c             | 502 --------------------
 drivers/firmware/efi/libstub/Makefile   |   7 -
 drivers/firmware/efi/libstub/x86-stub.c |  46 +-
 9 files changed, 113 insertions(+), 709 deletions(-)
 delete mode 100644 arch/x86/boot/tools/.gitignore
 delete mode 100644 arch/x86/boot/tools/build.c

Comments

H. Peter Anvin Aug. 20, 2023, 1:02 a.m. UTC | #1
On 8/18/23 06:44, Ard Biesheuvel wrote:
> Ancient (pre-2003) x86 kernels could boot from a floppy disk straight from
> the BIOS, using a small real mode boot stub at the start of the image
> where the BIOS would expect the boot record (or boot block) to appear.
> 
> Due to its limitations (kernel size < 1 MiB, no support for IDE, USB or
> El Torito floppy emulation), this support was dropped, and a Linux aware
> bootloader is now always required to boot the kernel from a legacy BIOS.
> 
> To smoothen this transition, the boot stub was not removed entirely, but
> replaced with one that just prints an error message telling the user to
> install a bootloader.
> 
> As it is unlikely that anyone doing direct floppy boot with such an
> ancient kernel is going to upgrade to v6.5+ and expect that this boot
> method still works, printing this message is kind of pointless, and so
> it should be possible to remove the logic that emits it.
> 
> Let's free up this space so it can be used to expand the PE header in a
> subsequent patch.
> 
> Signed-off-by: Ard Biesheuvel <ardb@kernel.org
>

Good riddance.

Acked-by: H. Peter Anvin (Intel) <hpa@zytor.com>
Ard Biesheuvel Aug. 20, 2023, 12:57 p.m. UTC | #2
On Sun, 20 Aug 2023 at 03:03, H. Peter Anvin <hpa@zytor.com> wrote:
>
>
>
> On 8/18/23 06:44, Ard Biesheuvel wrote:
> > The only remaining task carried out by the boot/tools/build.c build tool
> > is generating the CRC-32 checksum of the bzImage. This feature was added
> > in commit
> >
> >    7d6e737c8d2698b6 ("x86: add a crc32 checksum to the kernel image.")
> >
> > without any motivation (or any commit log text, for that matter). This
> > checksum is not verified by any known bootloader, and given that
> >
> > a) the checksum of the entire bzImage is reported by most tools (zlib,
> >     rhash) as 0xffffffff and not 0x0 as documented,
> > b) the checksum is corrupted when the image is signed for secure boot,
> >     which means that no distro ships x86 images with valid CRCs,
> >
> > it seems quite unlikely that this checksum is being used, so let's just
> > drop it, along with the tool that generates it.
> >
>
> This one I have concerns with.
>

I understand. I deliberately put this change at the very end because I
was anticipating some debate on this.

Do you have any recollection of why this CRC32 was introduced in the
first place? The commit logs are empty and the lore thread doesn't
contain any justification either.
H. Peter Anvin Aug. 21, 2023, 12:37 a.m. UTC | #3
On 8/20/23 05:57, Ard Biesheuvel wrote:
> 
> I understand. I deliberately put this change at the very end because I
> was anticipating some debate on this.
> 
> Do you have any recollection of why this CRC32 was introduced in the
> first place? The commit logs are empty and the lore thread doesn't
> contain any justification either.
 >

The justification is that firmware is notoriously unreliable and gives 
the boot loader an independent way to verify the load and have a 
fallback, rather than jumping to the kernel and having the decompressor 
fail.

At this time it is impossible to know what might rely on it. The EFI 
signing issue aside, there are a ton of Linux bootloaders for non-EFI 
systems using the BIOS or raw kernel entry points - and there is no 
telling what those environments might do.

	-hpa
Ard Biesheuvel Aug. 21, 2023, 7:04 a.m. UTC | #4
On Mon, 21 Aug 2023 at 02:37, H. Peter Anvin <hpa@zytor.com> wrote:
>
> On 8/20/23 05:57, Ard Biesheuvel wrote:
> >
> > I understand. I deliberately put this change at the very end because I
> > was anticipating some debate on this.
> >
> > Do you have any recollection of why this CRC32 was introduced in the
> > first place? The commit logs are empty and the lore thread doesn't
> > contain any justification either.
>  >
>
> The justification is that firmware is notoriously unreliable and gives
> the boot loader an independent way to verify the load and have a
> fallback, rather than jumping to the kernel and having the decompressor
> fail.
>
> At this time it is impossible to know what might rely on it. The EFI
> signing issue aside, there are a ton of Linux bootloaders for non-EFI
> systems using the BIOS or raw kernel entry points - and there is no
> telling what those environments might do.
>

Fair enough.

The PE header happens to have a checksum field that a) is not used by
EFI at all, and b) is not covered by the signature. So it wouldn't be
too hard to put a doctored value in that field that forces the CRC-32
of the entire image to 0xffff_ffff *after* signing, and this would
even work if the image did not have a CRC-32 at the end in the first
place. (So the signing tools wouldn't need to know whether they are
signing a x86 bzImage or some other PE executable). Note that pesign
and sbsign currently follow the PE/windows spec for generating this
checksum, but EFI never looks at it. (It is documented as being
intended for checksumming critical system DLLs on Windows)

But that is a lot of trouble for no known use case, so let's not
bother with that right now. But I'll withdraw this patch from the
series.

Thanks,
Ard.