[PATCH 0/5] Introduce UEFI shim support

*** BLURB HERE *** Michal Prívozník (5): conf: Introduce os/shim element qemu_capabilities: Introduce QEMU_CAPS_MACHINE_SHIM qemu_validate: Check whether UEFI shim is supported qemu_command: Generate cmd line for UEFI shim security: Set seclabels on UEFI shim docs/formatdomain.rst | 5 +++++ src/conf/domain_conf.c | 12 ++++++++---- src/conf/domain_conf.h | 1 + src/conf/domain_validate.c | 6 ++++++ src/conf/schemas/domaincommon.rng | 5 +++++ src/qemu/qemu_capabilities.c | 2 ++ src/qemu/qemu_capabilities.h | 1 + src/qemu/qemu_command.c | 2 ++ src/qemu/qemu_validate.c | 7 +++++++ src/security/security_dac.c | 10 ++++++++++ src/security/security_selinux.c | 9 +++++++++ src/security/virt-aa-helper.c | 4 ++++ tests/qemucapabilitiesdata/caps_10.0.0_s390x.xml | 1 + tests/qemucapabilitiesdata/caps_10.0.0_x86_64.xml | 1 + .../launch-security-sev-direct.x86_64-latest.args | 1 + .../launch-security-sev-direct.x86_64-latest.xml | 1 + tests/qemuxmlconfdata/launch-security-sev-direct.xml | 1 + 17 files changed, 65 insertions(+), 4 deletions(-) -- 2.45.3

For secure boot environments where <loader/> is signed, it may be unfeasible to keep the binary up to date (esp. when revoking certificates contained within). To address that, QEMU introduced '-shim' cmd line option which side loads another UEFI binary which can then contain new certification authorities or list of revocations. Expose it as <shim/> element that's nested under <os/>, just like kernel and initrd are. Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- docs/formatdomain.rst | 5 +++++ src/conf/domain_conf.c | 12 ++++++++---- src/conf/domain_conf.h | 1 + src/conf/domain_validate.c | 6 ++++++ src/conf/schemas/domaincommon.rng | 5 +++++ .../launch-security-sev-direct.x86_64-latest.xml | 1 + tests/qemuxmlconfdata/launch-security-sev-direct.xml | 1 + 7 files changed, 27 insertions(+), 4 deletions(-) diff --git a/docs/formatdomain.rst b/docs/formatdomain.rst index cbe378e61d..087e77217e 100644 --- a/docs/formatdomain.rst +++ b/docs/formatdomain.rst @@ -397,6 +397,7 @@ and full virtualized guests. <kernel>/root/f8-i386-vmlinuz</kernel> <initrd>/root/f8-i386-initrd</initrd> <cmdline>console=ttyS0 ks=http://example.com/f8-i386/os/</cmdline> + <shim>/path/to/shim.efi</shim> <dtb>/root/ppc.dtb</dtb> </os> ... @@ -417,6 +418,10 @@ and full virtualized guests. The contents of this element specify arguments to be passed to the kernel (or installer) at boot time. This is often used to specify an alternate primary console (eg serial port), or the installation media source / kickstart file +``shim`` + Use specified fully-qualified path to load an initial UEFI bootloader that + handles chaining to a trusted full bootloader under secure boot + environments. ``dtb`` The contents of this element specify the fully-qualified path to the (optional) device tree binary (dtb) image in the host OS. diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index f42b7075ad..907e11cced 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -3922,6 +3922,7 @@ virDomainOSDefClear(virDomainOSDef *os) g_free(os->kernel); g_free(os->initrd); g_free(os->cmdline); + g_free(os->shim); g_free(os->dtb); g_free(os->root); g_free(os->slic_table); @@ -17732,6 +17733,7 @@ virDomainDefParseBootKernelOptions(virDomainDef *def, def->os.kernel = virXPathString("string(./os/kernel[1])", ctxt); def->os.initrd = virXPathString("string(./os/initrd[1])", ctxt); def->os.cmdline = virXPathString("string(./os/cmdline[1])", ctxt); + def->os.shim = virXPathString("string(./os/shim[1])", ctxt); def->os.dtb = virXPathString("string(./os/dtb[1])", ctxt); def->os.root = virXPathString("string(./os/root[1])", ctxt); } @@ -17904,10 +17906,10 @@ virDomainDefParseBootOptions(virDomainDef *def, /* * Booting options for different OS types.... * - * - A bootloader (and optional kernel+initrd) (xen) - * - A kernel + initrd (xen) - * - A boot device (and optional kernel+initrd) (hvm) - * - An init script (exe) + * - A bootloader (and optional kernel+initrd) (xen) + * - A kernel + initrd (xen) + * - A boot device (and optional kernel+initrd(+shim)) (hvm) + * - An init script (exe) */ switch ((virDomainOSType) def->os.type) { @@ -28414,6 +28416,8 @@ virDomainDefFormatInternalSetRootName(virDomainDef *def, def->os.initrd); virBufferEscapeString(buf, "<cmdline>%s</cmdline>\n", def->os.cmdline); + virBufferEscapeString(buf, "<shim>%s</shim>\n", + def->os.shim); virBufferEscapeString(buf, "<dtb>%s</dtb>\n", def->os.dtb); virBufferEscapeString(buf, "<root>%s</root>\n", diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index e7947741bd..32dabfeaa7 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -2501,6 +2501,7 @@ struct _virDomainOSDef { char *kernel; char *initrd; char *cmdline; + char *shim; char *dtb; char *root; char *slic_table; diff --git a/src/conf/domain_validate.c b/src/conf/domain_validate.c index ad3d17f0fd..6807d8e46a 100644 --- a/src/conf/domain_validate.c +++ b/src/conf/domain_validate.c @@ -1726,6 +1726,12 @@ virDomainDefOSValidate(const virDomainDef *def, } } + if (def->os.shim && !def->os.kernel) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("shim only allowed with kernel option")); + return -1; + } + return 0; } diff --git a/src/conf/schemas/domaincommon.rng b/src/conf/schemas/domaincommon.rng index 824da9d066..95196bee6e 100644 --- a/src/conf/schemas/domaincommon.rng +++ b/src/conf/schemas/domaincommon.rng @@ -1552,6 +1552,11 @@ <text/> </element> </optional> + <optional> + <element name="shim"> + <text/> + </element> + </optional> <optional> <element name="dtb"> <ref name="absFilePath"/> diff --git a/tests/qemuxmlconfdata/launch-security-sev-direct.x86_64-latest.xml b/tests/qemuxmlconfdata/launch-security-sev-direct.x86_64-latest.xml index e289b1e95e..dea8236540 100644 --- a/tests/qemuxmlconfdata/launch-security-sev-direct.x86_64-latest.xml +++ b/tests/qemuxmlconfdata/launch-security-sev-direct.x86_64-latest.xml @@ -9,6 +9,7 @@ <kernel>/vmlinuz</kernel> <initrd>/initrd</initrd> <cmdline>runme</cmdline> + <shim>/shim</shim> <boot dev='hd'/> </os> <cpu mode='custom' match='exact' check='none'> diff --git a/tests/qemuxmlconfdata/launch-security-sev-direct.xml b/tests/qemuxmlconfdata/launch-security-sev-direct.xml index 80ce6412dd..76277b6278 100644 --- a/tests/qemuxmlconfdata/launch-security-sev-direct.xml +++ b/tests/qemuxmlconfdata/launch-security-sev-direct.xml @@ -9,6 +9,7 @@ <kernel>/vmlinuz</kernel> <initrd>/initrd</initrd> <cmdline>runme</cmdline> + <shim>/shim</shim> </os> <clock offset='utc'/> <on_poweroff>destroy</on_poweroff> -- 2.45.3

In its commit v9.2.0-323-ga5bd044b15 QEMU introduced another command line option: -shim. It's used to load kernel. Track presence of it via QEMU_CAPS_MACHINE_SHIM. Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- src/qemu/qemu_capabilities.c | 2 ++ src/qemu/qemu_capabilities.h | 1 + tests/qemucapabilitiesdata/caps_10.0.0_s390x.xml | 1 + tests/qemucapabilitiesdata/caps_10.0.0_x86_64.xml | 1 + 4 files changed, 5 insertions(+) diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 23b466c36e..762588a270 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -728,6 +728,7 @@ VIR_ENUM_IMPL(virQEMUCaps, "machine.virt.aia", /* QEMU_CAPS_MACHINE_VIRT_AIA */ "virtio-mem-ccw", /* QEMU_CAPS_DEVICE_VIRTIO_MEM_CCW */ "blockdev-set-active", /* QEMU_CAPS_BLOCKDEV_SET_ACTIVE */ + "shim", /* QEMU_CAPS_MACHINE_SHIM */ ); @@ -1774,6 +1775,7 @@ static struct virQEMUCapsStringFlags virQEMUCapsMachinePropsVirt[] = { static struct virQEMUCapsStringFlags virQEMUCapsMachinePropsGeneric[] = { { "confidential-guest-support", QEMU_CAPS_MACHINE_CONFIDENTAL_GUEST_SUPPORT }, + { "shim", QEMU_CAPS_MACHINE_SHIM }, }; static struct virQEMUCapsStringFlags virQEMUCapsMachinePropsGenericPC[] = { diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h index ee71331a09..840cb97dbe 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -707,6 +707,7 @@ typedef enum { /* virQEMUCapsFlags grouping marker for syntax-check */ QEMU_CAPS_MACHINE_VIRT_AIA, /* -machine virt,aia=(none|aplic|aplic-imsic), RISC-V only */ QEMU_CAPS_DEVICE_VIRTIO_MEM_CCW, /* -device virtio-mem-ccw */ QEMU_CAPS_BLOCKDEV_SET_ACTIVE, /* blockdev-set-active QMP command supported */ + QEMU_CAPS_MACHINE_SHIM, /* -shim command line argument */ QEMU_CAPS_LAST /* this must always be the last item */ } virQEMUCapsFlags; diff --git a/tests/qemucapabilitiesdata/caps_10.0.0_s390x.xml b/tests/qemucapabilitiesdata/caps_10.0.0_s390x.xml index bccce19bfc..e0ad72d5d4 100644 --- a/tests/qemucapabilitiesdata/caps_10.0.0_s390x.xml +++ b/tests/qemucapabilitiesdata/caps_10.0.0_s390x.xml @@ -142,6 +142,7 @@ <flag name='query-cpu-model-expansion.deprecated-props'/> <flag name='migrate-incoming.exit-on-error'/> <flag name='virtio-mem-ccw'/> + <flag name='shim'/> <version>9002050</version> <microcodeVersion>39100285</microcodeVersion> <package>v9.2.0-1203-gd6430c17d7</package> diff --git a/tests/qemucapabilitiesdata/caps_10.0.0_x86_64.xml b/tests/qemucapabilitiesdata/caps_10.0.0_x86_64.xml index 358e06b803..115baf9e93 100644 --- a/tests/qemucapabilitiesdata/caps_10.0.0_x86_64.xml +++ b/tests/qemucapabilitiesdata/caps_10.0.0_x86_64.xml @@ -212,6 +212,7 @@ <flag name='netdev-stream-reconnect-miliseconds'/> <flag name='migrate-incoming.exit-on-error'/> <flag name='blockdev-set-active'/> + <flag name='shim'/> <version>9002050</version> <microcodeVersion>43100285</microcodeVersion> <package>v9.2.0-1967-gb69801dd6b</package> -- 2.45.3

If UEFI shim is specified in domain XML but QEMU is too old, then report an error. Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- src/qemu/qemu_validate.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/qemu/qemu_validate.c b/src/qemu/qemu_validate.c index f3ef1be660..6be8c29b75 100644 --- a/src/qemu/qemu_validate.c +++ b/src/qemu/qemu_validate.c @@ -740,6 +740,13 @@ qemuValidateDomainDefBoot(const virDomainDef *def, return -1; } + if (def->os.shim && + !virQEMUCapsGet(qemuCaps, QEMU_CAPS_MACHINE_SHIM)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("shim is not supported by this QEMU binary")); + return -1; + } + return 0; } -- 2.45.3

Trivial. Resolves: https://issues.redhat.com/browse/RHEL-68043 Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- src/qemu/qemu_command.c | 2 ++ .../launch-security-sev-direct.x86_64-latest.args | 1 + 2 files changed, 3 insertions(+) diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 0ad73af335..c3d1d8dd70 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -6026,6 +6026,8 @@ qemuBuildBootCommandLine(virCommand *cmd, virCommandAddArgList(cmd, "-initrd", def->os.initrd, NULL); if (def->os.cmdline) virCommandAddArgList(cmd, "-append", def->os.cmdline, NULL); + if (def->os.shim) + virCommandAddArgList(cmd, "-shim", def->os.shim, NULL); if (def->os.dtb) virCommandAddArgList(cmd, "-dtb", def->os.dtb, NULL); if (def->os.slic_table) { diff --git a/tests/qemuxmlconfdata/launch-security-sev-direct.x86_64-latest.args b/tests/qemuxmlconfdata/launch-security-sev-direct.x86_64-latest.args index 09df8a7cb6..33f820f5ad 100644 --- a/tests/qemuxmlconfdata/launch-security-sev-direct.x86_64-latest.args +++ b/tests/qemuxmlconfdata/launch-security-sev-direct.x86_64-latest.args @@ -29,6 +29,7 @@ XDG_CONFIG_HOME=/var/lib/libvirt/qemu/domain--1-QEMUGuest1/.config \ -kernel /vmlinuz \ -initrd /initrd \ -append runme \ +-shim /shim \ -device '{"driver":"piix3-usb-uhci","id":"usb","bus":"pci.0","addr":"0x1.0x2"}' \ -blockdev '{"driver":"host_device","filename":"/dev/HostVG/QEMUGuest1","node-name":"libvirt-1-storage","read-only":false}' \ -device '{"driver":"ide-hd","bus":"ide.0","unit":0,"drive":"libvirt-1-storage","id":"ide0-0-0","bootindex":1}' \ -- 2.45.3

Again, trivial. Just copy what is done for kernel and initrd. Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- src/security/security_dac.c | 10 ++++++++++ src/security/security_selinux.c | 9 +++++++++ src/security/virt-aa-helper.c | 4 ++++ 3 files changed, 23 insertions(+) diff --git a/src/security/security_dac.c b/src/security/security_dac.c index 0505f4e4a3..c3f747a14a 100644 --- a/src/security/security_dac.c +++ b/src/security/security_dac.c @@ -2046,6 +2046,10 @@ virSecurityDACRestoreAllLabel(virSecurityManager *mgr, virSecurityDACRestoreFileLabel(mgr, def->os.initrd) < 0) rc = -1; + if (def->os.shim && + virSecurityDACRestoreFileLabel(mgr, def->os.shim) < 0) + rc = -1; + if (def->os.dtb && virSecurityDACRestoreFileLabel(mgr, def->os.dtb) < 0) rc = -1; @@ -2294,6 +2298,12 @@ virSecurityDACSetAllLabel(virSecurityManager *mgr, user, group, true) < 0) return -1; + if (def->os.shim && + virSecurityDACSetOwnership(mgr, NULL, + def->os.shim, + user, group, true) < 0) + return -1; + if (def->os.dtb && virSecurityDACSetOwnership(mgr, NULL, def->os.dtb, diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c index cdc32d9b34..cf4283217d 100644 --- a/src/security/security_selinux.c +++ b/src/security/security_selinux.c @@ -3009,6 +3009,10 @@ virSecuritySELinuxRestoreAllLabel(virSecurityManager *mgr, virSecuritySELinuxRestoreFileLabel(mgr, def->os.initrd, true) < 0) rc = -1; + if (def->os.shim && + virSecuritySELinuxRestoreFileLabel(mgr, def->os.shim, true) < 0) + rc = -1; + if (def->os.dtb && virSecuritySELinuxRestoreFileLabel(mgr, def->os.dtb, true) < 0) rc = -1; @@ -3438,6 +3442,11 @@ virSecuritySELinuxSetAllLabel(virSecurityManager *mgr, data->content_context, true) < 0) return -1; + if (def->os.shim && + virSecuritySELinuxSetFilecon(mgr, def->os.shim, + data->content_context, true) < 0) + return -1; + if (def->os.dtb && virSecuritySELinuxSetFilecon(mgr, def->os.dtb, data->content_context, true) < 0) diff --git a/src/security/virt-aa-helper.c b/src/security/virt-aa-helper.c index c255b64f35..5b27bbd663 100644 --- a/src/security/virt-aa-helper.c +++ b/src/security/virt-aa-helper.c @@ -970,6 +970,10 @@ get_files(vahControl * ctl) if (vah_add_file(&buf, ctl->def->os.initrd, "r") != 0) goto cleanup; + if (ctl->def->os.shim) + if (vah_add_file(&buf, ctl->def->os.shim, "r") != 0) + goto cleanup; + if (ctl->def->os.dtb) if (vah_add_file(&buf, ctl->def->os.dtb, "r") != 0) goto cleanup; -- 2.45.3

On Thu, Mar 06, 2025 at 09:36:13AM +0100, Michal Privoznik wrote:
*** BLURB HERE ***
Michal Prívozník (5): conf: Introduce os/shim element qemu_capabilities: Introduce QEMU_CAPS_MACHINE_SHIM qemu_validate: Check whether UEFI shim is supported qemu_command: Generate cmd line for UEFI shim security: Set seclabels on UEFI shim
Reviewed-by: Pavel Hrdina <phrdina@redhat.com>
participants (2)
-
Michal Privoznik
-
Pavel Hrdina