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: CLOSED ERRATA
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: Meina Li
URL:
Whiteboard:
Depends On:
Blocks: 1369007 1937150
TreeView+ depends on / blocked
 
Reported: 2021-02-16 17:54 UTC by Stephen Finucane
Modified: 2021-11-09 21:42 UTC (History)
5 users (show)

Fixed In Version: libvirt-6.0.0-36.el8
Doc Type: If docs needed, set a value
Doc Text:
Clone Of:
Environment:
Last Closed: 2021-11-09 17:58:01 UTC
Type: Feature Request
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


Links
System ID Private Priority Status Summary Last Updated
Red Hat Product Errata RHSA-2021:4191 0 None None None 2021-11-09 17:59:25 UTC

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.

Comment 7 Pavel Hrdina 2021-03-18 18:01:52 UTC
Upstream commits:

c91fa27306 qemu: implement support for firmware auto-selection feature filtering
cff524af6c conf: introduce support for firmware auto-selection feature filtering
6330be1ba3 conf: use switch in virDomainDefParseBootOptions
108cb29c1c conf: introduce virDomainDefParseBootAcpiOptions
b8dd70db4e conf: introduce virDomainDefParseBootLoaderOptions
bcf97abfc6 conf: introduce virDomainDefParseBootFirmwareOptions
bf9b3f8e57 conf: introduce virDomainDefParseBootKernelOptions
b07116438c conf: introduce virDomainDefParseBootInitOptions
f47d06260b docs: improve description of secure attribute for loader element

Comment 8 Pavel Hrdina 2021-05-20 12:01:53 UTC
Two additional commits that we will need to backport:

a9b1375d7d conf: remove duplicated firmware type attribute
c116b94814 domain_conf: Don't leak def->os.firmwareFeatures

Comment 13 Meina Li 2021-06-04 06:48:05 UTC
Verified Version:
libvirt-6.0.0-36.module+el8.5.0+11222+c889b3f3.x86_64
qemu-kvm-4.2.0-51.module+el8.5.0+11141+9dff516f.x86_64

Verified Steps:
1. Prepare an OVMF guest with the signed image and unsigned image respectively.
2. Update enabled features with different combination in guest xml.
# virsh dumpxml --inactive ovmf | grep /os -B7
  <os firmware='efi'>
    <type arch='x86_64' machine='pc-q35-rhel8.4.0'>hvm</type>
    <firmware>
      <feature enabled='**yes**' name='enrolled-keys'/>
      <feature enabled='**yes**' name='secure-boot'/>
    </firmware>
    <boot dev='hd'/>
  </os>
2. Start the guest and check the boot process.
# virsh start ovmf
Domain 'ovmf' started

# virt-viewer ovmf

Test Matrix:
S1: Boot OVMF guest with signed image and different features combination
Test Matrix:
secure-boot  enrolled-keys  Expected Result  	     
yes	          yes	          can boot	              
yes	          no	          can boot	
no	          no	          can't start guest with error
no	          yes	          can't start guest with error	     

S2: Boot OVMF guest with non-signed image and different features combination
secure-boot  enrolled-keys  Expected Result  	     
yes	          yes	          can't boot with has invalid signature error	              
yes	          no	          can boot
no	          no	          can't start guest with error
no	          yes	          can't start guest with error	

The test results are expected.

Comment 15 errata-xmlrpc 2021-11-09 17:58:01 UTC
Since the problem described in this bug report should be
resolved in a recent advisory, it has been closed with a
resolution of ERRATA.

For information on the advisory (Moderate: virt:rhel and virt-devel:rhel security, bug fix, and enhancement update), and where to find the updated
files, follow the link below.

If the solution does not work for you, open a new bug report.

https://access.redhat.com/errata/RHSA-2021:4191


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