QEMU >= 2.12 provides 'sev-guest' object which is used to launch encrypted VMs on AMD platform using SEV feature. The various inputs required to launch SEV guest is provided through the <launch-security> tag. A typical SEV guest launch command line looks like this:
# $QEMU ...\ -object sev-guest,id=sev0,cbitpos=47,reduced-phys-bits=5 ...\ -machine memory-encryption=sev0 \ Signed-off-by: Brijesh Singh <brijesh.si...@amd.com> Reviewed-by: Erik Skultety <eskul...@redhat.com> --- src/qemu/qemu_command.c | 41 ++++++++++++++++ src/qemu/qemu_process.c | 62 +++++++++++++++++++++++++ tests/qemuxml2argvdata/launch-security-sev.args | 29 ++++++++++++ tests/qemuxml2argvdata/launch-security-sev.xml | 37 +++++++++++++++ tests/qemuxml2argvtest.c | 4 ++ 5 files changed, 173 insertions(+) create mode 100644 tests/qemuxml2argvdata/launch-security-sev.args create mode 100644 tests/qemuxml2argvdata/launch-security-sev.xml diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 2f5cf4e..142455a 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -7235,6 +7235,9 @@ qemuBuildMachineCommandLine(virCommandPtr cmd, virQEMUCapsGet(qemuCaps, QEMU_CAPS_LOADPARM)) qemuAppendLoadparmMachineParm(&buf, def); + if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_SEV_GUEST) && def->sev) + virBufferAddLit(&buf, ",memory-encryption=sev0"); + virCommandAddArgBuffer(cmd, &buf); ret = 0; @@ -9594,6 +9597,41 @@ qemuBuildTPMCommandLine(virCommandPtr cmd, return 0; } +static int +qemuBuildSevCommandLine(virDomainObjPtr vm, virCommandPtr cmd, + virDomainSevDefPtr sev) +{ + virBuffer obj = VIR_BUFFER_INITIALIZER; + qemuDomainObjPrivatePtr priv = vm->privateData; + char *path = NULL; + + if (!sev) + return 0; + + VIR_DEBUG("policy=0x%x cbitpos=%d reduced_phys_bits=%d", + sev->policy, sev->cbitpos, sev->reduced_phys_bits); + + virBufferAsprintf(&obj, "sev-guest,id=sev0,cbitpos=%d", sev->cbitpos); + virBufferAsprintf(&obj, ",reduced-phys-bits=%d", sev->reduced_phys_bits); + virBufferAsprintf(&obj, ",policy=0x%x", sev->policy); + + if (sev->dh_cert) { + if (virAsprintf(&path, "%s/dh_cert.base64", priv->libDir) < 0) + return -1; + virBufferAsprintf(&obj, ",dh-cert-file=%s", path); + VIR_FREE(path); + } + + if (sev->session) { + if (virAsprintf(&path, "%s/session.base64", priv->libDir) < 0) + return -1; + virBufferAsprintf(&obj, ",session-file=%s", path); + VIR_FREE(path); + } + + virCommandAddArgList(cmd, "-object", virBufferContentAndReset(&obj), NULL); + return 0; +} static int qemuBuildVMCoreInfoCommandLine(virCommandPtr cmd, @@ -10188,6 +10226,9 @@ qemuBuildCommandLine(virQEMUDriverPtr driver, if (qemuBuildVMCoreInfoCommandLine(cmd, def, qemuCaps) < 0) goto error; + if (qemuBuildSevCommandLine(vm, cmd, def->sev) < 0) + goto error; + if (snapshot) virCommandAddArgList(cmd, "-loadvm", snapshot->def->name, NULL); diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 3e97971..c624d63 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -5818,6 +5818,65 @@ qemuProcessPrepareDomain(virQEMUDriverPtr driver, static int +qemuBuildSevCreateFile(const char *configDir, + const char *name, + const char *data) +{ + char *configFile; + + if (!(configFile = virFileBuildPath(configDir, name, ".base64"))) + return -1; + + if (virFileRewriteStr(configFile, S_IRUSR | S_IWUSR, data) < 0) { + virReportSystemError(errno, _("failed to write data to config '%s'"), + configFile); + goto error; + } + + VIR_FREE(configFile); + return 0; + + error: + VIR_FREE(configFile); + return -1; +} + + +static int +qemuProcessPrepareSevGuestInput(virDomainObjPtr vm) +{ + qemuDomainObjPrivatePtr priv = vm->privateData; + virDomainDefPtr def = vm->def; + virQEMUCapsPtr qemuCaps = priv->qemuCaps; + virDomainSevDefPtr sev = def->sev; + + if (!sev) + return 0; + + VIR_DEBUG("Prepare SEV guest"); + + if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_SEV_GUEST)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Domain %s asked for 'sev' launch but this " + "QEMU does not support SEV feature"), vm->def->name); + return -1; + } + + if (sev->dh_cert) { + if (qemuBuildSevCreateFile(priv->libDir, "dh_cert", sev->dh_cert) < 0) + return -1; + } + + if (sev->session) { + if (qemuBuildSevCreateFile(priv->libDir, "session", sev->session) < 0) + return -1; + } + + return 0; +} + + +static int qemuProcessPrepareHostStorage(virQEMUDriverPtr driver, virDomainObjPtr vm, unsigned int flags) @@ -5975,6 +6034,9 @@ qemuProcessPrepareHost(virQEMUDriverPtr driver, if (qemuProcessPrepareHostStorage(driver, vm, flags) < 0) goto cleanup; + if (qemuProcessPrepareSevGuestInput(vm) < 0) + goto cleanup; + ret = 0; cleanup: virObjectUnref(cfg); diff --git a/tests/qemuxml2argvdata/launch-security-sev.args b/tests/qemuxml2argvdata/launch-security-sev.args new file mode 100644 index 0000000..db0be1a --- /dev/null +++ b/tests/qemuxml2argvdata/launch-security-sev.args @@ -0,0 +1,29 @@ +LC_ALL=C \ +PATH=/bin \ +HOME=/home/test \ +USER=test \ +LOGNAME=test \ +QEMU_AUDIO_DRV=none \ +/usr/bin/qemu-system-x86_64 \ +-name QEMUGuest1 \ +-S \ +-machine pc-1.0,accel=kvm,usb=off,dump-guest-core=off,memory-encryption=sev0 \ +-m 214 \ +-smp 1,sockets=1,cores=1,threads=1 \ +-uuid c7a5fdbd-edaf-9455-926a-d65c16db1809 \ +-display none \ +-no-user-config \ +-nodefaults \ +-chardev socket,id=charmonitor,path=/tmp/lib/domain--1-QEMUGuest1/monitor.sock,\ +server,nowait \ +-mon chardev=charmonitor,id=monitor,mode=control \ +-rtc base=utc \ +-no-shutdown \ +-no-acpi \ +-boot c \ +-usb \ +-drive file=/dev/HostVG/QEMUGuest1,format=raw,if=none,id=drive-ide0-0-0 \ +-device ide-drive,bus=ide.0,unit=0,drive=drive-ide0-0-0,id=ide0-0-0 \ +-object sev-guest,id=sev0,cbitpos=47,reduced-phys-bits=1,policy=0x1,\ +dh-cert-file=/tmp/lib/domain--1-QEMUGuest1/dh_cert.base64,\ +session-file=/tmp/lib/domain--1-QEMUGuest1/session.base64 diff --git a/tests/qemuxml2argvdata/launch-security-sev.xml b/tests/qemuxml2argvdata/launch-security-sev.xml new file mode 100644 index 0000000..5ae83f6 --- /dev/null +++ b/tests/qemuxml2argvdata/launch-security-sev.xml @@ -0,0 +1,37 @@ +<domain type='kvm'> + <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='pc-1.0'>hvm</type> + <boot dev='hd'/> + </os> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu-system-x86_64</emulator> + <disk type='block' device='disk'> + <driver name='qemu' type='raw'/> + <source dev='/dev/HostVG/QEMUGuest1'/> + <target dev='hda' bus='ide'/> + <address type='drive' controller='0' bus='0' target='0' unit='0'/> + </disk> + <controller type='usb' index='0'/> + <controller type='ide' index='0'/> + <controller type='pci' index='0' model='pci-root'/> + <input type='mouse' bus='ps2'/> + <input type='keyboard' bus='ps2'/> + <memballoon model='none'/> + </devices> + <launch-security type='sev'> + <cbitpos>47</cbitpos> + <reduced-phys-bits>1</reduced-phys-bits> + <policy>0x0001</policy> + <dh-cert>AQAAAAAOAAAAQAAAAAOAAAAQAAAAAOAAAAQAAAAAOAAAAQAAAAAOAAA</dh-cert> + <session>IHAVENOIDEABUTJUSTPROVIDINGASTRING</session> + </launch-security> +</domain> diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index 36bff26..b4cf47f 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -2857,6 +2857,10 @@ mymain(void) DO_TEST_CAPS_LATEST("vhost-vsock"); DO_TEST_CAPS_LATEST("vhost-vsock-auto"); + DO_TEST("launch-security-sev", + QEMU_CAPS_KVM, + QEMU_CAPS_SEV_GUEST); + if (getenv("LIBVIRT_SKIP_CLEANUP") == NULL) virFileDeleteTree(fakerootdir); -- 2.7.4 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list