From 6f02748897062d40b411177ef752644505189a72 Mon Sep 17 00:00:00 2001 Message-Id: <6f02748897062d40b411177ef752644505189a72@dist-git> From: Pavel Hrdina Date: Fri, 21 May 2021 14:16:11 +0200 Subject: [PATCH] conf: introduce support for firmware auto-selection feature filtering When the firmware auto-selection was introduced it always picked first usable firmware based on the JSON descriptions on the host. It is possible to add/remove/change the JSON files but it will always be for the whole host. This patch introduces support for configuring the auto-selection per VM by adding users an option to limit what features they would like to have available in the firmware. Signed-off-by: Pavel Hrdina Reviewed-by: Michal Privoznik (cherry picked from commit cff524af6c5e1ddc11149394ed7f985242ebea0f) Conflicts: docs/formatdomain.rst - we still have formatdomain.html.in in downstream src/conf/domain_conf.c - missing following upstream commits: 0280fc72708b9d0f162a808bcc8d78137a68d58d 104dadcff6023da676df3905d1ed8688aea15e86 2d5f7a49ae0780143566932ab38215433982c89f Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1929357 Signed-off-by: Pavel Hrdina Message-Id: <631e05bc5363abb3e48d8b652a806324801cce16.1621599207.git.phrdina@redhat.com> Reviewed-by: Michal Privoznik --- docs/formatdomain.html.in | 58 +++++++++++++ docs/schemas/domaincommon.rng | 23 +++++ src/conf/domain_conf.c | 83 ++++++++++++++++++- src/conf/domain_conf.h | 10 +++ ...os-firmware-invalid-type.x86_64-latest.err | 1 + .../os-firmware-invalid-type.xml | 28 +++++++ tests/qemuxml2argvtest.c | 1 + ...aarch64-os-firmware-efi.aarch64-latest.xml | 1 + .../os-firmware-bios.x86_64-latest.xml | 1 + .../os-firmware-efi-secboot.x86_64-latest.xml | 1 + .../os-firmware-efi.x86_64-latest.xml | 1 + tests/vmx2xmldata/vmx2xml-firmware-efi.xml | 1 + 12 files changed, 206 insertions(+), 3 deletions(-) create mode 100644 tests/qemuxml2argvdata/os-firmware-invalid-type.x86_64-latest.err create mode 100644 tests/qemuxml2argvdata/os-firmware-invalid-type.xml diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in index a40bed347b..11f31618af 100644 --- a/docs/formatdomain.html.in +++ b/docs/formatdomain.html.in @@ -180,6 +180,64 @@ ESX and VMWare hypervisor drivers, however, the i686 arch will always be chosen even on an x86_64 host. Since 0.0.1 +
firmware
+
+

Since 7.2.0 QEMU/KVM only

+

+ When used together with firmware attribute of + os element the type attribute must + have the same value. +

+

+ List of mandatory attributes: +

    +
  • + type (accepted values are bios + and efi) same as the firmware + attribute of os element. +
  • +
+

+

+ When using firmware auto-selection there are different features + enabled in the firmwares. The list of features can be used to + limit what firmware should be automatically selected for the VM. + The list of features can be specified using zero or more + feature elements. Libvirt will take into consideration + only the listed features and ignore the rest when selecting the firmware. + +

+
feature
+
+ The list of mandatory attributes: + +
    +
  • + enabled (accepted values are yes + and no) is used to tell libvirt if the feature + must be enabled or not in the automatically selected firmware +
  • +
  • + name the name of the feature, the list of the features: +
      +
    • + enrolled-keys whether the selected nvram template + has default certificate enrolled. Firmware with Secure Boot + feature but without enrolled keys will successfully boot + non-signed binaries as well. Valid only for firmwares with + Secure Boot feature. +
    • +
    • + secure-boot whether the firmware implements + UEFI Secure boot feature. +
    • +
    +
  • +
+
+
+

+
loader
The optional loader tag refers to a firmware blob, which is specified by absolute path, diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index 6671ef3dfa..b7f6a6b494 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -268,6 +268,29 @@ + + + + + bios + efi + + + + + + + + + + enrolled-keys + secure-boot + + + + + + diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 93a78f8277..28c8d0ecbd 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -1240,6 +1240,12 @@ VIR_ENUM_IMPL(virDomainOsDefFirmware, "efi", ); +VIR_ENUM_IMPL(virDomainOsDefFirmwareFeature, + VIR_DOMAIN_OS_DEF_FIRMWARE_FEATURE_LAST, + "enrolled-keys", + "secure-boot", +); + /* Internal mapping: subset of block job types that can be present in * XML (remaining types are not two-phase). */ VIR_ENUM_DECL(virDomainBlockJob); @@ -19382,22 +19388,67 @@ virDomainDefParseBootFirmwareOptions(virDomainDefPtr def, xmlXPathContextPtr ctxt) { g_autofree char *firmware = virXPathString("string(./os/@firmware)", ctxt); + g_autofree char *type = virXPathString("string(./os/firmware/@type)", ctxt); + g_autofree xmlNodePtr *nodes = NULL; + g_autofree int *features = NULL; int fw = 0; + int n = 0; + size_t i; - if (!firmware) + if (!firmware && !type) return 0; - fw = virDomainOsDefFirmwareTypeFromString(firmware); + if (firmware && type && STRNEQ(firmware, type)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("firmware attribute and firmware type has to be the same")); + return -1; + } + + if (!type) + type = g_steal_pointer(&firmware); + + fw = virDomainOsDefFirmwareTypeFromString(type); if (fw <= 0) { virReportError(VIR_ERR_XML_ERROR, _("unknown firmware value %s"), - firmware); + type); return -1; } def->os.firmware = fw; + if ((n = virXPathNodeSet("./os/firmware/feature", ctxt, &nodes)) < 0) + return -1; + + if (n > 0) + features = g_new0(int, VIR_DOMAIN_OS_DEF_FIRMWARE_FEATURE_LAST); + + for (i = 0; i < n; i++) { + g_autofree char *name = virXMLPropString(nodes[i], "name"); + g_autofree char *enabled = virXMLPropString(nodes[i], "enabled"); + int feature = virDomainOsDefFirmwareFeatureTypeFromString(name); + int val = virTristateBoolTypeFromString(enabled); + + if (feature < 0) { + virReportError(VIR_ERR_XML_ERROR, + _("invalid firmware feature name '%s'"), + name); + return -1; + } + + if (val < 0) { + virReportError(VIR_ERR_XML_ERROR, + _("invalid firmware feature enabled value '%s'"), + enabled); + return -1; + } + + features[feature] = val; + } + + def->os.firmwareFeatures = g_steal_pointer(&features); + return 0; } @@ -28987,6 +29038,32 @@ virDomainDefFormatInternalSetRootName(virDomainDefPtr def, virBufferAsprintf(buf, ">%s\n", virDomainOSTypeToString(def->os.type)); + if (def->os.firmware) { + virBufferAsprintf(buf, "os.firmware)); + + if (def->os.firmwareFeatures) { + virBufferAddLit(buf, ">\n"); + + virBufferAdjustIndent(buf, 2); + + for (i = 0; i < VIR_DOMAIN_OS_DEF_FIRMWARE_FEATURE_LAST; i++) { + if (def->os.firmwareFeatures[i] == VIR_TRISTATE_BOOL_ABSENT) + continue; + + virBufferAsprintf(buf, "\n", + virTristateBoolTypeToString(def->os.firmwareFeatures[i]), + virDomainOsDefFirmwareFeatureTypeToString(i)); + } + + virBufferAdjustIndent(buf, -2); + + virBufferAddLit(buf, "\n"); + } else { + virBufferAddLit(buf, "/>\n"); + } + } + virBufferEscapeString(buf, "%s\n", def->os.init); for (i = 0; def->os.initargv && def->os.initargv[i]; i++) diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 3aed1fb22a..1ad77ecac6 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -1967,9 +1967,19 @@ G_STATIC_ASSERT((int)VIR_DOMAIN_OS_DEF_FIRMWARE_LAST == (int)VIR_DOMAIN_LOADER_T VIR_ENUM_DECL(virDomainOsDefFirmware); +typedef enum { + VIR_DOMAIN_OS_DEF_FIRMWARE_FEATURE_ENROLLED_KEYS, + VIR_DOMAIN_OS_DEF_FIRMWARE_FEATURE_SECURE_BOOT, + + VIR_DOMAIN_OS_DEF_FIRMWARE_FEATURE_LAST +} virDomainOsDefFirmwareFeature; + +VIR_ENUM_DECL(virDomainOsDefFirmwareFeature); + struct _virDomainOSDef { int type; virDomainOsDefFirmware firmware; + int *firmwareFeatures; virArch arch; char *machine; size_t nBootDevs; diff --git a/tests/qemuxml2argvdata/os-firmware-invalid-type.x86_64-latest.err b/tests/qemuxml2argvdata/os-firmware-invalid-type.x86_64-latest.err new file mode 100644 index 0000000000..c8174b1c8b --- /dev/null +++ b/tests/qemuxml2argvdata/os-firmware-invalid-type.x86_64-latest.err @@ -0,0 +1 @@ +unsupported configuration: firmware attribute and firmware type has to be the same diff --git a/tests/qemuxml2argvdata/os-firmware-invalid-type.xml b/tests/qemuxml2argvdata/os-firmware-invalid-type.xml new file mode 100644 index 0000000000..41360df0f7 --- /dev/null +++ b/tests/qemuxml2argvdata/os-firmware-invalid-type.xml @@ -0,0 +1,28 @@ + + fedora + 63840878-0deb-4095-97e6-fc444d9bc9fa + 8192 + 8192 + 1 + + hvm + + + /var/lib/libvirt/qemu/nvram/fedora_VARS.fd + + + + + + + + + + destroy + restart + restart + + /usr/bin/qemu-system-x86_64 + + + diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index a22e3ba157..bc04bea692 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -3094,6 +3094,7 @@ mymain(void) DO_TEST_CAPS_LATEST("os-firmware-bios"); DO_TEST_CAPS_LATEST("os-firmware-efi"); DO_TEST_CAPS_LATEST("os-firmware-efi-secboot"); + DO_TEST_CAPS_LATEST_PARSE_ERROR("os-firmware-invalid-type"); DO_TEST_CAPS_ARCH_LATEST("aarch64-os-firmware-efi", "aarch64"); DO_TEST_CAPS_LATEST("vhost-user-vga"); diff --git a/tests/qemuxml2xmloutdata/aarch64-os-firmware-efi.aarch64-latest.xml b/tests/qemuxml2xmloutdata/aarch64-os-firmware-efi.aarch64-latest.xml index 1e51d55305..3cac8fc5c6 100644 --- a/tests/qemuxml2xmloutdata/aarch64-os-firmware-efi.aarch64-latest.xml +++ b/tests/qemuxml2xmloutdata/aarch64-os-firmware-efi.aarch64-latest.xml @@ -6,6 +6,7 @@ 1 hvm + /aarch64.kernel /aarch64.initrd earlyprintk console=ttyAMA0,115200n8 rw root=/dev/vda rootwait diff --git a/tests/qemuxml2xmloutdata/os-firmware-bios.x86_64-latest.xml b/tests/qemuxml2xmloutdata/os-firmware-bios.x86_64-latest.xml index 60d3498765..ef24f2fece 100644 --- a/tests/qemuxml2xmloutdata/os-firmware-bios.x86_64-latest.xml +++ b/tests/qemuxml2xmloutdata/os-firmware-bios.x86_64-latest.xml @@ -6,6 +6,7 @@ 1 hvm + /var/lib/libvirt/qemu/nvram/fedora_VARS.fd diff --git a/tests/qemuxml2xmloutdata/os-firmware-efi-secboot.x86_64-latest.xml b/tests/qemuxml2xmloutdata/os-firmware-efi-secboot.x86_64-latest.xml index 938da73711..3757191e8e 100644 --- a/tests/qemuxml2xmloutdata/os-firmware-efi-secboot.x86_64-latest.xml +++ b/tests/qemuxml2xmloutdata/os-firmware-efi-secboot.x86_64-latest.xml @@ -6,6 +6,7 @@ 1 hvm + /var/lib/libvirt/qemu/nvram/fedora_VARS.fd diff --git a/tests/qemuxml2xmloutdata/os-firmware-efi.x86_64-latest.xml b/tests/qemuxml2xmloutdata/os-firmware-efi.x86_64-latest.xml index 97ce8a75c7..f2e6b7f36d 100644 --- a/tests/qemuxml2xmloutdata/os-firmware-efi.x86_64-latest.xml +++ b/tests/qemuxml2xmloutdata/os-firmware-efi.x86_64-latest.xml @@ -6,6 +6,7 @@ 1 hvm + /var/lib/libvirt/qemu/nvram/fedora_VARS.fd diff --git a/tests/vmx2xmldata/vmx2xml-firmware-efi.xml b/tests/vmx2xmldata/vmx2xml-firmware-efi.xml index e21158cebf..375c47d281 100644 --- a/tests/vmx2xmldata/vmx2xml-firmware-efi.xml +++ b/tests/vmx2xmldata/vmx2xml-firmware-efi.xml @@ -5,6 +5,7 @@ 1 hvm + destroy -- 2.31.1