mbox series

[0/2] arch-agnostic initrd loading method for EFI systems

Message ID 20200206140352.6300-1-ardb@kernel.org (mailing list archive)
Headers show
Series arch-agnostic initrd loading method for EFI systems | expand

Message

Ard Biesheuvel Feb. 6, 2020, 2:03 p.m. UTC
This series introduces an arch agnostic way of loading the initrd into
memory from the EFI stub. This addresses a number of shortcomings that
affect the current implementations that exist across architectures:

- The initrd=<file> command line option can only load files that reside
  on the same file system that the kernel itself was loaded from, which
  requires the bootloader or firmware to expose that file system via the
  appropriate EFI protocol, which is not always feasible. From the kernel
  side, this protocol is problematic since it is incompatible with mixed
  mode on x86 (this is due to the fact that some of its methods have
  prototypes that are difficult to marshall)

- The approach that is ordinarily taken by GRUB is to load the initrd into
  memory, and pass it to the kernel proper via the bootparams structure or
  via the device tree. This requires the boot loader to have an understanding
  of those structures, which are not always set in stone, and of the policies
  around where the initrd may be loaded into memory. In the ARM case, it
  requires GRUB to modify the hardware description provided by the firmware,
  given that the initrd base and offset in memory are passed via the same
  data structure. It also creates a time window where the initrd data sits
  in memory, and can potentially be corrupted before the kernel is booted.

Considering that we will soon have new users of these interfaces (EFI for
kvmtool on ARM, RISC-V in u-boot, etc), it makes sense to add a generic
interface now, before having another wave of bespoke arch specific code
coming in.

Another aspect to take into account is that support for UEFI secure boot
and measured boot is being taken into the upstream, and being able to
rely on the PE entry point for booting any architecture makes the GRUB
vs shim story much cleaner, as we should be able to rely on LoadImage
and StartImage on all architectures, while retaining the ability to
load initrds from anywhere.

Note that these patches depend on a fair amount of cleanup work that I
am targetting for v5.7. Branch can be found at:
https://git.kernel.org/pub/scm/linux/kernel/git/ardb/linux.git/log/?h=efistub-unification2

An implementation for ArmVirtQemu (OVMF for ARM aka AAVMF) can be found
at https://github.com/ardbiesheuvel/edk2/commits/linux-efi-generic.
The change is for ARM only, but the exact same code could be used on x86.

Cc: lersek@redhat.com
Cc: leif@nuviainc.com
Cc: pjones@redhat.com
Cc: mjg59@google.com
Cc: agraf@csgraf.de
Cc: ilias.apalodimas@linaro.org
Cc: xypron.glpk@gmx.de 
Cc: daniel.kiper@oracle.com

Ard Biesheuvel (2):
  efi/libstub: add support for loading the initrd from a device path
  efi/libstub: take noinitrd cmdline argument into account for devpath
    initrd

 drivers/firmware/efi/libstub/arm-stub.c       | 21 ++++--
 .../firmware/efi/libstub/efi-stub-helper.c    | 74 +++++++++++++++++++
 drivers/firmware/efi/libstub/efistub.h        | 13 ++++
 drivers/firmware/efi/libstub/x86-stub.c       | 51 ++++++++++---
 include/linux/efi.h                           |  1 +
 5 files changed, 146 insertions(+), 14 deletions(-)

Comments

Laszlo Ersek Feb. 7, 2020, 9:09 a.m. UTC | #1
On 02/06/20 15:03, Ard Biesheuvel wrote:
> This series introduces an arch agnostic way of loading the initrd into
> memory from the EFI stub. This addresses a number of shortcomings that
> affect the current implementations that exist across architectures:
> 
> - The initrd=<file> command line option can only load files that reside
>   on the same file system that the kernel itself was loaded from, which
>   requires the bootloader or firmware to expose that file system via the
>   appropriate EFI protocol, which is not always feasible. From the kernel
>   side, this protocol is problematic since it is incompatible with mixed
>   mode on x86 (this is due to the fact that some of its methods have
>   prototypes that are difficult to marshall)
> 
> - The approach that is ordinarily taken by GRUB is to load the initrd into
>   memory, and pass it to the kernel proper via the bootparams structure or
>   via the device tree. This requires the boot loader to have an understanding
>   of those structures, which are not always set in stone, and of the policies
>   around where the initrd may be loaded into memory. In the ARM case, it
>   requires GRUB to modify the hardware description provided by the firmware,
>   given that the initrd base and offset in memory are passed via the same
>   data structure. It also creates a time window where the initrd data sits
>   in memory, and can potentially be corrupted before the kernel is booted.
> 
> Considering that we will soon have new users of these interfaces (EFI for
> kvmtool on ARM, RISC-V in u-boot, etc), it makes sense to add a generic
> interface now, before having another wave of bespoke arch specific code
> coming in.
> 
> Another aspect to take into account is that support for UEFI secure boot
> and measured boot is being taken into the upstream, and being able to
> rely on the PE entry point for booting any architecture makes the GRUB
> vs shim story much cleaner, as we should be able to rely on LoadImage
> and StartImage on all architectures, while retaining the ability to
> load initrds from anywhere.
> 
> Note that these patches depend on a fair amount of cleanup work that I
> am targetting for v5.7. Branch can be found at:
> https://git.kernel.org/pub/scm/linux/kernel/git/ardb/linux.git/log/?h=efistub-unification2
> 
> An implementation for ArmVirtQemu (OVMF for ARM aka AAVMF) can be found
> at https://github.com/ardbiesheuvel/edk2/commits/linux-efi-generic.
> The change is for ARM only, but the exact same code could be used on x86.

I like this ArmVirtQemu feature, but I think it should be implemented as
an addition, rather than a replacement. Older kernels (older EFI stubs)
will try to fetch the initrd from the same fs where grub loaded the
kernel from (exactly as you describe in the blurb).

For example, virt-install's "--location" option "can recognize certain
distribution trees and fetches a bootable kernel/initrd pair to launch
the install". It would be nice to keep that working for older distros.

I think LoadFile[2] can co-exist with SimpleFs.

I also think that the "try SimpleFs first, fall back to LoadFile[2]
second" requirement applies only to the UEFI boot manager, and not to
the kernel's EFI stub. IOW in the new approach the kernel is free to
ignore (abandon) the old approach for good.

Thanks
Laszlo

> 
> Cc: lersek@redhat.com
> Cc: leif@nuviainc.com
> Cc: pjones@redhat.com
> Cc: mjg59@google.com
> Cc: agraf@csgraf.de
> Cc: ilias.apalodimas@linaro.org
> Cc: xypron.glpk@gmx.de 
> Cc: daniel.kiper@oracle.com
> 
> Ard Biesheuvel (2):
>   efi/libstub: add support for loading the initrd from a device path
>   efi/libstub: take noinitrd cmdline argument into account for devpath
>     initrd
> 
>  drivers/firmware/efi/libstub/arm-stub.c       | 21 ++++--
>  .../firmware/efi/libstub/efi-stub-helper.c    | 74 +++++++++++++++++++
>  drivers/firmware/efi/libstub/efistub.h        | 13 ++++
>  drivers/firmware/efi/libstub/x86-stub.c       | 51 ++++++++++---
>  include/linux/efi.h                           |  1 +
>  5 files changed, 146 insertions(+), 14 deletions(-)
>
Laszlo Ersek Feb. 7, 2020, 9:22 a.m. UTC | #2
On 02/07/20 10:09, Laszlo Ersek wrote:
> On 02/06/20 15:03, Ard Biesheuvel wrote:
>> This series introduces an arch agnostic way of loading the initrd into
>> memory from the EFI stub. This addresses a number of shortcomings that
>> affect the current implementations that exist across architectures:
>>
>> - The initrd=<file> command line option can only load files that reside
>>   on the same file system that the kernel itself was loaded from, which
>>   requires the bootloader or firmware to expose that file system via the
>>   appropriate EFI protocol, which is not always feasible. From the kernel
>>   side, this protocol is problematic since it is incompatible with mixed
>>   mode on x86 (this is due to the fact that some of its methods have
>>   prototypes that are difficult to marshall)
>>
>> - The approach that is ordinarily taken by GRUB is to load the initrd into
>>   memory, and pass it to the kernel proper via the bootparams structure or
>>   via the device tree. This requires the boot loader to have an understanding
>>   of those structures, which are not always set in stone, and of the policies
>>   around where the initrd may be loaded into memory. In the ARM case, it
>>   requires GRUB to modify the hardware description provided by the firmware,
>>   given that the initrd base and offset in memory are passed via the same
>>   data structure. It also creates a time window where the initrd data sits
>>   in memory, and can potentially be corrupted before the kernel is booted.
>>
>> Considering that we will soon have new users of these interfaces (EFI for
>> kvmtool on ARM, RISC-V in u-boot, etc), it makes sense to add a generic
>> interface now, before having another wave of bespoke arch specific code
>> coming in.
>>
>> Another aspect to take into account is that support for UEFI secure boot
>> and measured boot is being taken into the upstream, and being able to
>> rely on the PE entry point for booting any architecture makes the GRUB
>> vs shim story much cleaner, as we should be able to rely on LoadImage
>> and StartImage on all architectures, while retaining the ability to
>> load initrds from anywhere.
>>
>> Note that these patches depend on a fair amount of cleanup work that I
>> am targetting for v5.7. Branch can be found at:
>> https://git.kernel.org/pub/scm/linux/kernel/git/ardb/linux.git/log/?h=efistub-unification2
>>
>> An implementation for ArmVirtQemu (OVMF for ARM aka AAVMF) can be found
>> at https://github.com/ardbiesheuvel/edk2/commits/linux-efi-generic.
>> The change is for ARM only, but the exact same code could be used on x86.
> 
> I like this ArmVirtQemu feature, but I think it should be implemented as
> an addition, rather than a replacement. Older kernels (older EFI stubs)
> will try to fetch the initrd from the same fs where grub loaded the
> kernel from (exactly as you describe in the blurb).
> 
> For example, virt-install's "--location" option "can recognize certain
> distribution trees and fetches a bootable kernel/initrd pair to launch
> the install". It would be nice to keep that working for older distros.
> 
> I think LoadFile[2] can co-exist with SimpleFs.
> 
> I also think that the "try SimpleFs first, fall back to LoadFile[2]
> second" requirement applies only to the UEFI boot manager, and not to
> the kernel's EFI stub. IOW in the new approach the kernel is free to
> ignore (abandon) the old approach for good.

... But that might not be good for compatibility with grub and/or the
platform firmware, from the kernel's own perspective, perhaps?...

Who is supposed to produce LoadFile2 with the new VenMedia devpath?

Thanks
Laszlo

>>
>> Cc: lersek@redhat.com
>> Cc: leif@nuviainc.com
>> Cc: pjones@redhat.com
>> Cc: mjg59@google.com
>> Cc: agraf@csgraf.de
>> Cc: ilias.apalodimas@linaro.org
>> Cc: xypron.glpk@gmx.de 
>> Cc: daniel.kiper@oracle.com
>>
>> Ard Biesheuvel (2):
>>   efi/libstub: add support for loading the initrd from a device path
>>   efi/libstub: take noinitrd cmdline argument into account for devpath
>>     initrd
>>
>>  drivers/firmware/efi/libstub/arm-stub.c       | 21 ++++--
>>  .../firmware/efi/libstub/efi-stub-helper.c    | 74 +++++++++++++++++++
>>  drivers/firmware/efi/libstub/efistub.h        | 13 ++++
>>  drivers/firmware/efi/libstub/x86-stub.c       | 51 ++++++++++---
>>  include/linux/efi.h                           |  1 +
>>  5 files changed, 146 insertions(+), 14 deletions(-)
>>
>
Ard Biesheuvel Feb. 7, 2020, 12:23 p.m. UTC | #3
On Fri, 7 Feb 2020 at 09:22, Laszlo Ersek <lersek@redhat.com> wrote:
>
> On 02/07/20 10:09, Laszlo Ersek wrote:
> > On 02/06/20 15:03, Ard Biesheuvel wrote:
> >> This series introduces an arch agnostic way of loading the initrd into
> >> memory from the EFI stub. This addresses a number of shortcomings that
> >> affect the current implementations that exist across architectures:
> >>
> >> - The initrd=<file> command line option can only load files that reside
> >>   on the same file system that the kernel itself was loaded from, which
> >>   requires the bootloader or firmware to expose that file system via the
> >>   appropriate EFI protocol, which is not always feasible. From the kernel
> >>   side, this protocol is problematic since it is incompatible with mixed
> >>   mode on x86 (this is due to the fact that some of its methods have
> >>   prototypes that are difficult to marshall)
> >>
> >> - The approach that is ordinarily taken by GRUB is to load the initrd into
> >>   memory, and pass it to the kernel proper via the bootparams structure or
> >>   via the device tree. This requires the boot loader to have an understanding
> >>   of those structures, which are not always set in stone, and of the policies
> >>   around where the initrd may be loaded into memory. In the ARM case, it
> >>   requires GRUB to modify the hardware description provided by the firmware,
> >>   given that the initrd base and offset in memory are passed via the same
> >>   data structure. It also creates a time window where the initrd data sits
> >>   in memory, and can potentially be corrupted before the kernel is booted.
> >>
> >> Considering that we will soon have new users of these interfaces (EFI for
> >> kvmtool on ARM, RISC-V in u-boot, etc), it makes sense to add a generic
> >> interface now, before having another wave of bespoke arch specific code
> >> coming in.
> >>
> >> Another aspect to take into account is that support for UEFI secure boot
> >> and measured boot is being taken into the upstream, and being able to
> >> rely on the PE entry point for booting any architecture makes the GRUB
> >> vs shim story much cleaner, as we should be able to rely on LoadImage
> >> and StartImage on all architectures, while retaining the ability to
> >> load initrds from anywhere.
> >>
> >> Note that these patches depend on a fair amount of cleanup work that I
> >> am targetting for v5.7. Branch can be found at:
> >> https://git.kernel.org/pub/scm/linux/kernel/git/ardb/linux.git/log/?h=efistub-unification2
> >>
> >> An implementation for ArmVirtQemu (OVMF for ARM aka AAVMF) can be found
> >> at https://github.com/ardbiesheuvel/edk2/commits/linux-efi-generic.
> >> The change is for ARM only, but the exact same code could be used on x86.
> >
> > I like this ArmVirtQemu feature, but I think it should be implemented as
> > an addition, rather than a replacement. Older kernels (older EFI stubs)
> > will try to fetch the initrd from the same fs where grub loaded the
> > kernel from (exactly as you describe in the blurb).
> >

Agreed. The ArmVirtQemu change is not intended for merging, but
primarily as a test rig for the kernel changes.

> > For example, virt-install's "--location" option "can recognize certain
> > distribution trees and fetches a bootable kernel/initrd pair to launch
> > the install". It would be nice to keep that working for older distros.
> >
> > I think LoadFile[2] can co-exist with SimpleFs.
> >
> > I also think that the "try SimpleFs first, fall back to LoadFile[2]
> > second" requirement applies only to the UEFI boot manager, and not to
> > the kernel's EFI stub. IOW in the new approach the kernel is free to
> > ignore (abandon) the old approach for good.
>
> ... But that might not be good for compatibility with grub and/or the
> platform firmware, from the kernel's own perspective, perhaps?...
>
> Who is supposed to produce LoadFile2 with the new VenMedia devpath?
>

What I am ultimately after is a generic GRUB that uses
LoadImage+Startimage for starting the kernel on all architectures, and
is able to load the initrd from anywhere in an arch agnostic manner.

Additionally, we might have
- an implementation for OVMF/AAVMF,
- a EDK2 UEFI Shell command that takes a shell file path to provide
the Linux initrd
- a uboot implementation that passes the initrd this way.

This series is the first step, to align between all the stakeholders
on the approach for this aspect, before taking it any further.
James Bottomley Feb. 7, 2020, 4:20 p.m. UTC | #4
On Fri, 2020-02-07 at 12:23 +0000, Ard Biesheuvel wrote:
> On Fri, 7 Feb 2020 at 09:22, Laszlo Ersek <lersek@redhat.com> wrote:
> > 
> > On 02/07/20 10:09, Laszlo Ersek wrote:
[...]
> > > For example, virt-install's "--location" option "can recognize
> > > certain distribution trees and fetches a bootable kernel/initrd
> > > pair to launch the install". It would be nice to keep that
> > > working for older distros.
> > > 
> > > I think LoadFile[2] can co-exist with SimpleFs.
> > > 
> > > I also think that the "try SimpleFs first, fall back to
> > > LoadFile[2] second" requirement applies only to the UEFI boot
> > > manager, and not to the kernel's EFI stub. IOW in the new
> > > approach the kernel is free to ignore (abandon) the old approach
> > > for good.
> > 
> > ... But that might not be good for compatibility with grub and/or
> > the platform firmware, from the kernel's own perspective,
> > perhaps?...
> > 
> > Who is supposed to produce LoadFile2 with the new VenMedia devpath?
> > 
> 
> What I am ultimately after is a generic GRUB that uses
> LoadImage+Startimage for starting the kernel on all architectures, 

For most boots, we need to pivot to the MoK.  A long time ago, I
proposed updating the platform security policy to do an override to
allow MoK to become the security verifier (actually principally so I
could get the gummiboot bootloader to work with the MoK method):

https://git.kernel.org/pub/scm/linux/kernel/git/jejb/efitools.git/tree/lib/security_policy.c

And I believe all the pivot bootloaders now do this, but the fear was
always this looks a bit like hackery that might not work in some UEFI
implementations.  Since we don't really rely on it (shim link loads
after signature verification) we don't know whether the assumption does
break or not.  We'll need to get much more comfortable with the
security override before we can let grub do a simple load+start.

> and is able to load the initrd from anywhere in an arch agnostic
> manner.

I think the use case might not really be grub, it's gummiboot, or
systemd-boot as its now called:

https://wiki.archlinux.org/index.php/systemd-boot

The standard way of using grub and EFI is to put grub on the EFI
parition but have the kernel and the initrd on the root parition (which
won't be EFI readable).  This means we can keep the EFI partition small
and only needing modification when grub is updated, meaning it doesn't
even need mounting at all usually.

Don't get me wrong, I like the gummiboot way of doing the
LoadImage+StartImage: it's small and clean and doesn't need the shim
protocol, but people like the sophistication grub provides including
its ability to read kernel filesystems, so they're unlikely to change
that.

James
Ard Biesheuvel Feb. 7, 2020, 6:31 p.m. UTC | #5
On Fri, 7 Feb 2020 at 16:20, James Bottomley
<James.Bottomley@hansenpartnership.com> wrote:
>
> On Fri, 2020-02-07 at 12:23 +0000, Ard Biesheuvel wrote:
> > On Fri, 7 Feb 2020 at 09:22, Laszlo Ersek <lersek@redhat.com> wrote:
> > >
> > > On 02/07/20 10:09, Laszlo Ersek wrote:
> [...]
> > > > For example, virt-install's "--location" option "can recognize
> > > > certain distribution trees and fetches a bootable kernel/initrd
> > > > pair to launch the install". It would be nice to keep that
> > > > working for older distros.
> > > >
> > > > I think LoadFile[2] can co-exist with SimpleFs.
> > > >
> > > > I also think that the "try SimpleFs first, fall back to
> > > > LoadFile[2] second" requirement applies only to the UEFI boot
> > > > manager, and not to the kernel's EFI stub. IOW in the new
> > > > approach the kernel is free to ignore (abandon) the old approach
> > > > for good.
> > >
> > > ... But that might not be good for compatibility with grub and/or
> > > the platform firmware, from the kernel's own perspective,
> > > perhaps?...
> > >
> > > Who is supposed to produce LoadFile2 with the new VenMedia devpath?
> > >
> >
> > What I am ultimately after is a generic GRUB that uses
> > LoadImage+Startimage for starting the kernel on all architectures,
>
> For most boots, we need to pivot to the MoK.  A long time ago, I
> proposed updating the platform security policy to do an override to
> allow MoK to become the security verifier (actually principally so I
> could get the gummiboot bootloader to work with the MoK method):
>
> https://git.kernel.org/pub/scm/linux/kernel/git/jejb/efitools.git/tree/lib/security_policy.c
>
> And I believe all the pivot bootloaders now do this, but the fear was
> always this looks a bit like hackery that might not work in some UEFI
> implementations.  Since we don't really rely on it (shim link loads
> after signature verification) we don't know whether the assumption does
> break or not.  We'll need to get much more comfortable with the
> security override before we can let grub do a simple load+start.
>

I'd like to do something much simpler: let shim override LoadImage and
StartImage, and in their implementations, fall back to the firmware
ones if necessary.

> > and is able to load the initrd from anywhere in an arch agnostic
> > manner.
>
> I think the use case might not really be grub, it's gummiboot, or
> systemd-boot as its now called:
>

No it is definitely GRUB. GRUB today needs to attach to the shim
protocol, perform the authentication, measure the payload etc etc,
which means it knows far too much about the internals of shim or the
fact that it even exists.

My ideal bootflow would be where the OS installer looks at the
firmware's db/dbx, doesn't bother to install shim if the OS vendor's
cert is there, and uses the exact same GRUB regardless of whether shim
is part of the bootflow or not.

One of the things impeding this is the fact that we cannot load the
initrd from anywhere when using loadimage+startimage.

> https://wiki.archlinux.org/index.php/systemd-boot
>
> The standard way of using grub and EFI is to put grub on the EFI
> parition but have the kernel and the initrd on the root parition (which
> won't be EFI readable).  This means we can keep the EFI partition small
> and only needing modification when grub is updated, meaning it doesn't
> even need mounting at all usually.
>
> Don't get me wrong, I like the gummiboot way of doing the
> LoadImage+StartImage: it's small and clean and doesn't need the shim
> protocol, but people like the sophistication grub provides including
> its ability to read kernel filesystems, so they're unlikely to change
> that.
>
Arvind Sankar Feb. 7, 2020, 6:45 p.m. UTC | #6
On Thu, Feb 06, 2020 at 02:03:50PM +0000, Ard Biesheuvel wrote:
>   data structure. It also creates a time window where the initrd data sits
>   in memory, and can potentially be corrupted before the kernel is booted.
> 

I don't quite understand the time window aspect -- can you expand on
that? It seems like the same time window exists between when the kernel
is loaded and when it actually runs, no? Why is this more important for
initrd?
Ard Biesheuvel Feb. 7, 2020, 7:47 p.m. UTC | #7
On Fri, 7 Feb 2020 at 18:45, Arvind Sankar <nivedita@alum.mit.edu> wrote:
>
> On Thu, Feb 06, 2020 at 02:03:50PM +0000, Ard Biesheuvel wrote:
> >   data structure. It also creates a time window where the initrd data sits
> >   in memory, and can potentially be corrupted before the kernel is booted.
> >
>
> I don't quite understand the time window aspect -- can you expand on
> that? It seems like the same time window exists between when the kernel
> is loaded and when it actually runs, no? Why is this more important for
> initrd?

When using loadimage+startimage, the authentication and measurement of
the kernel image occur during the call to loadimage(), even if the
source of the load is memory itself, and startimage() is typically
called right after.

The assumption is that it may help to make this time as short as
possible for the initrd as well.
James Bottomley Feb. 7, 2020, 7:54 p.m. UTC | #8
On Fri, 2020-02-07 at 18:31 +0000, Ard Biesheuvel wrote:
> On Fri, 7 Feb 2020 at 16:20, James Bottomley
> <James.Bottomley@hansenpartnership.com> wrote:
> > 
> > On Fri, 2020-02-07 at 12:23 +0000, Ard Biesheuvel wrote:
> > > On Fri, 7 Feb 2020 at 09:22, Laszlo Ersek <lersek@redhat.com>
> > > wrote:
> > > > 
> > > > On 02/07/20 10:09, Laszlo Ersek wrote:
> > 
> > [...]
> > > > > For example, virt-install's "--location" option "can
> > > > > recognize certain distribution trees and fetches a bootable
> > > > > kernel/initrd pair to launch the install". It would be nice
> > > > > to keep that working for older distros.
> > > > > 
> > > > > I think LoadFile[2] can co-exist with SimpleFs.
> > > > > 
> > > > > I also think that the "try SimpleFs first, fall back to
> > > > > LoadFile[2] second" requirement applies only to the UEFI boot
> > > > > manager, and not to the kernel's EFI stub. IOW in the new
> > > > > approach the kernel is free to ignore (abandon) the old
> > > > > approach for good.
> > > > 
> > > > ... But that might not be good for compatibility with grub
> > > > and/or the platform firmware, from the kernel's own
> > > > perspective, perhaps?...
> > > > 
> > > > Who is supposed to produce LoadFile2 with the new VenMedia
> > > > devpath?
> > > > 
> > > 
> > > What I am ultimately after is a generic GRUB that uses
> > > LoadImage+Startimage for starting the kernel on all
> > > architectures,
> > 
> > For most boots, we need to pivot to the MoK.  A long time ago, I
> > proposed updating the platform security policy to do an override to
> > allow MoK to become the security verifier (actually principally so
> > I could get the gummiboot bootloader to work with the MoK method):
> > 
> > https://git.kernel.org/pub/scm/linux/kernel/git/jejb/efitools.git/t
> > ree/lib/security_policy.c
> > 
> > And I believe all the pivot bootloaders now do this, but the fear
> > was always this looks a bit like hackery that might not work in
> > some UEFI implementations.  Since we don't really rely on it (shim
> > link loads after signature verification) we don't know whether the
> > assumption does break or not.  We'll need to get much more
> > comfortable with the security override before we can let grub do a
> > simple load+start.
> > 
> 
> I'd like to do something much simpler: let shim override LoadImage
> and StartImage,

Actually, the non-shim bootloaders really don't want to do that: the
whole point of being able to use LoadImage is that you don't need to
know how to load a PECOFF binary or check its signature.  Overriding
the security protocol allows updating the signature check, but if you
look at the current efitools implementation it uses the pkcs7 protocol
to avoid having to include crypto code.

I've got the pecoff code they'd need in my uefi library:

https://git.kernel.org/pub/scm/linux/kernel/git/jejb/efitools.git/tree/lib/pecoff.c

But it's a lot of code for things that pride themselves on being tiny.

>  and in their implementations, fall back to the firmware
> ones if necessary.
> 
> > > and is able to load the initrd from anywhere in an arch agnostic
> > > manner.
> > 
> > I think the use case might not really be grub, it's gummiboot, or
> > systemd-boot as its now called:
> > 
> 
> No it is definitely GRUB. GRUB today needs to attach to the shim
> protocol, perform the authentication, measure the payload etc etc,
> which means it knows far too much about the internals of shim or the
> fact that it even exists.

The shim protocol and shim are fairly separate.  I agree it means grub
has to load and know the two entry points for context and verify but
they're very far removed for the inner workings of shim.  Obviously, my
non-shim loader has to supply them for grub, so this is the
implementation:

https://git.kernel.org/pub/scm/linux/kernel/git/jejb/efitools.git/tree/lib/shim_protocol.c

It's only 50 lines.

The other thing to consider is that crypto code is huge.  Shim
currently includes it (although it could avoid this by using the pkcs7
verifier protocol trick I use ... I should push that harder) and it
adds about 1M of static code.  Grub does not have this code, so either
grub uses shim and its code to do the signature verification or grub
will have to include the additional 1M as well ... I think using shim
via the protocol is preferable.

> My ideal bootflow would be where the OS installer looks at the
> firmware's db/dbx, doesn't bother to install shim if the OS vendor's
> cert is there, and uses the exact same GRUB regardless of whether
> shim is part of the bootflow or not.

That's not enough.  The whole point of MoK is that the user may have
done their own key addition, so you could be in the situation where the
vendor cert is present in db but the user has a MoK override for boot
and if you assume presence of the vendor cert means you can use
loadimage, this will fail because the MoK cert isn't in db ... unless
you've added the MoK key via the security protocol override.

> One of the things impeding this is the fact that we cannot load the
> initrd from anywhere when using loadimage+startimage.

unless initrd becomes a PECOFF binary, it can never be loaded by
loadimage ... I thought you were still letting the kernel load it via
LoadFile2?  (assuming you are and that the above is just a typo).

James
Ard Biesheuvel Feb. 7, 2020, 8:03 p.m. UTC | #9
On Fri, 7 Feb 2020 at 19:54, James Bottomley
<James.Bottomley@hansenpartnership.com> wrote:
>
> On Fri, 2020-02-07 at 18:31 +0000, Ard Biesheuvel wrote:
> > On Fri, 7 Feb 2020 at 16:20, James Bottomley
> > <James.Bottomley@hansenpartnership.com> wrote:
> > >
> > > On Fri, 2020-02-07 at 12:23 +0000, Ard Biesheuvel wrote:
> > > > On Fri, 7 Feb 2020 at 09:22, Laszlo Ersek <lersek@redhat.com>
> > > > wrote:
> > > > >
> > > > > On 02/07/20 10:09, Laszlo Ersek wrote:
> > >
> > > [...]
> > > > > > For example, virt-install's "--location" option "can
> > > > > > recognize certain distribution trees and fetches a bootable
> > > > > > kernel/initrd pair to launch the install". It would be nice
> > > > > > to keep that working for older distros.
> > > > > >
> > > > > > I think LoadFile[2] can co-exist with SimpleFs.
> > > > > >
> > > > > > I also think that the "try SimpleFs first, fall back to
> > > > > > LoadFile[2] second" requirement applies only to the UEFI boot
> > > > > > manager, and not to the kernel's EFI stub. IOW in the new
> > > > > > approach the kernel is free to ignore (abandon) the old
> > > > > > approach for good.
> > > > >
> > > > > ... But that might not be good for compatibility with grub
> > > > > and/or the platform firmware, from the kernel's own
> > > > > perspective, perhaps?...
> > > > >
> > > > > Who is supposed to produce LoadFile2 with the new VenMedia
> > > > > devpath?
> > > > >
> > > >
> > > > What I am ultimately after is a generic GRUB that uses
> > > > LoadImage+Startimage for starting the kernel on all
> > > > architectures,
> > >
> > > For most boots, we need to pivot to the MoK.  A long time ago, I
> > > proposed updating the platform security policy to do an override to
> > > allow MoK to become the security verifier (actually principally so
> > > I could get the gummiboot bootloader to work with the MoK method):
> > >
> > > https://git.kernel.org/pub/scm/linux/kernel/git/jejb/efitools.git/t
> > > ree/lib/security_policy.c
> > >
> > > And I believe all the pivot bootloaders now do this, but the fear
> > > was always this looks a bit like hackery that might not work in
> > > some UEFI implementations.  Since we don't really rely on it (shim
> > > link loads after signature verification) we don't know whether the
> > > assumption does break or not.  We'll need to get much more
> > > comfortable with the security override before we can let grub do a
> > > simple load+start.
> > >
> >
> > I'd like to do something much simpler: let shim override LoadImage
> > and StartImage,
>
> Actually, the non-shim bootloaders really don't want to do that: the
> whole point of being able to use LoadImage is that you don't need to
> know how to load a PECOFF binary or check its signature.  Overriding
> the security protocol allows updating the signature check, but if you
> look at the current efitools implementation it uses the pkcs7 protocol
> to avoid having to include crypto code.
>
> I've got the pecoff code they'd need in my uefi library:
>
> https://git.kernel.org/pub/scm/linux/kernel/git/jejb/efitools.git/tree/lib/pecoff.c
>
> But it's a lot of code for things that pride themselves on being tiny.
>

I think you are missing the point. GRUB will only use
loadimage+startimage, no matter what is backing it (the firmware or
shim). The same applies to gummiboot or even the uefi shell if you
wanted to. So all loaders use LoadImage/StartImage as usual, but shim
inserts itself into the call chain if it was loaded first.


> >  and in their implementations, fall back to the firmware
> > ones if necessary.
> >
> > > > and is able to load the initrd from anywhere in an arch agnostic
> > > > manner.
> > >
> > > I think the use case might not really be grub, it's gummiboot, or
> > > systemd-boot as its now called:
> > >
> >
> > No it is definitely GRUB. GRUB today needs to attach to the shim
> > protocol, perform the authentication, measure the payload etc etc,
> > which means it knows far too much about the internals of shim or the
> > fact that it even exists.
>
> The shim protocol and shim are fairly separate.  I agree it means grub
> has to load and know the two entry points for context and verify but
> they're very far removed for the inner workings of shim.  Obviously, my
> non-shim loader has to supply them for grub, so this is the
> implementation:
>
> https://git.kernel.org/pub/scm/linux/kernel/git/jejb/efitools.git/tree/lib/shim_protocol.c
>
> It's only 50 lines.
>
> The other thing to consider is that crypto code is huge.  Shim
> currently includes it (although it could avoid this by using the pkcs7
> verifier protocol trick I use ... I should push that harder) and it
> adds about 1M of static code.  Grub does not have this code, so either
> grub uses shim and its code to do the signature verification or grub
> will have to include the additional 1M as well ... I think using shim
> via the protocol is preferable.
>

No. GRUB will call loadimage+startimage, and will end up hitting the
implementation exposed by shim.

> > My ideal bootflow would be where the OS installer looks at the
> > firmware's db/dbx, doesn't bother to install shim if the OS vendor's
> > cert is there, and uses the exact same GRUB regardless of whether
> > shim is part of the bootflow or not.
>
> That's not enough.  The whole point of MoK is that the user may have
> done their own key addition, so you could be in the situation where the
> vendor cert is present in db but the user has a MoK override for boot
> and if you assume presence of the vendor cert means you can use
> loadimage, this will fail because the MoK cert isn't in db ... unless
> you've added the MoK key via the security protocol override.
>

No. The LoadImage you are hitting is shim's loadimage not the
firmware's loadimage in this case.

> > One of the things impeding this is the fact that we cannot load the
> > initrd from anywhere when using loadimage+startimage.
>
> unless initrd becomes a PECOFF binary, it can never be loaded by
> loadimage ... I thought you were still letting the kernel load it via
> LoadFile2?  (assuming you are and that the above is just a typo).
>

No it is not a typo.

If you load the kernel vis LoadImage, you need to use initrd= to load
the initrd, which required that file to be hosted on a file system
that EFI understands. The alternative is to load the initrd into
memory, store the address and size into a bootparams structure or DT,
and invoke the kernel via some other entry point that allows you to
carry this metadata.

I want to get rid of the latter, which means I need a way to load the
initrd that is not limited to loading from the same [EFI supported]
file system as the kernel. *That* is what this series is about.
Arvind Sankar Feb. 7, 2020, 8:26 p.m. UTC | #10
On Fri, Feb 07, 2020 at 07:47:46PM +0000, Ard Biesheuvel wrote:
> On Fri, 7 Feb 2020 at 18:45, Arvind Sankar <nivedita@alum.mit.edu> wrote:
> >
> > On Thu, Feb 06, 2020 at 02:03:50PM +0000, Ard Biesheuvel wrote:
> > >   data structure. It also creates a time window where the initrd data sits
> > >   in memory, and can potentially be corrupted before the kernel is booted.
> > >
> >
> > I don't quite understand the time window aspect -- can you expand on
> > that? It seems like the same time window exists between when the kernel
> > is loaded and when it actually runs, no? Why is this more important for
> > initrd?
> 
> When using loadimage+startimage, the authentication and measurement of
> the kernel image occur during the call to loadimage(), even if the
> source of the load is memory itself, and startimage() is typically
> called right after.
> 
> The assumption is that it may help to make this time as short as
> possible for the initrd as well.

Ok, this is for when we can use LoadImage, that makes sense.