[libvirt] [PATCH 0/5] Enable secure boot

We have UEFI enabled guests for a while now. But only recently qemu introduced secure boot. We should reflect that in our code too. Michal Privoznik (5): qemuBuildMachineCommandLine: Follow our pattern Introduce SMM feature Introduce @secure attribute to os loader element qemu: Enable secure boot qemu: Advertise OVMF_CODE.secboot.fd docs/formatdomain.html.in | 13 ++++- docs/schemas/domaincommon.rng | 17 +++++++ src/conf/domain_conf.c | 19 ++++++- src/conf/domain_conf.h | 2 + src/qemu/qemu_capabilities.c | 16 ++++++ src/qemu/qemu_capabilities.h | 4 ++ src/qemu/qemu_command.c | 58 ++++++++++++++-------- src/qemu/qemu_conf.c | 13 +++-- src/qemu/qemu_domain.c | 27 ++++++++++ tests/qemucapabilitiesdata/caps_2.4.0.x86_64.xml | 1 + tests/qemucapabilitiesdata/caps_2.5.0.x86_64.xml | 1 + .../caps_2.6.0-gicv2.aarch64.xml | 1 + .../caps_2.6.0-gicv3.aarch64.xml | 1 + tests/qemucapabilitiesdata/caps_2.6.0.ppc64le.xml | 1 + tests/qemucapabilitiesdata/caps_2.6.0.x86_64.xml | 1 + .../qemuxml2argv-bios-nvram-secure.args | 29 +++++++++++ .../qemuxml2argv-bios-nvram-secure.xml | 41 +++++++++++++++ .../qemuxml2argv-machine-smm-opt.args | 25 ++++++++++ .../qemuxml2argv-machine-smm-opt.xml | 28 +++++++++++ tests/qemuxml2argvtest.c | 14 ++++++ 20 files changed, 284 insertions(+), 28 deletions(-) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-bios-nvram-secure.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-bios-nvram-secure.xml create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-machine-smm-opt.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-machine-smm-opt.xml -- 2.8.4

We use 'goto cleanup' for a reason. If a function can exit at many places but doesn't follow the pattern, it has to copy the free code in multiple places. Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- src/qemu/qemu_command.c | 39 ++++++++++++++++++--------------------- 1 file changed, 18 insertions(+), 21 deletions(-) diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 3dc131b..6295eeb 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -6751,7 +6751,9 @@ qemuBuildMachineCommandLine(virCommandPtr cmd, const virDomainDef *def, virQEMUCapsPtr qemuCaps) { + virBuffer buf = VIR_BUFFER_INITIALIZER; bool obsoleteAccel = false; + int ret = -1; /* This should *never* be NULL, since we always provide * a machine in the capabilities data for QEMU. So this @@ -6776,7 +6778,7 @@ qemuBuildMachineCommandLine(virCommandPtr cmd, virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("disable shared memory is not available " "with this QEMU binary")); - return -1; + return -1; } obsoleteAccel = true; @@ -6788,7 +6790,6 @@ qemuBuildMachineCommandLine(virCommandPtr cmd, return -1; } } else { - virBuffer buf = VIR_BUFFER_INITIALIZER; virTristateSwitch vmport = def->features[VIR_DOMAIN_FEATURE_VMPORT]; virCommandAddArg(cmd, "-machine"); @@ -6812,8 +6813,7 @@ qemuBuildMachineCommandLine(virCommandPtr cmd, virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("vmport is not available " "with this QEMU binary")); - virBufferFreeAndReset(&buf); - return -1; + goto cleanup; } virBufferAsprintf(&buf, ",vmport=%s", @@ -6825,8 +6825,7 @@ qemuBuildMachineCommandLine(virCommandPtr cmd, virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("dump-guest-core is not available " "with this QEMU binary")); - virBufferFreeAndReset(&buf); - return -1; + goto cleanup; } virBufferAsprintf(&buf, ",dump-guest-core=%s", @@ -6834,22 +6833,19 @@ qemuBuildMachineCommandLine(virCommandPtr cmd, } if (def->mem.nosharepages) { - if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_MEM_MERGE)) { - virBufferAddLit(&buf, ",mem-merge=off"); - } else { + if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_MEM_MERGE)) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("disable shared memory is not available " "with this QEMU binary")); - virBufferFreeAndReset(&buf); - return -1; + goto cleanup; } + + virBufferAddLit(&buf, ",mem-merge=off"); } if (def->keywrap && - !qemuAppendKeyWrapMachineParms(&buf, qemuCaps, def->keywrap)) { - virBufferFreeAndReset(&buf); - return -1; - } + !qemuAppendKeyWrapMachineParms(&buf, qemuCaps, def->keywrap)) + goto cleanup; if (def->features[VIR_DOMAIN_FEATURE_GIC] == VIR_TRISTATE_SWITCH_ON) { if (def->gic_version != VIR_GIC_VERSION_NONE) { @@ -6857,8 +6853,7 @@ qemuBuildMachineCommandLine(virCommandPtr cmd, virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("gic-version option is available " "only for ARM virt machine")); - virBufferFreeAndReset(&buf); - return -1; + goto cleanup; } /* The default GIC version should not be specified on the @@ -6869,8 +6864,7 @@ qemuBuildMachineCommandLine(virCommandPtr cmd, virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("gic-version option is not available " "with this QEMU binary")); - virBufferFreeAndReset(&buf); - return -1; + goto cleanup; } virBufferAsprintf(&buf, ",gic-version=%s", @@ -6884,9 +6878,12 @@ qemuBuildMachineCommandLine(virCommandPtr cmd, if (obsoleteAccel && qemuBuildObsoleteAccelArg(cmd, def, qemuCaps) < 0) - return -1; + goto cleanup; - return 0; + ret = 0; + cleanup: + virBufferFreeAndReset(&buf); + return ret; } static int -- 2.8.4

On Wed, Jul 27, 2016 at 10:43:48AM +0200, Michal Privoznik wrote:
We use 'goto cleanup' for a reason. If a function can exit at many places but doesn't follow the pattern, it has to copy the free code in multiple places.
Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- src/qemu/qemu_command.c | 39 ++++++++++++++++++--------------------- 1 file changed, 18 insertions(+), 21 deletions(-)
ACK

Since its release of 2.4.0 qemu is able to enable System Management Module in the firmware, or disable it. We should expose this capability in the XML. Unfortunately, there's no good way to determine whether the binary we are talking to supports it. I mean, if qemu's run with real machine type, the smm attribute can be seen in 'qom-list /machine' output. But it's not there when qemu's run with -M none. Therefore we're stuck with version based check. Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- docs/formatdomain.html.in | 6 +++++ docs/schemas/domaincommon.rng | 9 +++++++ src/conf/domain_conf.c | 5 +++- src/conf/domain_conf.h | 1 + src/qemu/qemu_capabilities.c | 16 +++++++++++++ src/qemu/qemu_capabilities.h | 4 ++++ src/qemu/qemu_command.c | 12 ++++++++++ tests/qemucapabilitiesdata/caps_2.4.0.x86_64.xml | 1 + tests/qemucapabilitiesdata/caps_2.5.0.x86_64.xml | 1 + .../caps_2.6.0-gicv2.aarch64.xml | 1 + .../caps_2.6.0-gicv3.aarch64.xml | 1 + tests/qemucapabilitiesdata/caps_2.6.0.ppc64le.xml | 1 + tests/qemucapabilitiesdata/caps_2.6.0.x86_64.xml | 1 + .../qemuxml2argv-machine-smm-opt.args | 25 +++++++++++++++++++ .../qemuxml2argv-machine-smm-opt.xml | 28 ++++++++++++++++++++++ tests/qemuxml2argvtest.c | 7 ++++++ 16 files changed, 118 insertions(+), 1 deletion(-) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-machine-smm-opt.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-machine-smm-opt.xml diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in index 59a8bb9..3f67182 100644 --- a/docs/formatdomain.html.in +++ b/docs/formatdomain.html.in @@ -1655,6 +1655,12 @@ values are <code>2</code>, <code>3</code> and <code>host</code>. <span class="since">Since 1.2.16</span> </dd> + <dt><code>smm</code></dt> + <dd>Enable System Management Mode. Possible values are + <code>on</code> and <code>off</code>. The default is left + for hypervisor to decide. + <span class="since">Since 2.1.0</span> + </dd> </dl> <h3><a name="elementsTime">Time keeping</a></h3> diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index 741f268..39fcb7e 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -4291,6 +4291,15 @@ </optional> </element> </optional> + <optional> + <element name="smm"> + <optional> + <attribute name="state"> + <ref name="virOnOff"/> + </attribute> + </optional> + </element> + </optional> </interleave> </element> </optional> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 13e5dc9..3b6493e 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -137,7 +137,8 @@ VIR_ENUM_IMPL(virDomainFeature, VIR_DOMAIN_FEATURE_LAST, "capabilities", "pmu", "vmport", - "gic") + "gic", + "smm") VIR_ENUM_IMPL(virDomainCapabilitiesPolicy, VIR_DOMAIN_CAPABILITIES_POLICY_LAST, "default", @@ -16318,6 +16319,7 @@ virDomainDefParseXML(xmlDocPtr xml, case VIR_DOMAIN_FEATURE_PMU: case VIR_DOMAIN_FEATURE_PVSPINLOCK: case VIR_DOMAIN_FEATURE_VMPORT: + case VIR_DOMAIN_FEATURE_SMM: node = ctxt->node; ctxt->node = nodes[i]; if ((tmp = virXPathString("string(./@state)", ctxt))) { @@ -23291,6 +23293,7 @@ virDomainDefFormatInternal(virDomainDefPtr def, case VIR_DOMAIN_FEATURE_PMU: case VIR_DOMAIN_FEATURE_PVSPINLOCK: case VIR_DOMAIN_FEATURE_VMPORT: + case VIR_DOMAIN_FEATURE_SMM: switch ((virTristateSwitch) def->features[i]) { case VIR_TRISTATE_SWITCH_LAST: case VIR_TRISTATE_SWITCH_ABSENT: diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 3c2f182..60b4be5 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -1600,6 +1600,7 @@ typedef enum { VIR_DOMAIN_FEATURE_PMU, VIR_DOMAIN_FEATURE_VMPORT, VIR_DOMAIN_FEATURE_GIC, + VIR_DOMAIN_FEATURE_SMM, VIR_DOMAIN_FEATURE_LAST } virDomainFeature; diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index d5b73e6..0b36819 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -339,6 +339,7 @@ VIR_ENUM_IMPL(virQEMUCaps, QEMU_CAPS_LAST, "tls-creds-x509", /* 230 */ "display", "intel-iommu", + "smm", ); @@ -3533,6 +3534,10 @@ virQEMUCapsInitQMPMonitor(virQEMUCapsPtr qemuCaps, if (qemuCaps->version >= 2004000) virQEMUCapsSet(qemuCaps, QEMU_CAPS_VHOSTUSER_MULTIQUEUE); + /* smm option is supported from v2.4.0 */ + if (qemuCaps->version >= 2004000) + virQEMUCapsSet(qemuCaps, QEMU_CAPS_MACHINE_SMM_OPT); + /* Since 2.4.50 ARM virt machine supports gic-version option */ if (qemuCaps->version >= 2004050) virQEMUCapsSet(qemuCaps, QEMU_CAPS_MACH_VIRT_GIC_VERSION); @@ -4052,6 +4057,17 @@ virQEMUCapsSupportsVmport(virQEMUCapsPtr qemuCaps, bool +virQEMUCapsSupportsSMM(virQEMUCapsPtr qemuCaps, + const virDomainDef *def) +{ + if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_MACHINE_SMM_OPT)) + return false; + + return qemuDomainMachineIsQ35(def); +} + + +bool virQEMUCapsIsMachineSupported(virQEMUCapsPtr qemuCaps, const char *canonical_machine) { diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h index bd5c6d9..8c4bc95 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -372,6 +372,7 @@ typedef enum { QEMU_CAPS_OBJECT_TLS_CREDS_X509, /* -object tls-creds-x509 */ QEMU_CAPS_DISPLAY, /* -display */ QEMU_CAPS_DEVICE_INTEL_IOMMU, /* -device intel-iommu */ + QEMU_CAPS_MACHINE_SMM_OPT, /* -machine xxx,smm=on/off/auto */ QEMU_CAPS_LAST /* this must always be the last item */ } virQEMUCapsFlags; @@ -408,6 +409,9 @@ bool virQEMUCapsHasPCIMultiBus(virQEMUCapsPtr qemuCaps, bool virQEMUCapsSupportsVmport(virQEMUCapsPtr qemuCaps, const virDomainDef *def); +bool virQEMUCapsSupportsSMM(virQEMUCapsPtr qemuCaps, + const virDomainDef *def); + char *virQEMUCapsFlagsString(virQEMUCapsPtr qemuCaps); const char *virQEMUCapsGetBinary(virQEMUCapsPtr qemuCaps); diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 6295eeb..831aba1 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -6791,6 +6791,7 @@ qemuBuildMachineCommandLine(virCommandPtr cmd, } } else { virTristateSwitch vmport = def->features[VIR_DOMAIN_FEATURE_VMPORT]; + virTristateSwitch smm = def->features[VIR_DOMAIN_FEATURE_SMM]; virCommandAddArg(cmd, "-machine"); virBufferAdd(&buf, def->os.machine, -1); @@ -6820,6 +6821,17 @@ qemuBuildMachineCommandLine(virCommandPtr cmd, virTristateSwitchTypeToString(vmport)); } + if (smm) { + if (!virQEMUCapsSupportsSMM(qemuCaps, def)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("smm is not available with this QEMU binary")); + goto cleanup; + } + + virBufferAsprintf(&buf, ",smm=%s", + virTristateSwitchTypeToString(smm)); + } + if (def->mem.dump_core) { if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DUMP_GUEST_CORE)) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", diff --git a/tests/qemucapabilitiesdata/caps_2.4.0.x86_64.xml b/tests/qemucapabilitiesdata/caps_2.4.0.x86_64.xml index 80085d5..339ee1f 100644 --- a/tests/qemucapabilitiesdata/caps_2.4.0.x86_64.xml +++ b/tests/qemucapabilitiesdata/caps_2.4.0.x86_64.xml @@ -183,6 +183,7 @@ <flag name='drive-detect-zeroes'/> <flag name='display'/> <flag name='intel-iommu'/> + <flag name='smm'/> <version>2004000</version> <kvmVersion>0</kvmVersion> <package></package> diff --git a/tests/qemucapabilitiesdata/caps_2.5.0.x86_64.xml b/tests/qemucapabilitiesdata/caps_2.5.0.x86_64.xml index fad3291..c1a68d0 100644 --- a/tests/qemucapabilitiesdata/caps_2.5.0.x86_64.xml +++ b/tests/qemucapabilitiesdata/caps_2.5.0.x86_64.xml @@ -188,6 +188,7 @@ <flag name='tls-creds-x509'/> <flag name='display'/> <flag name='intel-iommu'/> + <flag name='smm'/> <version>2005000</version> <kvmVersion>0</kvmVersion> <package></package> diff --git a/tests/qemucapabilitiesdata/caps_2.6.0-gicv2.aarch64.xml b/tests/qemucapabilitiesdata/caps_2.6.0-gicv2.aarch64.xml index 4ed88bc..85d7d3f 100644 --- a/tests/qemucapabilitiesdata/caps_2.6.0-gicv2.aarch64.xml +++ b/tests/qemucapabilitiesdata/caps_2.6.0-gicv2.aarch64.xml @@ -157,6 +157,7 @@ <flag name='drive-detect-zeroes'/> <flag name='tls-creds-x509'/> <flag name='display'/> + <flag name='smm'/> <version>2005094</version> <kvmVersion>0</kvmVersion> <package></package> diff --git a/tests/qemucapabilitiesdata/caps_2.6.0-gicv3.aarch64.xml b/tests/qemucapabilitiesdata/caps_2.6.0-gicv3.aarch64.xml index 024596d..deb1257 100644 --- a/tests/qemucapabilitiesdata/caps_2.6.0-gicv3.aarch64.xml +++ b/tests/qemucapabilitiesdata/caps_2.6.0-gicv3.aarch64.xml @@ -157,6 +157,7 @@ <flag name='drive-detect-zeroes'/> <flag name='tls-creds-x509'/> <flag name='display'/> + <flag name='smm'/> <version>2005094</version> <kvmVersion>0</kvmVersion> <package></package> diff --git a/tests/qemucapabilitiesdata/caps_2.6.0.ppc64le.xml b/tests/qemucapabilitiesdata/caps_2.6.0.ppc64le.xml index e66433c..2b7ea0e 100644 --- a/tests/qemucapabilitiesdata/caps_2.6.0.ppc64le.xml +++ b/tests/qemucapabilitiesdata/caps_2.6.0.ppc64le.xml @@ -151,6 +151,7 @@ <flag name='drive-detect-zeroes'/> <flag name='tls-creds-x509'/> <flag name='display'/> + <flag name='smm'/> <version>2005094</version> <kvmVersion>0</kvmVersion> <package></package> diff --git a/tests/qemucapabilitiesdata/caps_2.6.0.x86_64.xml b/tests/qemucapabilitiesdata/caps_2.6.0.x86_64.xml index 653ec75..495c114 100644 --- a/tests/qemucapabilitiesdata/caps_2.6.0.x86_64.xml +++ b/tests/qemucapabilitiesdata/caps_2.6.0.x86_64.xml @@ -194,6 +194,7 @@ <flag name='tls-creds-x509'/> <flag name='display'/> <flag name='intel-iommu'/> + <flag name='smm'/> <version>2006000</version> <kvmVersion>0</kvmVersion> <package></package> diff --git a/tests/qemuxml2argvdata/qemuxml2argv-machine-smm-opt.args b/tests/qemuxml2argvdata/qemuxml2argv-machine-smm-opt.args new file mode 100644 index 0000000..e49d7e9 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-machine-smm-opt.args @@ -0,0 +1,25 @@ +LC_ALL=C \ +PATH=/bin \ +HOME=/home/test \ +USER=test \ +LOGNAME=test \ +QEMU_AUDIO_DRV=none \ +/usr/bin/qemu \ +-name QEMUGuest1 \ +-S \ +-machine q35,accel=tcg,smm=on \ +-m 214 \ +-smp 1,sockets=1,cores=1,threads=1 \ +-uuid c7a5fdbd-edaf-9455-926a-d65c16db1809 \ +-nographic \ +-nodefaults \ +-monitor unix:/tmp/lib/domain--1-QEMUGuest1/monitor.sock,server,nowait \ +-no-acpi \ +-boot c \ +-device i82801b11-bridge,id=pci.1,bus=pcie.0,addr=0x1e \ +-device pci-bridge,chassis_nr=2,id=pci.2,bus=pci.1,addr=0x0 \ +-device virtio-scsi-pci,id=scsi0,bus=pci.2,addr=0x1 \ +-drive file=/dev/HostVG/QEMUGuest1,format=raw,if=none,id=drive-scsi0-0-0-0 \ +-device scsi-disk,bus=scsi0.0,channel=0,scsi-id=0,lun=0,\ +drive=drive-scsi0-0-0-0,id=scsi0-0-0-0 \ +-device virtio-balloon-pci,id=balloon0,bus=pci.2,addr=0x2 diff --git a/tests/qemuxml2argvdata/qemuxml2argv-machine-smm-opt.xml b/tests/qemuxml2argvdata/qemuxml2argv-machine-smm-opt.xml new file mode 100644 index 0000000..b964b5e --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-machine-smm-opt.xml @@ -0,0 +1,28 @@ +<domain type='qemu'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory unit='KiB'>219100</memory> + <currentMemory unit='KiB'>219100</currentMemory> + <vcpu placement='static'>1</vcpu> + <os> + <type arch='x86_64' machine='q35'>hvm</type> + <boot dev='hd'/> + </os> + <features> + <smm state='on'/> + </features> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu</emulator> + <disk type='block' device='disk'> + <source dev='/dev/HostVG/QEMUGuest1'/> + <target dev='sda' bus='scsi'/> + <address type='drive' controller='0' bus='0' target='0' unit='0'/> + </disk> + <controller type='scsi' index='0'/> + <memballoon model='virtio'/> + </devices> +</domain> diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index a5d51a8..f9588d5 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -618,6 +618,13 @@ mymain(void) QEMU_CAPS_DUMP_GUEST_CORE); DO_TEST_FAILURE("machine-core-on", NONE); DO_TEST_FAILURE("machine-core-on", QEMU_CAPS_MACHINE_OPT); + DO_TEST("machine-smm-opt", + QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE, + QEMU_CAPS_DEVICE_PCI_BRIDGE, + QEMU_CAPS_ICH9_AHCI, + QEMU_CAPS_MACHINE_OPT, + QEMU_CAPS_MACHINE_SMM_OPT, + QEMU_CAPS_VIRTIO_SCSI); DO_TEST("machine-usb-opt", QEMU_CAPS_MACHINE_OPT, QEMU_CAPS_MACHINE_USB_OPT); DO_TEST("machine-vmport-opt", QEMU_CAPS_MACHINE_OPT, -- 2.8.4

Hi Michal, thanks a lot for posting this. One question: On 07/27/16 10:43, Michal Privoznik wrote:
Since its release of 2.4.0 qemu is able to enable System Management Module in the firmware, or disable it. We should expose this capability in the XML. Unfortunately, there's no good way to determine whether the binary we are talking to supports it. I mean, if qemu's run with real machine type, the smm attribute can be seen in 'qom-list /machine' output. But it's not there when qemu's run with -M none. Therefore we're stuck with version based check.
Where does your information come from that says QEMU 2.4 is good enough for this? To my knowledge, the pc-q35-2.5 machine type is minimally required, i.e., no i440fx at all, and for q35, 2.5 or later, which can only be provided by QEMU v2.5.0 or later. Hmmm... I found QEMU commit 355023f2010c4 ("pc: add SMM property"), and it's indeed part of v2.4.0. I wonder where *I* got the information from that only pc-q35-2.5+ machtypes are suitable for SMM (as OVMF needs it). Perhaps there were other requirements too (SMRAM emulation etc). Ah, wait, *large* SMRAM (T-SEG) is Q35-only. The SMM property is available on i440fx as well. Hm, even Paolo's presentation ("Securing secure boot with System Management Mode") mentions "QEMU: released in 2.4". ... Ah, I think I might now why. In this RHBZ: https://bugzilla.redhat.com/show_bug.cgi?id=1202822 Gerd set
Gerd Hoffmann 2016-03-21 08:23:06 CET Fixed In Version: qemu-2.5
I checked git log --no-merges --oneline --reverse v2.4.0..v2.5.0 but nothing says "smm", "smram", or "tseg" (case-insensitively). I recall commit bafc90bdc594 ("q35: implement TSEG") as one of Gerd's QEMU patches, but that's also part of v2.4.0. Confirmed by: <http://wiki.qemu.org/ChangeLog/2.4#x86>. ... Gerd's above metadata change is dated 2016-03-21, at which point both QEMU v2.4.0 and v2.5.0 had been tagged (on 2015-08-11 and on 2015-12-16, respectively). I guess Gerd may have mis-remembered the exact QEMU release which included SMM support? I don't remember ever testing SMM (using OVMF) with released 2.4 machine types, so I feel a bit uncertain about mentioning and looking for 2.4 in this patch. ... Anyway, looking over your patch quickly, I think it really only concerns itself with "-machine smm=on", and for that, the 2.4 version check should suffice. It's only OVMF that needs a lot more than that. Acked-by: Laszlo Ersek <lersek@redhat.com> Thanks! Laszlo
Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- docs/formatdomain.html.in | 6 +++++ docs/schemas/domaincommon.rng | 9 +++++++ src/conf/domain_conf.c | 5 +++- src/conf/domain_conf.h | 1 + src/qemu/qemu_capabilities.c | 16 +++++++++++++ src/qemu/qemu_capabilities.h | 4 ++++ src/qemu/qemu_command.c | 12 ++++++++++ tests/qemucapabilitiesdata/caps_2.4.0.x86_64.xml | 1 + tests/qemucapabilitiesdata/caps_2.5.0.x86_64.xml | 1 + .../caps_2.6.0-gicv2.aarch64.xml | 1 + .../caps_2.6.0-gicv3.aarch64.xml | 1 + tests/qemucapabilitiesdata/caps_2.6.0.ppc64le.xml | 1 + tests/qemucapabilitiesdata/caps_2.6.0.x86_64.xml | 1 + .../qemuxml2argv-machine-smm-opt.args | 25 +++++++++++++++++++ .../qemuxml2argv-machine-smm-opt.xml | 28 ++++++++++++++++++++++ tests/qemuxml2argvtest.c | 7 ++++++ 16 files changed, 118 insertions(+), 1 deletion(-) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-machine-smm-opt.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-machine-smm-opt.xml
diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in index 59a8bb9..3f67182 100644 --- a/docs/formatdomain.html.in +++ b/docs/formatdomain.html.in @@ -1655,6 +1655,12 @@ values are <code>2</code>, <code>3</code> and <code>host</code>. <span class="since">Since 1.2.16</span> </dd> + <dt><code>smm</code></dt> + <dd>Enable System Management Mode. Possible values are + <code>on</code> and <code>off</code>. The default is left + for hypervisor to decide. + <span class="since">Since 2.1.0</span> + </dd> </dl>
<h3><a name="elementsTime">Time keeping</a></h3> diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index 741f268..39fcb7e 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -4291,6 +4291,15 @@ </optional> </element> </optional> + <optional> + <element name="smm"> + <optional> + <attribute name="state"> + <ref name="virOnOff"/> + </attribute> + </optional> + </element> + </optional> </interleave> </element> </optional> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 13e5dc9..3b6493e 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -137,7 +137,8 @@ VIR_ENUM_IMPL(virDomainFeature, VIR_DOMAIN_FEATURE_LAST, "capabilities", "pmu", "vmport", - "gic") + "gic", + "smm")
VIR_ENUM_IMPL(virDomainCapabilitiesPolicy, VIR_DOMAIN_CAPABILITIES_POLICY_LAST, "default", @@ -16318,6 +16319,7 @@ virDomainDefParseXML(xmlDocPtr xml, case VIR_DOMAIN_FEATURE_PMU: case VIR_DOMAIN_FEATURE_PVSPINLOCK: case VIR_DOMAIN_FEATURE_VMPORT: + case VIR_DOMAIN_FEATURE_SMM: node = ctxt->node; ctxt->node = nodes[i]; if ((tmp = virXPathString("string(./@state)", ctxt))) { @@ -23291,6 +23293,7 @@ virDomainDefFormatInternal(virDomainDefPtr def, case VIR_DOMAIN_FEATURE_PMU: case VIR_DOMAIN_FEATURE_PVSPINLOCK: case VIR_DOMAIN_FEATURE_VMPORT: + case VIR_DOMAIN_FEATURE_SMM: switch ((virTristateSwitch) def->features[i]) { case VIR_TRISTATE_SWITCH_LAST: case VIR_TRISTATE_SWITCH_ABSENT: diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 3c2f182..60b4be5 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -1600,6 +1600,7 @@ typedef enum { VIR_DOMAIN_FEATURE_PMU, VIR_DOMAIN_FEATURE_VMPORT, VIR_DOMAIN_FEATURE_GIC, + VIR_DOMAIN_FEATURE_SMM,
VIR_DOMAIN_FEATURE_LAST } virDomainFeature; diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index d5b73e6..0b36819 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -339,6 +339,7 @@ VIR_ENUM_IMPL(virQEMUCaps, QEMU_CAPS_LAST, "tls-creds-x509", /* 230 */ "display", "intel-iommu", + "smm", );
@@ -3533,6 +3534,10 @@ virQEMUCapsInitQMPMonitor(virQEMUCapsPtr qemuCaps, if (qemuCaps->version >= 2004000) virQEMUCapsSet(qemuCaps, QEMU_CAPS_VHOSTUSER_MULTIQUEUE);
+ /* smm option is supported from v2.4.0 */ + if (qemuCaps->version >= 2004000) + virQEMUCapsSet(qemuCaps, QEMU_CAPS_MACHINE_SMM_OPT); + /* Since 2.4.50 ARM virt machine supports gic-version option */ if (qemuCaps->version >= 2004050) virQEMUCapsSet(qemuCaps, QEMU_CAPS_MACH_VIRT_GIC_VERSION); @@ -4052,6 +4057,17 @@ virQEMUCapsSupportsVmport(virQEMUCapsPtr qemuCaps,
bool +virQEMUCapsSupportsSMM(virQEMUCapsPtr qemuCaps, + const virDomainDef *def) +{ + if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_MACHINE_SMM_OPT)) + return false; + + return qemuDomainMachineIsQ35(def); +} + + +bool virQEMUCapsIsMachineSupported(virQEMUCapsPtr qemuCaps, const char *canonical_machine) { diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h index bd5c6d9..8c4bc95 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -372,6 +372,7 @@ typedef enum { QEMU_CAPS_OBJECT_TLS_CREDS_X509, /* -object tls-creds-x509 */ QEMU_CAPS_DISPLAY, /* -display */ QEMU_CAPS_DEVICE_INTEL_IOMMU, /* -device intel-iommu */ + QEMU_CAPS_MACHINE_SMM_OPT, /* -machine xxx,smm=on/off/auto */
QEMU_CAPS_LAST /* this must always be the last item */ } virQEMUCapsFlags; @@ -408,6 +409,9 @@ bool virQEMUCapsHasPCIMultiBus(virQEMUCapsPtr qemuCaps, bool virQEMUCapsSupportsVmport(virQEMUCapsPtr qemuCaps, const virDomainDef *def);
+bool virQEMUCapsSupportsSMM(virQEMUCapsPtr qemuCaps, + const virDomainDef *def); + char *virQEMUCapsFlagsString(virQEMUCapsPtr qemuCaps);
const char *virQEMUCapsGetBinary(virQEMUCapsPtr qemuCaps); diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 6295eeb..831aba1 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -6791,6 +6791,7 @@ qemuBuildMachineCommandLine(virCommandPtr cmd, } } else { virTristateSwitch vmport = def->features[VIR_DOMAIN_FEATURE_VMPORT]; + virTristateSwitch smm = def->features[VIR_DOMAIN_FEATURE_SMM];
virCommandAddArg(cmd, "-machine"); virBufferAdd(&buf, def->os.machine, -1); @@ -6820,6 +6821,17 @@ qemuBuildMachineCommandLine(virCommandPtr cmd, virTristateSwitchTypeToString(vmport)); }
+ if (smm) { + if (!virQEMUCapsSupportsSMM(qemuCaps, def)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("smm is not available with this QEMU binary")); + goto cleanup; + } + + virBufferAsprintf(&buf, ",smm=%s", + virTristateSwitchTypeToString(smm)); + } + if (def->mem.dump_core) { if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DUMP_GUEST_CORE)) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", diff --git a/tests/qemucapabilitiesdata/caps_2.4.0.x86_64.xml b/tests/qemucapabilitiesdata/caps_2.4.0.x86_64.xml index 80085d5..339ee1f 100644 --- a/tests/qemucapabilitiesdata/caps_2.4.0.x86_64.xml +++ b/tests/qemucapabilitiesdata/caps_2.4.0.x86_64.xml @@ -183,6 +183,7 @@ <flag name='drive-detect-zeroes'/> <flag name='display'/> <flag name='intel-iommu'/> + <flag name='smm'/> <version>2004000</version> <kvmVersion>0</kvmVersion> <package></package> diff --git a/tests/qemucapabilitiesdata/caps_2.5.0.x86_64.xml b/tests/qemucapabilitiesdata/caps_2.5.0.x86_64.xml index fad3291..c1a68d0 100644 --- a/tests/qemucapabilitiesdata/caps_2.5.0.x86_64.xml +++ b/tests/qemucapabilitiesdata/caps_2.5.0.x86_64.xml @@ -188,6 +188,7 @@ <flag name='tls-creds-x509'/> <flag name='display'/> <flag name='intel-iommu'/> + <flag name='smm'/> <version>2005000</version> <kvmVersion>0</kvmVersion> <package></package> diff --git a/tests/qemucapabilitiesdata/caps_2.6.0-gicv2.aarch64.xml b/tests/qemucapabilitiesdata/caps_2.6.0-gicv2.aarch64.xml index 4ed88bc..85d7d3f 100644 --- a/tests/qemucapabilitiesdata/caps_2.6.0-gicv2.aarch64.xml +++ b/tests/qemucapabilitiesdata/caps_2.6.0-gicv2.aarch64.xml @@ -157,6 +157,7 @@ <flag name='drive-detect-zeroes'/> <flag name='tls-creds-x509'/> <flag name='display'/> + <flag name='smm'/> <version>2005094</version> <kvmVersion>0</kvmVersion> <package></package> diff --git a/tests/qemucapabilitiesdata/caps_2.6.0-gicv3.aarch64.xml b/tests/qemucapabilitiesdata/caps_2.6.0-gicv3.aarch64.xml index 024596d..deb1257 100644 --- a/tests/qemucapabilitiesdata/caps_2.6.0-gicv3.aarch64.xml +++ b/tests/qemucapabilitiesdata/caps_2.6.0-gicv3.aarch64.xml @@ -157,6 +157,7 @@ <flag name='drive-detect-zeroes'/> <flag name='tls-creds-x509'/> <flag name='display'/> + <flag name='smm'/> <version>2005094</version> <kvmVersion>0</kvmVersion> <package></package> diff --git a/tests/qemucapabilitiesdata/caps_2.6.0.ppc64le.xml b/tests/qemucapabilitiesdata/caps_2.6.0.ppc64le.xml index e66433c..2b7ea0e 100644 --- a/tests/qemucapabilitiesdata/caps_2.6.0.ppc64le.xml +++ b/tests/qemucapabilitiesdata/caps_2.6.0.ppc64le.xml @@ -151,6 +151,7 @@ <flag name='drive-detect-zeroes'/> <flag name='tls-creds-x509'/> <flag name='display'/> + <flag name='smm'/> <version>2005094</version> <kvmVersion>0</kvmVersion> <package></package> diff --git a/tests/qemucapabilitiesdata/caps_2.6.0.x86_64.xml b/tests/qemucapabilitiesdata/caps_2.6.0.x86_64.xml index 653ec75..495c114 100644 --- a/tests/qemucapabilitiesdata/caps_2.6.0.x86_64.xml +++ b/tests/qemucapabilitiesdata/caps_2.6.0.x86_64.xml @@ -194,6 +194,7 @@ <flag name='tls-creds-x509'/> <flag name='display'/> <flag name='intel-iommu'/> + <flag name='smm'/> <version>2006000</version> <kvmVersion>0</kvmVersion> <package></package> diff --git a/tests/qemuxml2argvdata/qemuxml2argv-machine-smm-opt.args b/tests/qemuxml2argvdata/qemuxml2argv-machine-smm-opt.args new file mode 100644 index 0000000..e49d7e9 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-machine-smm-opt.args @@ -0,0 +1,25 @@ +LC_ALL=C \ +PATH=/bin \ +HOME=/home/test \ +USER=test \ +LOGNAME=test \ +QEMU_AUDIO_DRV=none \ +/usr/bin/qemu \ +-name QEMUGuest1 \ +-S \ +-machine q35,accel=tcg,smm=on \ +-m 214 \ +-smp 1,sockets=1,cores=1,threads=1 \ +-uuid c7a5fdbd-edaf-9455-926a-d65c16db1809 \ +-nographic \ +-nodefaults \ +-monitor unix:/tmp/lib/domain--1-QEMUGuest1/monitor.sock,server,nowait \ +-no-acpi \ +-boot c \ +-device i82801b11-bridge,id=pci.1,bus=pcie.0,addr=0x1e \ +-device pci-bridge,chassis_nr=2,id=pci.2,bus=pci.1,addr=0x0 \ +-device virtio-scsi-pci,id=scsi0,bus=pci.2,addr=0x1 \ +-drive file=/dev/HostVG/QEMUGuest1,format=raw,if=none,id=drive-scsi0-0-0-0 \ +-device scsi-disk,bus=scsi0.0,channel=0,scsi-id=0,lun=0,\ +drive=drive-scsi0-0-0-0,id=scsi0-0-0-0 \ +-device virtio-balloon-pci,id=balloon0,bus=pci.2,addr=0x2 diff --git a/tests/qemuxml2argvdata/qemuxml2argv-machine-smm-opt.xml b/tests/qemuxml2argvdata/qemuxml2argv-machine-smm-opt.xml new file mode 100644 index 0000000..b964b5e --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-machine-smm-opt.xml @@ -0,0 +1,28 @@ +<domain type='qemu'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory unit='KiB'>219100</memory> + <currentMemory unit='KiB'>219100</currentMemory> + <vcpu placement='static'>1</vcpu> + <os> + <type arch='x86_64' machine='q35'>hvm</type> + <boot dev='hd'/> + </os> + <features> + <smm state='on'/> + </features> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu</emulator> + <disk type='block' device='disk'> + <source dev='/dev/HostVG/QEMUGuest1'/> + <target dev='sda' bus='scsi'/> + <address type='drive' controller='0' bus='0' target='0' unit='0'/> + </disk> + <controller type='scsi' index='0'/> + <memballoon model='virtio'/> + </devices> +</domain> diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index a5d51a8..f9588d5 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -618,6 +618,13 @@ mymain(void) QEMU_CAPS_DUMP_GUEST_CORE); DO_TEST_FAILURE("machine-core-on", NONE); DO_TEST_FAILURE("machine-core-on", QEMU_CAPS_MACHINE_OPT); + DO_TEST("machine-smm-opt", + QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE, + QEMU_CAPS_DEVICE_PCI_BRIDGE, + QEMU_CAPS_ICH9_AHCI, + QEMU_CAPS_MACHINE_OPT, + QEMU_CAPS_MACHINE_SMM_OPT, + QEMU_CAPS_VIRTIO_SCSI); DO_TEST("machine-usb-opt", QEMU_CAPS_MACHINE_OPT, QEMU_CAPS_MACHINE_USB_OPT); DO_TEST("machine-vmport-opt", QEMU_CAPS_MACHINE_OPT,

Hi,
... Gerd's above metadata change is dated 2016-03-21, at which point both QEMU v2.4.0 and v2.5.0 had been tagged (on 2015-08-11 and on 2015-12-16, respectively). I guess Gerd may have mis-remembered the exact QEMU release which included SMM support?
Either that, or because some of the bits needed for secure boot didn't made it into 2.4 (and secure boot being *the* use case for smm emulation).
... Anyway, looking over your patch quickly, I think it really only concerns itself with "-machine smm=on", and for that, the 2.4 version check should suffice. It's only OVMF that needs a lot more than that.
Well, in kvm mode there is also a kernel support for smm required ... cheers, Gerd

On 08/01/16 14:28, Gerd Hoffmann wrote:
Hi,
... Gerd's above metadata change is dated 2016-03-21, at which point both QEMU v2.4.0 and v2.5.0 had been tagged (on 2015-08-11 and on 2015-12-16, respectively). I guess Gerd may have mis-remembered the exact QEMU release which included SMM support?
Either that, or because some of the bits needed for secure boot didn't made it into 2.4 (and secure boot being *the* use case for smm emulation).
Good point.
... Anyway, looking over your patch quickly, I think it really only concerns itself with "-machine smm=on", and for that, the 2.4 version check should suffice. It's only OVMF that needs a lot more than that.
Well, in kvm mode there is also a kernel support for smm required ...
Indeed; I just assumed libvirt didn't try to confirm host kernel (KVM) features as well. If it does, then the host kernel should be 4.4 or later. (If we want to capture version numbers, then for each minor release, the latest patch level should be required: 4.4.16, 4.5.7, 4.6.5, 4.7.0, because there have been a number of KVM tweaks and stable backports for SMM support.) Thanks Laszlo

Hi,
If it does, then the host kernel should be 4.4 or later. (If we want to capture version numbers, then for each minor release, the latest patch level should be required: 4.4.16, 4.5.7, 4.6.5, 4.7.0, because there have been a number of KVM tweaks and stable backports for SMM support.)
Better check /dev/kvm for the KVM_CAP_X86_SMM capability, otherwise the rhel-7 kernel is out even though smm is backported. Probably libvirt already has checks for other caps so it should be easy. cheers, Gerd

On 08/01/16 19:05, Gerd Hoffmann wrote:
Hi,
If it does, then the host kernel should be 4.4 or later. (If we want to capture version numbers, then for each minor release, the latest patch level should be required: 4.4.16, 4.5.7, 4.6.5, 4.7.0, because there have been a number of KVM tweaks and stable backports for SMM support.)
Better check /dev/kvm for the KVM_CAP_X86_SMM capability, otherwise the rhel-7 kernel is out even though smm is backported.
Probably libvirt already has checks for other caps so it should be easy.
The problem is that KVM_CAP_X86_SMM does not guarantee that all the tricky bugfixes are present in the host kernel. Laszlo

On 01.08.2016 21:10, Laszlo Ersek wrote:
On 08/01/16 19:05, Gerd Hoffmann wrote:
Hi,
If it does, then the host kernel should be 4.4 or later. (If we want to capture version numbers, then for each minor release, the latest patch level should be required: 4.4.16, 4.5.7, 4.6.5, 4.7.0, because there have been a number of KVM tweaks and stable backports for SMM support.)
Better check /dev/kvm for the KVM_CAP_X86_SMM capability, otherwise the rhel-7 kernel is out even though smm is backported.
Probably libvirt already has checks for other caps so it should be easy.
The problem is that KVM_CAP_X86_SMM does not guarantee that all the tricky bugfixes are present in the host kernel.
Moreover, libvirt does not validate nor check guest kernel. And the only /dev/kvm/ caps we check are: KVM_CAP_IOMMU - to see if legacy PCI passthrough works KVM_CAP_PPC_SMT - KVM_CAP_MAX_VCPUS - KVM_CAP_NR_VCPUS - for some vCPUs counts I don't think libvirt should check for KVM_CAP_x86_SMM. I mean, if we go down the rabbit hole, libvirt would have to check everything. The buck has to stop somewhere. Michal

On 08/02/16 10:58, Michal Privoznik wrote:
On 01.08.2016 21:10, Laszlo Ersek wrote:
On 08/01/16 19:05, Gerd Hoffmann wrote:
Hi,
If it does, then the host kernel should be 4.4 or later. (If we want to capture version numbers, then for each minor release, the latest patch level should be required: 4.4.16, 4.5.7, 4.6.5, 4.7.0, because there have been a number of KVM tweaks and stable backports for SMM support.)
Better check /dev/kvm for the KVM_CAP_X86_SMM capability, otherwise the rhel-7 kernel is out even though smm is backported.
Probably libvirt already has checks for other caps so it should be easy.
The problem is that KVM_CAP_X86_SMM does not guarantee that all the tricky bugfixes are present in the host kernel.
Moreover, libvirt does not validate nor check guest kernel. And the only /dev/kvm/ caps we check are:
KVM_CAP_IOMMU - to see if legacy PCI passthrough works
KVM_CAP_PPC_SMT - KVM_CAP_MAX_VCPUS - KVM_CAP_NR_VCPUS - for some vCPUs counts
I don't think libvirt should check for KVM_CAP_x86_SMM. I mean, if we go down the rabbit hole, libvirt would have to check everything. The buck has to stop somewhere.
I agree. Thanks Laszlo

On Wed, Jul 27, 2016 at 10:43:49AM +0200, Michal Privoznik wrote:
Since its release of 2.4.0 qemu is able to enable System Management Module in the firmware, or disable it. We should expose this capability in the XML. Unfortunately, there's no good way to determine whether the binary we are talking to supports it. I mean, if qemu's run with real machine type, the smm attribute can be seen in 'qom-list /machine' output. But it's not there when qemu's run with -M none. Therefore we're stuck with version based check.
Signed-off-by: Michal Privoznik <mprivozn@redhat.com> ---
Based on the discussion qemu 2.4.0 is the correct version to check for SMM support. ACK

This element will control secure boot implemented by some firmwares. If the firmware used in <loader/> does support the feature we must tell it to the underlying hypervisor. However, we can't know whether loader does support it or not just by looking at the file. Therefore we have to have an attribute to the element where users can tell us whether the firmware is secure boot enabled or not. Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- docs/formatdomain.html.in | 7 ++-- docs/schemas/domaincommon.rng | 8 +++++ src/conf/domain_conf.c | 14 ++++++++ src/conf/domain_conf.h | 1 + .../qemuxml2argv-bios-nvram-secure.xml | 41 ++++++++++++++++++++++ 5 files changed, 69 insertions(+), 2 deletions(-) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-bios-nvram-secure.xml diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in index 3f67182..102ae55 100644 --- a/docs/formatdomain.html.in +++ b/docs/formatdomain.html.in @@ -102,7 +102,7 @@ ... <os> <type>hvm</type> - <loader readonly='yes' type='rom'>/usr/lib/xen/boot/hvmloader</loader> + <loader readonly='yes' secure='no' type='rom'>/usr/lib/xen/boot/hvmloader</loader> <nvram template='/usr/share/OVMF/OVMF_VARS.fd'>/var/lib/libvirt/nvram/guest_VARS.fd</nvram> <boot dev='hd'/> <boot dev='cdrom'/> @@ -140,7 +140,10 @@ <code>pflash</code>. It tells the hypervisor where in the guest memory the file should be mapped. For instance, if the loader path points to an UEFI image, <code>type</code> should be - <code>pflash</code>.</dd> + <code>pflash</code>. Moreover, some firmwares may + implement the Secure boot feature. Attribute + <code>secure</code> can be used then to control it. + <span class="since">Since 2.1.0</span></dd> <dt><code>nvram</code></dt> <dd>Some UEFI firmwares may want to use a non-volatile memory to store some variables. In the host, this is represented as a file and the diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index 39fcb7e..c5a263b 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -260,6 +260,14 @@ </attribute> </optional> <optional> + <attribute name="secure"> + <choice> + <value>yes</value> + <value>no</value> + </choice> + </attribute> + </optional> + <optional> <attribute name="type"> <choice> <value>rom</value> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 3b6493e..e0ecca3 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -15327,9 +15327,11 @@ virDomainLoaderDefParseXML(xmlNodePtr node, { int ret = -1; char *readonly_str = NULL; + char *secure_str = NULL; char *type_str = NULL; readonly_str = virXMLPropString(node, "readonly"); + secure_str = virXMLPropString(node, "secure"); type_str = virXMLPropString(node, "type"); loader->path = (char *) xmlNodeGetContent(node); @@ -15340,6 +15342,13 @@ virDomainLoaderDefParseXML(xmlNodePtr node, goto cleanup; } + if (secure_str && + (loader->secure = virTristateBoolTypeFromString(secure_str)) <= 0) { + virReportError(VIR_ERR_XML_DETAIL, + _("unknown secure value: %s"), secure_str); + goto cleanup; + } + if (type_str) { int type; if ((type = virDomainLoaderTypeFromString(type_str)) < 0) { @@ -15353,6 +15362,7 @@ virDomainLoaderDefParseXML(xmlNodePtr node, ret = 0; cleanup: VIR_FREE(readonly_str); + VIR_FREE(secure_str); VIR_FREE(type_str); return ret; } @@ -22521,6 +22531,7 @@ virDomainLoaderDefFormat(virBufferPtr buf, virDomainLoaderDefPtr loader) { const char *readonly = virTristateBoolTypeToString(loader->readonly); + const char *secure = virTristateBoolTypeToString(loader->secure); const char *type = virDomainLoaderTypeToString(loader->type); virBufferAddLit(buf, "<loader"); @@ -22528,6 +22539,9 @@ virDomainLoaderDefFormat(virBufferPtr buf, if (loader->readonly) virBufferAsprintf(buf, " readonly='%s'", readonly); + if (loader->secure) + virBufferAsprintf(buf, " secure='%s'", secure); + virBufferAsprintf(buf, " type='%s'>", type); virBufferEscapeString(buf, "%s</loader>\n", loader->path); diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 60b4be5..9c63257 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -1733,6 +1733,7 @@ struct _virDomainLoaderDef { char *path; int readonly; /* enum virTristateBool */ virDomainLoader type; + int secure; /* enum virTristateBool */ char *nvram; /* path to non-volatile RAM */ char *templt; /* user override of path to master nvram */ }; diff --git a/tests/qemuxml2argvdata/qemuxml2argv-bios-nvram-secure.xml b/tests/qemuxml2argvdata/qemuxml2argv-bios-nvram-secure.xml new file mode 100644 index 0000000..0ddddfe3 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-bios-nvram-secure.xml @@ -0,0 +1,41 @@ +<domain type='qemu'> + <name>test-bios</name> + <uuid>362d1fc1-df7d-193e-5c18-49a71bd1da66</uuid> + <memory unit='KiB'>1048576</memory> + <currentMemory unit='KiB'>1048576</currentMemory> + <vcpu placement='static'>1</vcpu> + <os> + <type arch='x86_64' machine='pc-q35-2.5'>hvm</type> + <loader readonly='yes' secure='yes' type='pflash'>/usr/share/OVMF/OVMF_CODE.secboot.fd</loader> + <nvram>/usr/share/OVMF/OVMF_VARS.fd</nvram> + <boot dev='hd'/> + <bootmenu enable='yes'/> + </os> + <features> + <acpi/> + <smm state='on'/> + </features> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>restart</on_crash> + <devices> + <emulator>/usr/bin/qemu</emulator> + <disk type='block' device='disk'> + <source dev='/dev/HostVG/QEMUGuest1'/> + <target dev='sda' bus='scsi'/> + <address type='drive' controller='0' bus='0' target='0' unit='0'/> + </disk> + <controller type='scsi' index='0'/> + <controller type='pci' index='0' model='pcie-root'/> + <serial type='pty'> + <target port='0'/> + </serial> + <console type='pty'> + <target type='serial' port='0'/> + </console> + <input type='mouse' bus='ps2'/> + <input type='keyboard' bus='ps2'/> + <memballoon model='virtio'/> + </devices> +</domain> -- 2.8.4

On Wed, Jul 27, 2016 at 10:43:50AM +0200, Michal Privoznik wrote:
This element will control secure boot implemented by some firmwares. If the firmware used in <loader/> does support the feature we must tell it to the underlying hypervisor. However, we can't know whether loader does support it or not just by looking at the file. Therefore we have to have an attribute to the element where users can tell us whether the firmware is secure boot enabled or not.
Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- docs/formatdomain.html.in | 7 ++-- docs/schemas/domaincommon.rng | 8 +++++ src/conf/domain_conf.c | 14 ++++++++ src/conf/domain_conf.h | 1 + .../qemuxml2argv-bios-nvram-secure.xml | 41 ++++++++++++++++++++++
This XML file should be part of the next patch. ACK

On 04.08.2016 12:19, Pavel Hrdina wrote:
On Wed, Jul 27, 2016 at 10:43:50AM +0200, Michal Privoznik wrote:
This element will control secure boot implemented by some firmwares. If the firmware used in <loader/> does support the feature we must tell it to the underlying hypervisor. However, we can't know whether loader does support it or not just by looking at the file. Therefore we have to have an attribute to the element where users can tell us whether the firmware is secure boot enabled or not.
Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- docs/formatdomain.html.in | 7 ++-- docs/schemas/domaincommon.rng | 8 +++++ src/conf/domain_conf.c | 14 ++++++++ src/conf/domain_conf.h | 1 + .../qemuxml2argv-bios-nvram-secure.xml | 41 ++++++++++++++++++++++
This XML file should be part of the next patch.
In fact, I always thought that XML test files should go hand in hand with our parser/formatter & schema changes. I mean, the .xml file I'm introducing is checked to be compliant with the RNG schema. I think the XML file can be viewed as a test for RNG schema change. Michal

On Thu, Aug 04, 2016 at 05:11:11PM +0200, Michal Privoznik wrote:
On 04.08.2016 12:19, Pavel Hrdina wrote:
On Wed, Jul 27, 2016 at 10:43:50AM +0200, Michal Privoznik wrote:
This element will control secure boot implemented by some firmwares. If the firmware used in <loader/> does support the feature we must tell it to the underlying hypervisor. However, we can't know whether loader does support it or not just by looking at the file. Therefore we have to have an attribute to the element where users can tell us whether the firmware is secure boot enabled or not.
Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- docs/formatdomain.html.in | 7 ++-- docs/schemas/domaincommon.rng | 8 +++++ src/conf/domain_conf.c | 14 ++++++++ src/conf/domain_conf.h | 1 + .../qemuxml2argv-bios-nvram-secure.xml | 41 ++++++++++++++++++++++
This XML file should be part of the next patch.
In fact, I always thought that XML test files should go hand in hand with our parser/formatter & schema changes. I mean, the .xml file I'm introducing is checked to be compliant with the RNG schema. I think the XML file can be viewed as a test for RNG schema change.
I thought about this too that it is checked by our RNG schema test. I'm not against to leave it in this patch, but for RNG schema tests there is tests/domainschemadata folder. In this case it's pointless to create a separate schema test because it will be covered by XML file for qemuxml2argv test. I just thought that it would be better to keep it close to the qemuxml2argv test but if you don't want to move it to the next patch I can live with that :) Pavel

In qemu, enabling this feature boils down to adding the following onto the command line: -global driver=cfi.pflash01,property=secure,value=on However, there are some constraints resulting from the implementation. For instance, System Management Mode (SMM) is required to be enabled, the machine type must be q35-2.5 or later, and the guest should be x86_64. While technically it is possible to have 32 bit guests with secure boot, some non-trivial CPU flags tuning is required (for instance lm and nx flags must be prohibited). Given complexity of our CPU driver, this is not trivial. Therefore I've chosen to forbid 32 bit guests for now. If there's ever need, we can refine the check later. Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- src/qemu/qemu_command.c | 7 ++++++ src/qemu/qemu_domain.c | 27 ++++++++++++++++++++ .../qemuxml2argv-bios-nvram-secure.args | 29 ++++++++++++++++++++++ tests/qemuxml2argvtest.c | 7 ++++++ 4 files changed, 70 insertions(+) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-bios-nvram-secure.args diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 831aba1..c6e629e 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -8731,6 +8731,13 @@ qemuBuildDomainLoaderCommandLine(virCommandPtr cmd, goto cleanup; } + if (loader->secure == VIR_TRISTATE_BOOL_YES) { + virCommandAddArgList(cmd, + "-global", + "driver=cfi.pflash01,property=secure,value=on", + NULL); + } + virBufferAsprintf(&buf, "file=%s,if=pflash,format=raw,unit=%d", loader->path, unit); diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 9045f37..ed51481 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -2321,6 +2321,33 @@ qemuDomainDefValidate(const virDomainDef *def, return -1; } + if (def->os.loader && + def->os.loader->secure == VIR_TRISTATE_BOOL_YES) { + /* These are the QEMU implementation limitations. But we + * have to live with them for now. */ + + if (!qemuDomainMachineIsQ35(def)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Secure boot is supported with q35 machine types only")); + return -1; + } + + /* Now, technically it is possible to have secure boot on + * 32bits too, but that would require some -cpu xxx magic + * too. Not worth it unless we are explicitly asked. */ + if (def->os.arch != VIR_ARCH_X86_64) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Secure boot is supported for x86_64 architecture only")); + return -1; + } + + if (def->features[VIR_DOMAIN_FEATURE_SMM] != VIR_TRISTATE_SWITCH_ON) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Secure boot requires SMM feature enabled")); + return -1; + } + } + return 0; } diff --git a/tests/qemuxml2argvdata/qemuxml2argv-bios-nvram-secure.args b/tests/qemuxml2argvdata/qemuxml2argv-bios-nvram-secure.args new file mode 100644 index 0000000..c014254 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-bios-nvram-secure.args @@ -0,0 +1,29 @@ +LC_ALL=C \ +PATH=/bin \ +HOME=/home/test \ +USER=test \ +LOGNAME=test \ +QEMU_AUDIO_DRV=none \ +/usr/bin/qemu \ +-name test-bios \ +-S \ +-machine pc-q35-2.5,accel=tcg,smm=on \ +-global driver=cfi.pflash01,property=secure,value=on \ +-drive file=/usr/share/OVMF/OVMF_CODE.secboot.fd,if=pflash,format=raw,unit=0,\ +readonly=on \ +-drive file=/usr/share/OVMF/OVMF_VARS.fd,if=pflash,format=raw,unit=1 \ +-m 1024 \ +-smp 1,sockets=1,cores=1,threads=1 \ +-uuid 362d1fc1-df7d-193e-5c18-49a71bd1da66 \ +-nographic \ +-nodefaults \ +-monitor unix:/tmp/lib/domain--1-test-bios/monitor.sock,server,nowait \ +-boot c \ +-device i82801b11-bridge,id=pci.1,bus=pcie.0,addr=0x1e \ +-device pci-bridge,chassis_nr=2,id=pci.2,bus=pci.1,addr=0x0 \ +-device virtio-scsi-pci,id=scsi0,bus=pci.2,addr=0x1 \ +-drive file=/dev/HostVG/QEMUGuest1,format=raw,if=none,id=drive-scsi0-0-0-0 \ +-device scsi-disk,bus=scsi0.0,channel=0,scsi-id=0,lun=0,\ +drive=drive-scsi0-0-0-0,id=scsi0-0-0-0 \ +-serial pty \ +-device virtio-balloon-pci,id=balloon0,bus=pci.2,addr=0x2 diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index f9588d5..7b05150 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -685,6 +685,13 @@ mymain(void) DO_TEST("bios", QEMU_CAPS_SGA); DO_TEST("bios-nvram", NONE); + DO_TEST("bios-nvram-secure", + QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE, + QEMU_CAPS_DEVICE_PCI_BRIDGE, + QEMU_CAPS_ICH9_AHCI, + QEMU_CAPS_MACHINE_OPT, + QEMU_CAPS_MACHINE_SMM_OPT, + QEMU_CAPS_VIRTIO_SCSI); DO_TEST("clock-utc", QEMU_CAPS_NODEFCONFIG); DO_TEST("clock-localtime", NONE); DO_TEST("clock-localtime-basis-localtime", QEMU_CAPS_RTC); -- 2.8.4

On 07/27/16 10:43, Michal Privoznik wrote:
In qemu, enabling this feature boils down to adding the following onto the command line:
-global driver=cfi.pflash01,property=secure,value=on
However, there are some constraints resulting from the implementation. For instance, System Management Mode (SMM) is required to be enabled, the machine type must be q35-2.5 or later, and the guest should be x86_64. While technically it is possible to have 32 bit guests with secure boot, some non-trivial CPU flags tuning is required (for instance lm and nx flags must be prohibited). Given complexity of our CPU driver, this is not trivial. Therefore I've chosen to forbid 32 bit guests for now. If there's ever need, we can refine the check later.
Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- src/qemu/qemu_command.c | 7 ++++++ src/qemu/qemu_domain.c | 27 ++++++++++++++++++++ .../qemuxml2argv-bios-nvram-secure.args | 29 ++++++++++++++++++++++ tests/qemuxml2argvtest.c | 7 ++++++ 4 files changed, 70 insertions(+) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-bios-nvram-secure.args
This patch looks almost complete to me (it causes all necessary QEMU options to appear, directly or indirectly (= via requiring SMM)). However, can you also enforce that the Q35 machtype has version 2.5 or later? Technically, "pc-q35-2.4" exists too, and it's not good enough (according to the instructions I wrote up in OvmfPkg/README earlier). I certainly never tested it. Thanks, Laszlo
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 831aba1..c6e629e 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -8731,6 +8731,13 @@ qemuBuildDomainLoaderCommandLine(virCommandPtr cmd, goto cleanup; }
+ if (loader->secure == VIR_TRISTATE_BOOL_YES) { + virCommandAddArgList(cmd, + "-global", + "driver=cfi.pflash01,property=secure,value=on", + NULL); + } + virBufferAsprintf(&buf, "file=%s,if=pflash,format=raw,unit=%d", loader->path, unit); diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 9045f37..ed51481 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -2321,6 +2321,33 @@ qemuDomainDefValidate(const virDomainDef *def, return -1; }
+ if (def->os.loader && + def->os.loader->secure == VIR_TRISTATE_BOOL_YES) { + /* These are the QEMU implementation limitations. But we + * have to live with them for now. */ + + if (!qemuDomainMachineIsQ35(def)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Secure boot is supported with q35 machine types only")); + return -1; + } + + /* Now, technically it is possible to have secure boot on + * 32bits too, but that would require some -cpu xxx magic + * too. Not worth it unless we are explicitly asked. */ + if (def->os.arch != VIR_ARCH_X86_64) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Secure boot is supported for x86_64 architecture only")); + return -1; + } + + if (def->features[VIR_DOMAIN_FEATURE_SMM] != VIR_TRISTATE_SWITCH_ON) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Secure boot requires SMM feature enabled")); + return -1; + } + } + return 0; }
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-bios-nvram-secure.args b/tests/qemuxml2argvdata/qemuxml2argv-bios-nvram-secure.args new file mode 100644 index 0000000..c014254 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-bios-nvram-secure.args @@ -0,0 +1,29 @@ +LC_ALL=C \ +PATH=/bin \ +HOME=/home/test \ +USER=test \ +LOGNAME=test \ +QEMU_AUDIO_DRV=none \ +/usr/bin/qemu \ +-name test-bios \ +-S \ +-machine pc-q35-2.5,accel=tcg,smm=on \ +-global driver=cfi.pflash01,property=secure,value=on \ +-drive file=/usr/share/OVMF/OVMF_CODE.secboot.fd,if=pflash,format=raw,unit=0,\ +readonly=on \ +-drive file=/usr/share/OVMF/OVMF_VARS.fd,if=pflash,format=raw,unit=1 \ +-m 1024 \ +-smp 1,sockets=1,cores=1,threads=1 \ +-uuid 362d1fc1-df7d-193e-5c18-49a71bd1da66 \ +-nographic \ +-nodefaults \ +-monitor unix:/tmp/lib/domain--1-test-bios/monitor.sock,server,nowait \ +-boot c \ +-device i82801b11-bridge,id=pci.1,bus=pcie.0,addr=0x1e \ +-device pci-bridge,chassis_nr=2,id=pci.2,bus=pci.1,addr=0x0 \ +-device virtio-scsi-pci,id=scsi0,bus=pci.2,addr=0x1 \ +-drive file=/dev/HostVG/QEMUGuest1,format=raw,if=none,id=drive-scsi0-0-0-0 \ +-device scsi-disk,bus=scsi0.0,channel=0,scsi-id=0,lun=0,\ +drive=drive-scsi0-0-0-0,id=scsi0-0-0-0 \ +-serial pty \ +-device virtio-balloon-pci,id=balloon0,bus=pci.2,addr=0x2 diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index f9588d5..7b05150 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -685,6 +685,13 @@ mymain(void)
DO_TEST("bios", QEMU_CAPS_SGA); DO_TEST("bios-nvram", NONE); + DO_TEST("bios-nvram-secure", + QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE, + QEMU_CAPS_DEVICE_PCI_BRIDGE, + QEMU_CAPS_ICH9_AHCI, + QEMU_CAPS_MACHINE_OPT, + QEMU_CAPS_MACHINE_SMM_OPT, + QEMU_CAPS_VIRTIO_SCSI); DO_TEST("clock-utc", QEMU_CAPS_NODEFCONFIG); DO_TEST("clock-localtime", NONE); DO_TEST("clock-localtime-basis-localtime", QEMU_CAPS_RTC);

On Wed, Jul 27, 2016 at 05:11:59PM +0200, Laszlo Ersek wrote:
On 07/27/16 10:43, Michal Privoznik wrote:
In qemu, enabling this feature boils down to adding the following onto the command line:
-global driver=cfi.pflash01,property=secure,value=on
However, there are some constraints resulting from the implementation. For instance, System Management Mode (SMM) is required to be enabled, the machine type must be q35-2.5 or
s/q35-2.5/q35-2.4/
later, and the guest should be x86_64. While technically it is possible to have 32 bit guests with secure boot, some non-trivial CPU flags tuning is required (for instance lm and nx flags must be prohibited). Given complexity of our CPU driver, this is not trivial. Therefore I've chosen to forbid 32 bit guests for now. If there's ever need, we can refine the check later.
Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- src/qemu/qemu_command.c | 7 ++++++ src/qemu/qemu_domain.c | 27 ++++++++++++++++++++ .../qemuxml2argv-bios-nvram-secure.args | 29 ++++++++++++++++++++++ tests/qemuxml2argvtest.c | 7 ++++++ 4 files changed, 70 insertions(+) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-bios-nvram-secure.args
This patch looks almost complete to me (it causes all necessary QEMU options to appear, directly or indirectly (= via requiring SMM)). However, can you also enforce that the Q35 machtype has version 2.5 or later? Technically, "pc-q35-2.4" exists too, and it's not good enough (according to the instructions I wrote up in OvmfPkg/README earlier). I certainly never tested it.
Thanks, Laszlo
I've tested it and it seems to work also with "pc-q35-2.4". I've installed Fedora 24 inside a guest and I can see "Secure boot enabled" in dmesg output. Unless Laszlo has some more information about secure boot and why it shouldn't work with "pc-q35-2.4" this patch can be pushed as is. ACK

On 08/04/16 15:14, Pavel Hrdina wrote:
On Wed, Jul 27, 2016 at 05:11:59PM +0200, Laszlo Ersek wrote:
On 07/27/16 10:43, Michal Privoznik wrote:
In qemu, enabling this feature boils down to adding the following onto the command line:
-global driver=cfi.pflash01,property=secure,value=on
However, there are some constraints resulting from the implementation. For instance, System Management Mode (SMM) is required to be enabled, the machine type must be q35-2.5 or
s/q35-2.5/q35-2.4/
later, and the guest should be x86_64. While technically it is possible to have 32 bit guests with secure boot, some non-trivial CPU flags tuning is required (for instance lm and nx flags must be prohibited). Given complexity of our CPU driver, this is not trivial. Therefore I've chosen to forbid 32 bit guests for now. If there's ever need, we can refine the check later.
Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- src/qemu/qemu_command.c | 7 ++++++ src/qemu/qemu_domain.c | 27 ++++++++++++++++++++ .../qemuxml2argv-bios-nvram-secure.args | 29 ++++++++++++++++++++++ tests/qemuxml2argvtest.c | 7 ++++++ 4 files changed, 70 insertions(+) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-bios-nvram-secure.args
This patch looks almost complete to me (it causes all necessary QEMU options to appear, directly or indirectly (= via requiring SMM)). However, can you also enforce that the Q35 machtype has version 2.5 or later? Technically, "pc-q35-2.4" exists too, and it's not good enough (according to the instructions I wrote up in OvmfPkg/README earlier). I certainly never tested it.
Thanks, Laszlo
I've tested it and it seems to work also with "pc-q35-2.4". I've installed Fedora 24 inside a guest and I can see "Secure boot enabled" in dmesg output. Unless Laszlo has some more information about secure boot and why it shouldn't work with "pc-q35-2.4" this patch can be pushed as is.
ACK
The Secure Boot feature and the SMM driver stack are orthogonal build-time options in OVMF. You may enable both, you may enable neither, and you may enable only one of them as well. However, the Secure Boot feature is not actually secure without the SMM driver stack. Meaning, the software interfaces that relate to Secure Boot will be available, and -- once certificates have been enrolled -- a "well behaved" guest will see Secure Boot enabled. However, a malicious guest can directly tamper with the pflash chip that stores the authenticated UEFI variables. In other words, without the SMM driver stack, a malicious guest can subvert / circumvent Secure Boot. Therefore, for "production environments", it makes sense to refer *only* to the combination Secure Boot Feature + SMM Driver Stack as "secure". This is the meaning of "secure" that you can see in the commit messages and the new XML tags here. Therefore, whether or not your test results provide actual information, depends on the following question: did your OVMF build include the SMM Driver Stack *as well*, or only the Secure Boot feature? Because, if solely the latter was built into your OVMF binary, that would suffice for the Secure boot enabled message to appear in the guest dmesg. However, per se the message doesn't prove that the SMM driver stack was built into the binary. Consequently, the message also doesn't prove that pc-q35-2.4 provides everything that's needed for SMM. Where did you get your OVMF binary? ... If you want to verify the presence of the SMM driver stack, please add the following to your domain XML (note the QEMU namespace declaration in the root element): <domain type='kvm' xmlns:qemu='http://libvirt.org/schemas/domain/qemu/1.0'
[...] <qemu:commandline> <qemu:arg value='-global'/> <qemu:arg value='isa-debugcon.iobase=0x402'/> <qemu:arg value='-debugcon'/> <qemu:arg value='file:/tmp/GUEST_NAME.log'/> </qemu:commandline> </domain> Then look for the following string in /tmp/GUEST_NAME.log: SMM CPU Module exit from SMRAM with EFI_SUCCESS If you see it, your OVMF binary contains the SMM driver stack, and then the message in the dmesg is meaningful as evidence. If you don't see it, then the message in the dmesg is worthless, as evidence for pc-q35-2.4. Thanks! Laszlo

On Thu, Aug 04, 2016 at 03:45:39PM +0200, Laszlo Ersek wrote:
On 08/04/16 15:14, Pavel Hrdina wrote:
On Wed, Jul 27, 2016 at 05:11:59PM +0200, Laszlo Ersek wrote:
On 07/27/16 10:43, Michal Privoznik wrote:
In qemu, enabling this feature boils down to adding the following onto the command line:
-global driver=cfi.pflash01,property=secure,value=on
However, there are some constraints resulting from the implementation. For instance, System Management Mode (SMM) is required to be enabled, the machine type must be q35-2.5 or
s/q35-2.5/q35-2.4/
later, and the guest should be x86_64. While technically it is possible to have 32 bit guests with secure boot, some non-trivial CPU flags tuning is required (for instance lm and nx flags must be prohibited). Given complexity of our CPU driver, this is not trivial. Therefore I've chosen to forbid 32 bit guests for now. If there's ever need, we can refine the check later.
Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- src/qemu/qemu_command.c | 7 ++++++ src/qemu/qemu_domain.c | 27 ++++++++++++++++++++ .../qemuxml2argv-bios-nvram-secure.args | 29 ++++++++++++++++++++++ tests/qemuxml2argvtest.c | 7 ++++++ 4 files changed, 70 insertions(+) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-bios-nvram-secure.args
This patch looks almost complete to me (it causes all necessary QEMU options to appear, directly or indirectly (= via requiring SMM)). However, can you also enforce that the Q35 machtype has version 2.5 or later? Technically, "pc-q35-2.4" exists too, and it's not good enough (according to the instructions I wrote up in OvmfPkg/README earlier). I certainly never tested it.
Thanks, Laszlo
I've tested it and it seems to work also with "pc-q35-2.4". I've installed Fedora 24 inside a guest and I can see "Secure boot enabled" in dmesg output. Unless Laszlo has some more information about secure boot and why it shouldn't work with "pc-q35-2.4" this patch can be pushed as is.
ACK
The Secure Boot feature and the SMM driver stack are orthogonal build-time options in OVMF. You may enable both, you may enable neither, and you may enable only one of them as well.
However, the Secure Boot feature is not actually secure without the SMM driver stack. Meaning, the software interfaces that relate to Secure Boot will be available, and -- once certificates have been enrolled -- a "well behaved" guest will see Secure Boot enabled. However, a malicious guest can directly tamper with the pflash chip that stores the authenticated UEFI variables. In other words, without the SMM driver stack, a malicious guest can subvert / circumvent Secure Boot.
Therefore, for "production environments", it makes sense to refer *only* to the combination
Secure Boot Feature + SMM Driver Stack
as "secure". This is the meaning of "secure" that you can see in the commit messages and the new XML tags here.
Therefore, whether or not your test results provide actual information, depends on the following question: did your OVMF build include the SMM Driver Stack *as well*, or only the Secure Boot feature?
Because, if solely the latter was built into your OVMF binary, that would suffice for the
Secure boot enabled
message to appear in the guest dmesg.
However, per se the message doesn't prove that the SMM driver stack was built into the binary. Consequently, the message also doesn't prove that pc-q35-2.4 provides everything that's needed for SMM.
Where did you get your OVMF binary?
I have two OVMF binaries, one from Fedora 24 rpm package: edk2-ovmf-20160418gita8c39ba-4.fc24.noarch.rpm and the second one I've built myself from upstream edk2 repository using "./build.sh -a X64 -b DEBUG -p OvmfPkg/OvmfPkgX64.dsc -D SECURE_BOOT_ENABLE -D SMM_REQUIRE"
... If you want to verify the presence of the SMM driver stack, please add the following to your domain XML (note the QEMU namespace declaration in the root element):
<domain type='kvm' xmlns:qemu='http://libvirt.org/schemas/domain/qemu/1.0'
[...]
<qemu:commandline> <qemu:arg value='-global'/> <qemu:arg value='isa-debugcon.iobase=0x402'/> <qemu:arg value='-debugcon'/> <qemu:arg value='file:/tmp/GUEST_NAME.log'/> </qemu:commandline> </domain>
Then look for the following string in /tmp/GUEST_NAME.log:
SMM CPU Module exit from SMRAM with EFI_SUCCESS
If you see it, your OVMF binary contains the SMM driver stack, and then the message in the dmesg is meaningful as evidence. If you don't see it, then the message in the dmesg is worthless, as evidence for pc-q35-2.4.
I'm using upstream qemu 2.6.0 and with the OVMF binary from Fedora 24 package called "OVMF_CODE.secboot.fd" and machine type "pc-q35-2.4" I'm able to see that line in that log file and also "Secure boot enabled" in dmesg log. The line "SMM CPU Module exit from SMRAM with EFI_SUCCESS" is also in that log file with the built OVMF binary. So based on the testing with OVMF binary from the fedora package it should be good enough to use also "pc-q35-2.4". Pavel

On 08/04/16 16:39, Pavel Hrdina wrote:
On Thu, Aug 04, 2016 at 03:45:39PM +0200, Laszlo Ersek wrote:
On 08/04/16 15:14, Pavel Hrdina wrote:
On Wed, Jul 27, 2016 at 05:11:59PM +0200, Laszlo Ersek wrote:
On 07/27/16 10:43, Michal Privoznik wrote:
In qemu, enabling this feature boils down to adding the following onto the command line:
-global driver=cfi.pflash01,property=secure,value=on
However, there are some constraints resulting from the implementation. For instance, System Management Mode (SMM) is required to be enabled, the machine type must be q35-2.5 or
s/q35-2.5/q35-2.4/
later, and the guest should be x86_64. While technically it is possible to have 32 bit guests with secure boot, some non-trivial CPU flags tuning is required (for instance lm and nx flags must be prohibited). Given complexity of our CPU driver, this is not trivial. Therefore I've chosen to forbid 32 bit guests for now. If there's ever need, we can refine the check later.
Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- src/qemu/qemu_command.c | 7 ++++++ src/qemu/qemu_domain.c | 27 ++++++++++++++++++++ .../qemuxml2argv-bios-nvram-secure.args | 29 ++++++++++++++++++++++ tests/qemuxml2argvtest.c | 7 ++++++ 4 files changed, 70 insertions(+) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-bios-nvram-secure.args
This patch looks almost complete to me (it causes all necessary QEMU options to appear, directly or indirectly (= via requiring SMM)). However, can you also enforce that the Q35 machtype has version 2.5 or later? Technically, "pc-q35-2.4" exists too, and it's not good enough (according to the instructions I wrote up in OvmfPkg/README earlier). I certainly never tested it.
Thanks, Laszlo
I've tested it and it seems to work also with "pc-q35-2.4". I've installed Fedora 24 inside a guest and I can see "Secure boot enabled" in dmesg output. Unless Laszlo has some more information about secure boot and why it shouldn't work with "pc-q35-2.4" this patch can be pushed as is.
ACK
The Secure Boot feature and the SMM driver stack are orthogonal build-time options in OVMF. You may enable both, you may enable neither, and you may enable only one of them as well.
However, the Secure Boot feature is not actually secure without the SMM driver stack. Meaning, the software interfaces that relate to Secure Boot will be available, and -- once certificates have been enrolled -- a "well behaved" guest will see Secure Boot enabled. However, a malicious guest can directly tamper with the pflash chip that stores the authenticated UEFI variables. In other words, without the SMM driver stack, a malicious guest can subvert / circumvent Secure Boot.
Therefore, for "production environments", it makes sense to refer *only* to the combination
Secure Boot Feature + SMM Driver Stack
as "secure". This is the meaning of "secure" that you can see in the commit messages and the new XML tags here.
Therefore, whether or not your test results provide actual information, depends on the following question: did your OVMF build include the SMM Driver Stack *as well*, or only the Secure Boot feature?
Because, if solely the latter was built into your OVMF binary, that would suffice for the
Secure boot enabled
message to appear in the guest dmesg.
However, per se the message doesn't prove that the SMM driver stack was built into the binary. Consequently, the message also doesn't prove that pc-q35-2.4 provides everything that's needed for SMM.
Where did you get your OVMF binary?
I have two OVMF binaries, one from Fedora 24 rpm package:
edk2-ovmf-20160418gita8c39ba-4.fc24.noarch.rpm
and the second one I've built myself from upstream edk2 repository using
"./build.sh -a X64 -b DEBUG -p OvmfPkg/OvmfPkgX64.dsc -D SECURE_BOOT_ENABLE -D SMM_REQUIRE"
... If you want to verify the presence of the SMM driver stack, please add the following to your domain XML (note the QEMU namespace declaration in the root element):
<domain type='kvm' xmlns:qemu='http://libvirt.org/schemas/domain/qemu/1.0'
[...]
<qemu:commandline> <qemu:arg value='-global'/> <qemu:arg value='isa-debugcon.iobase=0x402'/> <qemu:arg value='-debugcon'/> <qemu:arg value='file:/tmp/GUEST_NAME.log'/> </qemu:commandline> </domain>
Then look for the following string in /tmp/GUEST_NAME.log:
SMM CPU Module exit from SMRAM with EFI_SUCCESS
If you see it, your OVMF binary contains the SMM driver stack, and then the message in the dmesg is meaningful as evidence. If you don't see it, then the message in the dmesg is worthless, as evidence for pc-q35-2.4.
I'm using upstream qemu 2.6.0 and with the OVMF binary from Fedora 24 package called "OVMF_CODE.secboot.fd" and machine type "pc-q35-2.4" I'm able to see that line in that log file and also "Secure boot enabled" in dmesg log.
The line "SMM CPU Module exit from SMRAM with EFI_SUCCESS" is also in that log file with the built OVMF binary.
So based on the testing with OVMF binary from the fedora package it should be good enough to use also "pc-q35-2.4".
Thank you for confirming! Laszlo

Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- src/qemu/qemu_conf.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c index fa9d65e..b51f36f 100644 --- a/src/qemu/qemu_conf.c +++ b/src/qemu/qemu_conf.c @@ -126,6 +126,8 @@ void qemuDomainCmdlineDefFree(qemuDomainCmdlineDefPtr def) #define VIR_QEMU_OVMF_LOADER_PATH "/usr/share/OVMF/OVMF_CODE.fd" #define VIR_QEMU_OVMF_NVRAM_PATH "/usr/share/OVMF/OVMF_VARS.fd" +#define VIR_QEMU_OVMF_SEC_LOADER_PATH "/usr/share/OVMF/OVMF_CODE.secboot.fd" +#define VIR_QEMU_OVMF_SEC_NVRAM_PATH "/usr/share/OVMF/OVMF_VARS.fd" #define VIR_QEMU_AAVMF_LOADER_PATH "/usr/share/AAVMF/AAVMF_CODE.fd" #define VIR_QEMU_AAVMF_NVRAM_PATH "/usr/share/AAVMF/AAVMF_VARS.fd" @@ -292,16 +294,19 @@ virQEMUDriverConfigPtr virQEMUDriverConfigNew(bool privileged) goto error; #else - if (VIR_ALLOC_N(cfg->firmwares, 2) < 0) + if (VIR_ALLOC_N(cfg->firmwares, 3) < 0) goto error; - cfg->nfirmwares = 2; - if (VIR_ALLOC(cfg->firmwares[0]) < 0 || VIR_ALLOC(cfg->firmwares[1]) < 0) + cfg->nfirmwares = 3; + if (VIR_ALLOC(cfg->firmwares[0]) < 0 || VIR_ALLOC(cfg->firmwares[1]) < 0 || + VIR_ALLOC(cfg->firmwares[2]) < 0) goto error; if (VIR_STRDUP(cfg->firmwares[0]->name, VIR_QEMU_AAVMF_LOADER_PATH) < 0 || VIR_STRDUP(cfg->firmwares[0]->nvram, VIR_QEMU_AAVMF_NVRAM_PATH) < 0 || VIR_STRDUP(cfg->firmwares[1]->name, VIR_QEMU_OVMF_LOADER_PATH) < 0 || - VIR_STRDUP(cfg->firmwares[1]->nvram, VIR_QEMU_OVMF_NVRAM_PATH) < 0) + VIR_STRDUP(cfg->firmwares[1]->nvram, VIR_QEMU_OVMF_NVRAM_PATH) < 0 || + VIR_STRDUP(cfg->firmwares[2]->name, VIR_QEMU_OVMF_SEC_LOADER_PATH) < 0 || + VIR_STRDUP(cfg->firmwares[2]->nvram, VIR_QEMU_OVMF_SEC_NVRAM_PATH) < 0) goto error; #endif -- 2.8.4

On 07/27/16 10:43, Michal Privoznik wrote:
Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- src/qemu/qemu_conf.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-)
diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c index fa9d65e..b51f36f 100644 --- a/src/qemu/qemu_conf.c +++ b/src/qemu/qemu_conf.c @@ -126,6 +126,8 @@ void qemuDomainCmdlineDefFree(qemuDomainCmdlineDefPtr def)
#define VIR_QEMU_OVMF_LOADER_PATH "/usr/share/OVMF/OVMF_CODE.fd" #define VIR_QEMU_OVMF_NVRAM_PATH "/usr/share/OVMF/OVMF_VARS.fd" +#define VIR_QEMU_OVMF_SEC_LOADER_PATH "/usr/share/OVMF/OVMF_CODE.secboot.fd" +#define VIR_QEMU_OVMF_SEC_NVRAM_PATH "/usr/share/OVMF/OVMF_VARS.fd" #define VIR_QEMU_AAVMF_LOADER_PATH "/usr/share/AAVMF/AAVMF_CODE.fd" #define VIR_QEMU_AAVMF_NVRAM_PATH "/usr/share/AAVMF/AAVMF_VARS.fd"
@@ -292,16 +294,19 @@ virQEMUDriverConfigPtr virQEMUDriverConfigNew(bool privileged) goto error;
#else - if (VIR_ALLOC_N(cfg->firmwares, 2) < 0) + if (VIR_ALLOC_N(cfg->firmwares, 3) < 0) goto error; - cfg->nfirmwares = 2; - if (VIR_ALLOC(cfg->firmwares[0]) < 0 || VIR_ALLOC(cfg->firmwares[1]) < 0) + cfg->nfirmwares = 3; + if (VIR_ALLOC(cfg->firmwares[0]) < 0 || VIR_ALLOC(cfg->firmwares[1]) < 0 || + VIR_ALLOC(cfg->firmwares[2]) < 0) goto error;
if (VIR_STRDUP(cfg->firmwares[0]->name, VIR_QEMU_AAVMF_LOADER_PATH) < 0 || VIR_STRDUP(cfg->firmwares[0]->nvram, VIR_QEMU_AAVMF_NVRAM_PATH) < 0 || VIR_STRDUP(cfg->firmwares[1]->name, VIR_QEMU_OVMF_LOADER_PATH) < 0 || - VIR_STRDUP(cfg->firmwares[1]->nvram, VIR_QEMU_OVMF_NVRAM_PATH) < 0) + VIR_STRDUP(cfg->firmwares[1]->nvram, VIR_QEMU_OVMF_NVRAM_PATH) < 0 || + VIR_STRDUP(cfg->firmwares[2]->name, VIR_QEMU_OVMF_SEC_LOADER_PATH) < 0 || + VIR_STRDUP(cfg->firmwares[2]->nvram, VIR_QEMU_OVMF_SEC_NVRAM_PATH) < 0) goto error; #endif
Acked-by: Laszlo Ersek <lersek@redhat.com> You might want to add the same to the default qemu.conf file, in the "nvram" stanza. Thanks Laszlo

On 27.07.2016 10:43, Michal Privoznik wrote:
We have UEFI enabled guests for a while now. But only recently qemu introduced secure boot. We should reflect that in our code too.
Michal Privoznik (5): qemuBuildMachineCommandLine: Follow our pattern Introduce SMM feature Introduce @secure attribute to os loader element qemu: Enable secure boot qemu: Advertise OVMF_CODE.secboot.fd
docs/formatdomain.html.in | 13 ++++- docs/schemas/domaincommon.rng | 17 +++++++ src/conf/domain_conf.c | 19 ++++++- src/conf/domain_conf.h | 2 + src/qemu/qemu_capabilities.c | 16 ++++++ src/qemu/qemu_capabilities.h | 4 ++ src/qemu/qemu_command.c | 58 ++++++++++++++-------- src/qemu/qemu_conf.c | 13 +++-- src/qemu/qemu_domain.c | 27 ++++++++++ tests/qemucapabilitiesdata/caps_2.4.0.x86_64.xml | 1 + tests/qemucapabilitiesdata/caps_2.5.0.x86_64.xml | 1 + .../caps_2.6.0-gicv2.aarch64.xml | 1 + .../caps_2.6.0-gicv3.aarch64.xml | 1 + tests/qemucapabilitiesdata/caps_2.6.0.ppc64le.xml | 1 + tests/qemucapabilitiesdata/caps_2.6.0.x86_64.xml | 1 + .../qemuxml2argv-bios-nvram-secure.args | 29 +++++++++++ .../qemuxml2argv-bios-nvram-secure.xml | 41 +++++++++++++++ .../qemuxml2argv-machine-smm-opt.args | 25 ++++++++++ .../qemuxml2argv-machine-smm-opt.xml | 28 +++++++++++ tests/qemuxml2argvtest.c | 14 ++++++ 20 files changed, 284 insertions(+), 28 deletions(-) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-bios-nvram-secure.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-bios-nvram-secure.xml create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-machine-smm-opt.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-machine-smm-opt.xml
Thank you all gyus. I've pushed these. Michal
participants (4)
-
Gerd Hoffmann
-
Laszlo Ersek
-
Michal Privoznik
-
Pavel Hrdina