Bug 1929357 - UEFI: Provide a way how to configure different combinations of secure boot enabled/disabled and keys enrolled/not enrolled
Summary: UEFI: Provide a way how to configure different combinations of secure boot en...
Keywords:
Status: NEW
Alias: None
Product: Red Hat Enterprise Linux 8
Classification: Red Hat
Component: libvirt
Version: 8.0
Hardware: Unspecified
OS: Unspecified
medium
medium
Target Milestone: rc
: ---
Assignee: Pavel Hrdina
QA Contact: Virtualization Bugs
URL:
Whiteboard:
Depends On:
Blocks: 1369007
TreeView+ depends on / blocked
 
Reported: 2021-02-16 17:54 UTC by Stephen Finucane
Modified: 2021-02-23 16:37 UTC (History)
3 users (show)

Fixed In Version:
Doc Type: If docs needed, set a value
Doc Text:
Clone Of:
Environment:
Last Closed:
Type: Bug
Target Upstream Version:


Attachments (Terms of Use)
Sample reproducer (1.52 KB, text/plain)
2021-02-16 17:54 UTC, Stephen Finucane
no flags Details

Description Stephen Finucane 2021-02-16 17:54:56 UTC
Created attachment 1757309 [details]
Sample reproducer

Description of problem:

BZ#1564270 added support for auto-negotiation of UEFI firmware using the firmware metadata files provided by QEMU. This allows us to specify the following as part of the XML generation:

  <os firmware="efi">
    <type arch="x86_64" machine="pc-q35-5.1">hvm</type>
    <boot dev="cdrom"/>
  </os>

Which libvirt will duly transform into e.g.:

  <os>
    <type arch='x86_64' machine='pc-q35-5.1'>hvm</type>
    <loader readonly='yes' secure='no' type='pflash'>/usr/share/edk2/ovmf/OVMF_CODE.secboot.fd</loader>
    <nvram template='/usr/share/edk2/ovmf/OVMF_VARS.secboot.fd'>/home/user/.config/libvirt/qemu/nvram/alpinelinux-q35-uefi-experiment_VARS.fd</nvram>
    <boot dev='cdrom'/>
  </os>

I'm attempting to boot a live CD to sanity check things. Upon booting, I see the following emitted:

  BdsDxe: loading Boot0001 "UEFI QEMU DVD-ROM QM00001 " from PciRoot(0x0)/Pci(0x1F,0x2)/Sata(0x0,0xFFFF,0x0)
  BdsDxe: failed to load Boot0001 "UEFI QEMU DVD-ROM QM00001 " from PciRoot(0x0)/Pci(0x1F,0x2)/Sata(0x0,0xFFFF,0x0): Access Denied
  BdsDxe: No bootable option or device was found.
  BdsDxe: Press any key to enter the Boot Manager Menu.

This appears to be an issue with secure boot. I duly disabled this by adding the '<loader>' element, like so:

  <os firmware="efi">
    <type arch="x86_64" machine="pc-q35-5.1">hvm</type>
    <loader secure="no"/>
    <boot dev="cdrom"/>
  </os>

However, this still fails. Looking at the XML, it appears libvirt has ignored the '//os/loader[@secure]' attribute:

  <os>                                                                                                                                                                                                             
    <type arch='x86_64' machine='pc-q35-5.1'>hvm</type>
    <loader readonly='yes' secure='no' type='pflash'>/usr/share/edk2/ovmf/OVMF_CODE.secboot.fd</loader>
    <nvram template='/usr/share/edk2/ovmf/OVMF_VARS.secboot.fd'>/home/stephenfin/.config/libvirt/qemu/nvram/alpinelinux-q35-uefi-experiment_VARS.fd</nvram>
    <boot dev='cdrom'/>
  </os>

If I manually specify the firmware, the issue goes away and I'm able to boot the live CD:

  <os>
    <type arch='x86_64' machine='pc-q35-5.1'>hvm</type>
    <loader readonly='yes' type='pflash'>/usr/share/edk2/ovmf/OVMF_CODE.fd</loader>
    <boot dev='cdrom'/>
  </os>

Version-Release number of selected component (if applicable):

libvirt 6.6.0
edk2-ovmf 20200801stable

How reproducible:

Always.
Steps to Reproduce:

Using the attached XML

1. cd /tmp
2. wget https://dl-cdn.alpinelinux.org/alpine/v3.13/releases/x86_64/alpine-virt-3.13.1-x86_64.iso
3. virsh create alpine-virt.xml
4. virsh console alpinelinux-q35-uefi-experiment

Actual results:

Bootloader is unable to boot from live CD.

Expected results:

Instance should boot.

Additional info:

Comment 1 Stephen Finucane 2021-02-16 18:06:54 UTC
Some additional information:

  $ ls /usr/share/qemu/firmware/ -1
  40-edk2-ovmf-x64-sb-enrolled.json
  50-edk2-ovmf-x64-sb.json
  60-edk2-ovmf-x64.json
  70-edk2-aarch64-verbose.json

Comment 3 Stephen Finucane 2021-02-16 21:31:28 UTC
Another data point. This works:

  <os firmware="efi">
    <type arch='x86_64' machine='pc-q35-5.1'>hvm</type>
    <loader readonly='yes' type='pflash'>/usr/share/edk2/ovmf/OVMF_CODE.fd</loader>
    <boot dev='cdrom'/>
  </os>

It results in the following XML:

  <os>
    <type arch='x86_64' machine='pc-q35-5.1'>hvm</type>
    <loader readonly='yes' type='pflash'>/usr/share/edk2/ovmf/OVMF_CODE.fd</loader>
    <nvram>/home/stephenfin/.config/libvirt/qemu/nvram/alpinelinux-q35-uefi-experiment_VARS.fd</nvram>
    <boot dev='cdrom'/>
  </os>

This does not work:

  <os firmware="efi">
    <type arch='x86_64' machine='pc-q35-5.1'>hvm</type>
    <loader readonly='yes' type='pflash'>/usr/share/edk2/ovmf/OVMF_CODE.fd</loader>
    <boot dev='cdrom'/>
  </os>

It results in the following XML, where we see the requested loader is totally ignored. This seems like it should be an error?

  <os>
    <type arch='x86_64' machine='pc-q35-5.1'>hvm</type>
    <loader readonly='yes' type='pflash'>/usr/share/edk2/ovmf/OVMF_CODE.secboot.fd</loader>
    <nvram template='/usr/share/edk2/ovmf/OVMF_VARS.secboot.fd'>/home/stephenfin/.config/libvirt/qemu/nvram/alpinelinux-q35-uefi-experiment_VARS.fd</nvram>
    <boot dev='cdrom'/>
  </os>

Also, I tried with a Fedora 33 Workstation image and things boot just fine regardless of the bootloader configuration. This is presumably because the Fedora images are signed?

I've documented my findings at [1], though it mostly duplicates what I've already said here.

[1] https://that.guru/blog/uefi-secure-boot-in-libvirt/

Comment 4 Stephen Finucane 2021-02-17 11:24:54 UTC
(In reply to Stephen Finucane from comment #3)
> Another data point. This works:
> 
>   <os firmware="efi">
>     <type arch='x86_64' machine='pc-q35-5.1'>hvm</type>
>     <loader readonly='yes'
> type='pflash'>/usr/share/edk2/ovmf/OVMF_CODE.fd</loader>
>     <boot dev='cdrom'/>
>   </os>

Apologies. This should read:

  <os>
    <type arch='x86_64' machine='pc-q35-5.1'>hvm</type>
    <loader readonly='yes' type='pflash'>/usr/share/edk2/ovmf/OVMF_CODE.fd</loader>
    <boot dev='cdrom'/>
  </os>

i.e. no 'firmware' attribute on the 'os' element. If the 'firmware' attribute is specified, everything else inside the '<os>' element is seemingly ignored, which seems wrong: surely this should raise an error rather than being silently dropped?

I tried experimenting with the 'secure' attribute of the 'loader' element. For example:

  <os>
    <type arch="x86_64" machine="pc-q35-5.1">hvm</type>
    <loader readonly="yes" type="pflash" secure="no">/usr/share/edk2/ovmf/OVMF_CODE.secboot.fd</loader>
    <boot dev="cdrom"/>
  </os>

The docs [1] suggest setting the 'secure' attribute should allow me to control secure boot behavior, stating:

  Moreover, some firmwares may implement the Secure boot feature. Attribute secure can be used then to control it.

This would also align with what I've been told me about secure boot-enabled firmware being able to be used for non-secure boot guests. However, secure boot still appears to be enabled and I'm unable to boot the guest, with the same Access Denied errors being raised by the bootloader. Note that doing the opposite and attempting to set the 'secure="yes"' attribute when using a non-secure boot firmware does fail as expected. For example:

  <os>
    <type arch="x86_64" machine="pc-q35-5.1">hvm</type>
    <loader readonly="yes" type="pflash" secure="yes">/usr/share/edk2/ovmf/OVMF_CODE.fd</loader>
    <boot dev="cdrom"/>
  </os>

This fails with the following error message:

  error: Failed to create domain from alpine-test.xml
  error: unsupported configuration: Secure boot requires SMM feature enabled

Finally, I have also tested this with a Mageia 7.1 netinstall image just to rule out issues with the Alpine Linux issue. This image was chosen as the Mageia docs suggest that UEFI is supported but secure boot is not [2]. Once again, I see an Access Denied error from the bootloader if the secboot firmware is used.

[1] https://libvirt.org/formatdomain.html#bios-bootloader
[2] https://wiki.mageia.org/en/About_EFI_UEFI#Secure_Boot

Comment 5 Pavel Hrdina 2021-02-18 19:25:52 UTC
Hi, thanks for the report.

The situation with secure boot and firmwares is a bit complicated.

One thing to note is that there is no '/usr/share/edk2/ovmf/OVMF_CODE.fd'
in RHEL-8, my guess is that you tried it on Fedora.


There are several JSON descriptions of firmware configurations:

  1) '40-edk2-ovmf-sb.json' (RHEL-8), '40-edk2-ovmf-x64-sb-enrolled.json' (Fedora-33)

    - secure boot feature enabled, keys enrolled

    - With this configuration it will boot only signed loaders, others are rejected
      with 'Access denied' or 'permission denied' so similar.

    - This refers to firmware '/usr/share/edk2/ovmf/OVMF_CODE.secboot.fd' and
      NVRAM template '/usr/share/edk2/ovmf/OVMF_VARS.secboot.fd'.


  2) '50-edk2-ovmf.json' (RHEL-8), '50-edk2-ovmf-x64-sb.json' (Fedora-33)

    - secure boot feature enabled, no keys enrolled

    - With this configuration it will boot all loaders because there are no keys
      to verify any signature.

    - This refers to firmware '/usr/share/edk2/ovmf/OVMF_CODE.secboot.fd' and 
      NVRAM template '/usr/share/edk2/ovmf/OVMF_VARS.fd'.


  3) '60-edk2-ovmf-x64.json' (Fedora-33)

    - secure boot feature disabled, no keys enrolled

    - With this configuration it will boot all loaders because there is no secure
      boot feature available in the firmware.

    - This refers to firmware '/usr/share/edk2/ovmf/OVMF_CODE.fd' and
      NVRAM template '/usr/share/edk2/ovmf/OVMF_VARS.fd'.


Currently with libvirt the <os firmware='efi'> will automatically select only
option 1) as it is the first available JSON description.

There is no other easy way in libvirt to configure options 2) and 3) except for
providing all the paths to firmware in <loader> element and NVRAM template
in <nvram> element.

Now the 'secure' attribute has a bit misleading documentations as it doesn't control
whether the feature is enabled/disabled in the firmware but it is used to tell to
QEMU if the provided firmware is with secure boot feature enabled/disabled so QEMU
knows how to handle the firmware and access to it. We definitely need to improve
the documentation.

There is another BZ 1906500 that hits the same limitation in libvirt without
providing all the paths manually in the XML, you can check the comments for
additional details.


We need to probably add new attributes/elements to libvirt VM XML to have simple
way how to configure options 2) and 3).

Comment 6 Stephen Finucane 2021-02-23 16:37:48 UTC
(In reply to Pavel Hrdina from comment #5)
> Hi, thanks for the report.
> 
> The situation with secure boot and firmwares is a bit complicated.
> 
> One thing to note is that there is no '/usr/share/edk2/ovmf/OVMF_CODE.fd'
> in RHEL-8, my guess is that you tried it on Fedora.

Correct. I had a long comment written out last week explaining this but BZ was returning HTTP 5xx errors and took my comment with it :)

> There are several JSON descriptions of firmware configurations:
> 
>   1) '40-edk2-ovmf-sb.json' (RHEL-8), '40-edk2-ovmf-x64-sb-enrolled.json' (Fedora-33)
> 
>     - secure boot feature enabled, keys enrolled
> 
>     - With this configuration it will boot only signed loaders, others are rejected
>       with 'Access denied' or 'permission denied' so similar.
> 
>     - This refers to firmware '/usr/share/edk2/ovmf/OVMF_CODE.secboot.fd' and
>       NVRAM template '/usr/share/edk2/ovmf/OVMF_VARS.secboot.fd'.
> 
> 
>   2) '50-edk2-ovmf.json' (RHEL-8), '50-edk2-ovmf-x64-sb.json' (Fedora-33)
> 
>     - secure boot feature enabled, no keys enrolled
> 
>     - With this configuration it will boot all loaders because there are no keys
>       to verify any signature.
> 
>     - This refers to firmware '/usr/share/edk2/ovmf/OVMF_CODE.secboot.fd' and 
>       NVRAM template '/usr/share/edk2/ovmf/OVMF_VARS.fd'.
> 
> 
>   3) '60-edk2-ovmf-x64.json' (Fedora-33)
> 
>     - secure boot feature disabled, no keys enrolled
> 
>     - With this configuration it will boot all loaders because there is no secure
>       boot feature available in the firmware.
> 
>     - This refers to firmware '/usr/share/edk2/ovmf/OVMF_CODE.fd' and
>       NVRAM template '/usr/share/edk2/ovmf/OVMF_VARS.fd'.
> 
> 
> Currently with libvirt the <os firmware='efi'> will automatically select only
> option 1) as it is the first available JSON description.
> 
> There is no other easy way in libvirt to configure options 2) and 3) except for
> providing all the paths to firmware in <loader> element and NVRAM template
> in <nvram> element.
> 
> Now the 'secure' attribute has a bit misleading documentations as it doesn't control
> whether the feature is enabled/disabled in the firmware but it is used to tell to
> QEMU if the provided firmware is with secure boot feature enabled/disabled so QEMU
> knows how to handle the firmware and access to it. We definitely need to improve
> the documentation.
> 
> There is another BZ 1906500 that hits the same limitation in libvirt without
> providing all the paths manually in the XML, you can check the comments for
> additional details.
> 
> We need to probably add new attributes/elements to libvirt VM XML to have simple
> way how to configure options 2) and 3).

Thank you for all the context. I'll feed this into back into the OpenStack Nova RFE.
It sounds like we can use libvirt's discovery functionality but not the auto-configuration
feature (at least not yet). For what it's worth, something akin to what I was trying to
do (enable or disable secure boot via '<loader secure="yes|no"/>') would be fantastic
and probably what we'll need to be able to consume this feature.


Note You need to log in before you can comment on or make changes to this bug.