[RFC PATCH 3/3] qemu: Implement the virDomainInjectLaunchSecret API
Jim Fehlig
jfehlig at suse.com
Tue Nov 23 18:15:27 UTC 2021
On 11/17/21 03:39, Peter Krempa wrote:
> On Tue, Nov 16, 2021 at 19:23:54 -0700, Jim Fehlig wrote:
>> Inject a launch secret in domain memory using the sev-inject-launch-secret
>> QMP API. Only supported for SEV-enabed domains.
>>
>> Signed-off-by: Jim Fehlig <jfehlig at suse.com>
>> ---
>> src/qemu/qemu_driver.c | 53 ++++++++++++++++++++++++++++++++++++
>> src/qemu/qemu_monitor.c | 12 ++++++++
>> src/qemu/qemu_monitor.h | 6 ++++
>> src/qemu/qemu_monitor_json.c | 34 +++++++++++++++++++++++
>> src/qemu/qemu_monitor_json.h | 5 ++++
>> 5 files changed, 110 insertions(+)
>>
>> diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
>> index d954635dde..58e3f08afe 100644
>> --- a/src/qemu/qemu_driver.c
>> +++ b/src/qemu/qemu_driver.c
>> @@ -20104,6 +20104,58 @@ qemuDomainGetLaunchSecurityInfo(virDomainPtr domain,
>> return ret;
>> }
>>
>> +
>> +static int
>> +qemuDomainInjectLaunchSecret(virDomainPtr domain,
>> + const char *secrethdr,
>> + const char *secret,
>> + unsigned long long injectaddr,
>> + unsigned int flags)
>> +{
>> + virQEMUDriver *driver = domain->conn->privateData;
>> + virDomainObj *vm;
>> + int ret = -1;
>> +
>> + virCheckFlags(0, -1);
>> +
>> + if (!(vm = qemuDomainObjFromDomain(domain)))
>> + goto cleanup;
>> +
>> + if (virDomainInjectLaunchSecretEnsureACL(domain->conn, vm->def) < 0)
>> + goto cleanup;
>> +
>> + /* Currently only SEV is supported */
>> + if (!vm->def->sec ||
>> + vm->def->sec->sectype != VIR_DOMAIN_LAUNCH_SECURITY_SEV) {
>> + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
>> + _("injecting a launch secret is only supported in SEV-enabled domains"));
>> + goto cleanup;
>> + }
>
> Missing check that the VM is running.
>
>> +
>> + if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
>> + goto cleanup;
>> +
>> + if (qemuDomainObjEnterMonitorAsync(driver, vm, QEMU_ASYNC_JOB_NONE) < 0)
>> + goto endjob;
>
> No need for async monitor without an async job
>
>> +
>> + if (qemuMonitorInjectLaunchSecret(QEMU_DOMAIN_PRIVATE(vm)->mon,
>> + secrethdr, secret, injectaddr) < 0)
>> + goto endjob;
>> +
>> + if (qemuDomainObjExitMonitor(driver, vm) < 0)
>> + goto endjob;
>> +
>> + ret = 0;
>> +
>> + endjob:
>> + qemuDomainObjEndJob(driver, vm);
>> +
>> + cleanup:
>
>
> [...]
>
>> diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
>> index 810dac209d..c64469a03b 100644
>> --- a/src/qemu/qemu_monitor.c
>> +++ b/src/qemu/qemu_monitor.c
>> @@ -4383,6 +4383,18 @@ qemuMonitorGetSEVMeasurement(qemuMonitor *mon)
>> }
>>
>>
>> +int
>> +qemuMonitorInjectLaunchSecret(qemuMonitor *mon,
>> + const char *secrethdr,
>> + const char *secret,
>> + unsigned long long injectaddr)
>> +{
>> + QEMU_CHECK_MONITOR(mon);
>
> You cleverly avoid logging the secret here ...
>
>> +
>> + return qemuMonitorJSONInjectLaunchSecret(mon, secrethdr, secret, injectaddr);
>> +}
>> +
>> +
>> int
>> qemuMonitorGetPRManagerInfo(qemuMonitor *mon,
>> GHashTable **retinfo)
>
>
> [...]
>
>> diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
>> index 4669b9135d..69aef078ec 100644
>> --- a/src/qemu/qemu_monitor_json.c
>> +++ b/src/qemu/qemu_monitor_json.c
>> @@ -8124,6 +8124,40 @@ qemuMonitorJSONGetSEVMeasurement(qemuMonitor *mon)
>> }
>>
>>
>> +/**
>> + * The function is used to inject a launch secret in an SEV guest.
>> + *
>> + * Example JSON:
>> + *
>> + * { "execute" : "sev-inject-launch-secret",
>> + * "data": { "packet-header": "str", "secret": "str", "gpa": "uint64" } }
>> + */
>> +int
>> +qemuMonitorJSONInjectLaunchSecret(qemuMonitor *mon,
>> + const char *secrethdr,
>> + const char *secret,
>> + unsigned long long injectaddr)
>> +{
>> + g_autoptr(virJSONValue) cmd = NULL;
>> + g_autoptr(virJSONValue) reply = NULL;
>> +
>> + if (!(cmd = qemuMonitorJSONMakeCommand("sev-inject-launch-secret",
>> + "s:packet-header", secrethdr,
>> + "s:secret", secret,
>> + "U:gpa", injectaddr,
>> + NULL)))
>> + return -1;
>> +
>> + if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
>
> ... but once this is sent to the monitor it can be logged if QMP traffic
> logging is enabled.
>
> Thus either the secret is not so secret, but the qemu documentation nor
> the documentation you've added seem to be lessening the secrecy of the
> passed string in any way, or the 'sev-inject-launch-secret' is broken by
> design as it doesn't support passing an encrypted object via qcrypto.
AFAICT, the secret is an encrypted object. See section "6.6 LAUNCH_SECRET" in
the following doc
https://www.amd.com/system/files/TechDocs/55766_SEV-KM_API_Specification.pdf
I'll need to do more snooping so I can improve the API documentation in 1/3. A
clearer description of the API and its parameters would help with questions like
this.
Regards,
Jim
>
> In case when the secret must really be kept secret the QMP command must
> be fixed first, otherwise libvirt is not able to guarantee any secrecy.
>
>> + return -1;
>> +
>> + if (qemuMonitorJSONCheckError(cmd, reply) < 0)
>> + return -1;
>> +
>> + return 0;
>> +}
>
More information about the libvir-list
mailing list