Re: Grub menu with 3 kernels by default

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Thu, Oct 06, 2022 at 10:45:40AM -0400, Robbie Harwood wrote:
> Daniel P. Berrangé <berrange@xxxxxxxxxx> writes:
> 
> > The way grub has to write its entire grub.conf into the TPM PCRs is
> > totally impractical for anyone wishing to maintain attestation
> > policies to verify the OS boot state from the TPM eventlog.
> 
> So this has been mentioned in several places, but no one in grub
> development has actually seen this problem articulated out, which makes
> me worry that it's spreading FUD.  Could you write up a bug report or
> something concrete?

I've not filed a bug report, as to I tended to view it as an inherant
result of the goals of grub to be a flexible &configurable boot
environment. Let me try to explain in more detail here though...


Right now the default way more or less any Linux distro does SecureBoot
is not too useful, since only the kernel is signed by the vendor. The
content of both the initrd and cmdline is local to the installation.
Mostly I'd say it solves the problem of enabling a Linux distro to boot
in an environment where SecureBoot is active.  It doesn't solve the
problem of enabling the booted OS to be verified, or at least not in a
manner that is practical to use for unknowledable users.

Despite this we still have functionality that can tie LUKS volume key
unlock to the state of a specific set of TPM PCRs, such disks are
unlocked if-and-only-if the OS is launched in the expected configuration.
This is only secure, if everything that can influence the configuration
is covered by the PCRs we're using for unlock policy. 

We need PCRs to cover at minimum

  1. Machine firmware
  2. Bootloader(s)
  3. Bootloader configuration
  4. Booted kernel
  5. Booted initrd
  6. Booted cmdline

Item 1 is OK-ish. It won't change unless you upgrade your firmware,
so is relatively stable, though fwupd has made this more dynamic
than in the past.

Items 2 & 4 are OK because Microsoft signs shim, and the OS vendor
signs grub and their kernels. So we can rely on the fact that if
SecureBoot is signalled enabled by the relevant PCR, the bootloaders(s)
& kernel are trusted (within scope of the SecureBoot keys that are
enrolled).

Item 5 and 6 are a problem, because as mentioned thse are not signed
by the OS vendor with their secureboot key. The PCRs reflect their
contents, but the expected PCR digests will change any time the
initrd/cmdline are updated, meaning the LUKS keys needs to be
re-sealed. One practical approach to this problem is to use 
prebuilt unified kernel images, such that the OS vendor's secureboot
signature covers the kernel,initrd and cmdline. Verification now
merely involves checking the PCR for SecureBOot state. The flipside
is that we loose flexibility that exists today with per-host
generated initrd/cmdline. This may matter for some scenarios (bare
metal) but not for others (most VMs).



Item 3 is a problem. Grub is highly configurable, via grub.conf, and
its contents are tuned for each install. We need to validate any
parts of grub.conf that applied to the current boot state. On a fairly
typical VM the PCR eventlog recording the bootloader configuration
contains something that looks similarish to:

      (hd0,gpt15)/EFI/ubuntu/grub.cfg
      grub_cmd: search.fs_uuid c73d8355-1ac9-41b4-8edf-c1c1a9d5bd6a root
      grub_cmd: set prefix=(hd0,gpt1)/boot/grub
      (hd0,gpt1)/boot/grub/x86_64-efi/command.lst
      (hd0,gpt1)/boot/grub/x86_64-efi/fs.lst
      (hd0,gpt1)/boot/grub/x86_64-efi/crypto.lst
      (hd0,gpt1)/boot/grub/x86_64-efi/terminal.lst
      grub_cmd: configfile (hd0,gpt1)/boot/grub/grub.cfg
      (hd0,gpt1)/boot/grub/grub.cfg
      grub_cmd: [ -s (hd0,gpt1)/boot/grub/grubenv ]
      (hd0,gpt1)/boot/grub/grubenv
      grub_cmd: set have_grubenv=true
      grub_cmd: load_env
      (hd0,gpt1)/boot/grub/grubenv
      grub_cmd: [  = 2 ]
      grub_cmd: [  = 1 ]
      grub_cmd: [  ]
      grub_cmd: set default=0
      grub_cmd: [ xy = xy ]
      grub_cmd: menuentry_id_option=--id
      grub_cmd: export menuentry_id_option
      grub_cmd: [  ]
      grub_cmd: terminal_input console
      grub_cmd: terminal_output console
      grub_cmd: [  = 1 ]
      grub_cmd: [ xy = xy ]
      grub_cmd: set timeout_style=hidden
      grub_cmd: set timeout=0.1
      grub_cmd: [ -n true ]
      grub_cmd: [ -n  ]
      grub_cmd: set initrdless_boot_fallback_triggered=0
      grub_cmd: save_env initrdless_boot_fallback_triggered
      grub_cmd: set menu_color_normal=white/black
      grub_cmd: set menu_color_highlight=black/light-gray
      grub_cmd: set partuuid=bf817bdf-6a3a-4221-8edb-2c1ca7c5537f
      grub_cmd: [  != 1 ]
      grub_cmd: [ -e (hd0,gpt1)/boot/grub/gfxblacklist.txt ]
      grub_cmd: hwmatch (hd0,gpt1)/boot/grub/gfxblacklist.txt 3
      grub_cmd: [ = 0 ]
      grub_cmd: set linux_gfx_mode=keep
      grub_cmd: export linux_gfx_mode
      grub_cmd: menuentry Ubuntu --class ubuntu --class gnu-linux --class gnu --class os --id gnulinux-simple-c73d8355-1ac9-41b4-8edf-c1c1a9d5bd6a {
      	if [ x$grub_platform = xxen ]; then insmod xzio; insmod lzopio; fi
      grub_cmd: submenu Advanced options for Ubuntu --id gnulinux-advanced-c73d8355-1ac9-41b4-8edf-c1c1a9d5bd6a {
      		if [ x$grub_platform = xxen ]; then insmod xzio; insmod lzopio; fi
      		if [ x$grub_platform = xxen ]; then insmod xzio; insmod lzopio; fi
      		if [ x$grub_platform = xxen ]; then insmod xzio; insmod lzopio; fi
      		if [ x$grub_platform = xxen ]; then insmod xzio; insmod lzopio; fi
      grub_cmd: menuentry Ubuntu 21.04 (21.04) (on /dev/sda1) --class ubuntu --class gnu-linux --class gnu --class os --id osprober-gnulinux-simple-c73d8355-1ac9-41b4-8edf-c1c1a9d5bd6a {
      grub_cmd: submenu Advanced options for Ubuntu 21.04 (21.04) (on /dev/sda1) --id osprober-gnulinux-advanced-c73d8355-1ac9-41b4-8edf-c1c1a9d5bd6a {
      grub_cmd: set timeout_style=menu
      grub_cmd: [ 0.1 = 0 ]
      grub_cmd: menuentry UEFI Firmware Settings --id uefi-firmware {
      grub_cmd: [ -f (hd0,gpt1)/boot/grub/custom.cfg ]
      grub_cmd: [ -z (hd0,gpt1)/boot/grub -a -f (hd0,gpt1)/boot/grub/custom.cfg ]
      grub_cmd: setparams Ubuntu
      grub_cmd: recordfail
      grub_cmd: set recordfail=1
      grub_cmd: [ -n true ]
      grub_cmd: [ -z  ]
      grub_cmd: save_env recordfail
      grub_cmd: load_video
      grub_cmd: [ xy = xy ]
      grub_cmd: insmod all_video
      grub_cmd: gfxmode keep
      grub_cmd: set gfxpayload=keep
      grub_cmd: [ keep = keep ]
      grub_cmd: set vt_handoff=vt.handoff=7
      grub_cmd: insmod gzio
      grub_cmd: [ xefi = xxen ]
      grub_cmd: insmod part_gpt
      grub_cmd: insmod ext2
      grub_cmd: set root=hd0,gpt1
      grub_cmd: [ xy = xy ]
      grub_cmd: search --no-floppy --fs-uuid --set=root --hint-bios=hd0,gpt1 --hint-efi=hd0,gpt1 --hint-baremetal=ahci0,gpt1 c73d8355-1ac9-41b4-8edf-c1c1a9d5bd6a
      grub_cmd: [  = 1 ]
      grub_cmd: echo GRUB_FORCE_PARTUUID set, attempting initrdless boot.
      grub_cmd: linux /boot/vmlinuz-5.11.0-1008-gcp root=PARTUUID=bf817bdf-6a3a-4221-8edb-2c1ca7c5537f ro scsi_mod.use_blk_mq=Y ima_hash=sha256 console=ttyS0 panic=-1
      grub_cmd: initrdfail
      grub_cmd: [ -n true ]
      grub_cmd: [ -n bf817bdf-6a3a-4221-8edb-2c1ca7c5537f ]
      grub_cmd: [ -z  ]
      grub_cmd: set initrdfail=1
      grub_cmd: [ -n  ]
      grub_cmd: save_env initrdfail


This is a really challenging eventlog when trying to validate the PCR
state is matching some expected "known good" state. Given a single
grub.conf, you get both a huge number of entries for every boot, plus
a combinatorial expansion of possible entries that would be considered
valid for a given install over time as kernels and/or grub itself are
updated. A tiny change to the way grub2-mkconfig could result in a
very different PCR eventlog, but which is semantically identical to
what came before.

Thus any attempt to validate the the grub.conf PCR eventlog, as it
exists in typical distro deployments today, is going to be both
complex and fragile, which is a bad combination.


If we compare this to what is done when booting a unified kernel
image with sd-boot + sd-shim. It has the fortune of being designed
for a pretty narrow use case, thus not needing to address legacy
non-EFI environments, and excluding much of the functionality that
grub aims to provided. Its operation is also designed to be almost
zero-conf - the loader.conf has just a handful of possible entries,
of which none need to be verified directly, as they dont' affect
what is boot, just what the sd-boot UI does (possible exception
with the 'random-seed-mode' opt).

Rather than being a bootloader, it is better considered to be a
boot menu. It just lets the user pick between a selection of
kernel images. If all the images are using unified kernel image
format and signed by the OS vendor (or whatever SB cert is
trusted), there is nothing about the bootloader config that
needs verifying. All that's required is verifying that the
bootloader was indeed sd-boot, and then verifying that SecureBoot
was enabled with the desired cert enrolled.

I guess in fairness to grub, maybe it is possible to achieve something
similar if one were to have a cut down grub that had nearly all its
functionality disabled, such that it merely became a boot menu for
selecting between auto-detected unified kernel images found via the
BootLoaderSpec.

I guess I'd summarize the overall goal as being to find a way to verify
the boot state in a way that does not depend on any local installation
specific data, beyond what physical firmware is installed. The ultimate
result being to be able to verify solely based on the PCR recording the
machine firmware,  the Secure Boot flag state and which Secure Boot certs
were associted with the loaded image(s). Realistically you likely need to
verify which bootloader was used, unless the OS vendor has different
signing keys for each bootloader they distribute. Beyond that, as little
as possible, ideally nothing as it risks creating combinatorial expansions
of state to keep track of.

With regards,
Daniel
-- 
|: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org         -o-            https://fstop138.berrange.com :|
|: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|
_______________________________________________
devel mailing list -- devel@xxxxxxxxxxxxxxxxxxxxxxx
To unsubscribe send an email to devel-leave@xxxxxxxxxxxxxxxxxxxxxxx
Fedora Code of Conduct: https://docs.fedoraproject.org/en-US/project/code-of-conduct/
List Guidelines: https://fedoraproject.org/wiki/Mailing_list_guidelines
List Archives: https://lists.fedoraproject.org/archives/list/devel@xxxxxxxxxxxxxxxxxxxxxxx
Do not reply to spam, report it: https://pagure.io/fedora-infrastructure/new_issue




[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Fedora Announce]     [Fedora Users]     [Fedora Kernel]     [Fedora Testing]     [Fedora Formulas]     [Fedora PHP Devel]     [Kernel Development]     [Fedora Legacy]     [Fedora Maintainers]     [Fedora Desktop]     [PAM]     [Red Hat Development]     [Gimp]     [Yosemite News]

  Powered by Linux