
On 4/2/18 6:04 PM, John Ferlan wrote:
On 04/02/2018 10:18 AM, Brijesh Singh wrote:
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.singh@amd.com> --- src/qemu/qemu_command.c | 35 +++++++++++++++++++++++++++++ src/qemu/qemu_process.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+)
(slight delay for next part of review - today was rocket launch day and then we headed out for a bit ;-))
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 682d714..55bbfa2 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -7405,6 +7405,9 @@ qemuBuildMachineCommandLine(virCommandPtr cmd, virQEMUCapsGet(qemuCaps, QEMU_CAPS_LOADPARM)) qemuAppendLoadparmMachineParm(&buf, def);
+ if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_SEV_GUEST) && def->sev) Since we already checked sev-guest at prepare host storage (mostly unconditionally), I don't think we have to make the check here as well - although I could be wrong...
Yes, probably we can avoid the SEV_GUEST cap check in this case. I will make the changes in next rev.
+ virBufferAddLit(&buf, ",memory-encryption=sev0"); + virCommandAddArgBuffer(cmd, &buf); }
@@ -9750,6 +9753,35 @@ qemuBuildTPMCommandLine(virCommandPtr cmd, return 0; }
+static void This probably should be an int...
I think it will be unlikely that this function will fail hence I was using void. The only time it can fail is when we fail to create a dh-cert and session blob file (e.g disk is full). I will propagate the error.
+qemuBuildSevCommandLine(virDomainObjPtr vm, virCommandPtr cmd, + virDomainSevDefPtr sev) +{ + virBuffer obj = VIR_BUFFER_INITIALIZER; + qemuDomainObjPrivatePtr priv = vm->privateData; + char *path = NULL; + if (!dev->sev) return 0;
again, since prepare host storage checked the sev-guest capability we should be good to go here...
OK.
+ 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); Here I would say:
if (sev->policy > 0) virBufferAsprintf(&obj, ",policy=0x%x", sev->policy);
and let qemu pick the default (which is 0x1 as I read that code).
OK, then I will remove the comment from html about the default value since I was trying to not depend on QEMU default.
+ + if (sev->dh_cert) { + ignore_value(virAsprintf(&path, "%s/dh_cert.base64", priv->libDir)); + virBufferAsprintf(&obj, ",dh-cert-file=%s", path); + VIR_FREE(path); + } + + if (sev->session) { + ignore_value(virAsprintf(&path, "%s/session.base64", priv->libDir)); + virBufferAsprintf(&obj, ",session-file=%s", path); + VIR_FREE(path); + } ...since I don't believe we can ignore_value on the paths - especially since we're using it to create a path to a file containing some sort of session info or DH key (base64 encrypted).
Sure, will do.
+ + virCommandAddArgList(cmd, "-object", virBufferContentAndReset(&obj), NULL); +}
static int qemuBuildVMCoreInfoCommandLine(virCommandPtr cmd, @@ -10195,6 +10227,9 @@ qemuBuildCommandLine(virQEMUDriverPtr driver, if (qemuBuildVMCoreInfoCommandLine(cmd, def, qemuCaps) < 0) goto error;
+ if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_SEV_GUEST) && def->sev) + qemuBuildSevCommandLine(vm, cmd, def->sev); + I think we're save to change this to:
if (qemuBuildSevCommandLine(vm, cmd, dev->sev) < 0) goto error;
Yep
if (snapshot) virCommandAddArgList(cmd, "-loadvm", snapshot->def->name, NULL);
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index c0105c8..0c93f15 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -5745,6 +5745,61 @@ qemuProcessPrepareDomain(virQEMUDriverPtr driver, return ret; }
Two blank lines
+static int +qemuBuildSevCreateFile(const char *configDir, const char *name, + const char *data) 3 lines for args
+{ + 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; + } Check out storageBackendCreateQemuImgSecretPath which just goes straight to safewrite when writing to the file or qemuDomainWriteMasterKeyFile which is a similar w/r/t a single key file for the domain.
The one thing to think about being the privileges for the file being created and written and the expectations for QEMU's usage. I think this is more like the storage secret code, but I could be wrong!
The data is public in this case, we do not need to protect it with secret. Hence I am keeping all this certificate keys in unsecure place.
+ + VIR_FREE(configFile); + return 0; + + error: + VIR_FREE(configFile); + return -1; +} + 2 blank lines
+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 " s/but/but this/
Noted.
+ "QEMU does not support SEV feature"), vm->def->name); + return -1; + } Since we check for this here - I think this should be good enough for command line building. That is - qemuProcessPrepareHostStorage will come before command line building - so the check is already made.
Got it.
+ + 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; +} 2 blank lines
John
static int qemuProcessPrepareHostStorage(virQEMUDriverPtr driver, @@ -5870,6 +5925,9 @@ qemuProcessPrepareHost(virQEMUDriverPtr driver, if (qemuProcessPrepareHostStorage(driver, vm, flags) < 0) goto cleanup;
+ if (qemuProcessPrepareSevGuestInput(vm) < 0) + goto cleanup; + ret = 0; cleanup: virObjectUnref(cfg);