[libvirt] [PATCH v2 3/9] conf: introduce launch-security element in domain
Daniel P. Berrangé
berrange at redhat.com
Mon Mar 12 13:34:54 UTC 2018
On Thu, Mar 08, 2018 at 11:12:02AM -0600, Brijesh Singh wrote:
> The launch-security element can be used to define the security
> model to use when launching a domain. Currently we support 'sev'.
>
> When 'sev' is used, the VM will be launched with AMD SEV feature enabled.
> SEV feature supports running encrypted VM under the control of KVM.
> Encrypted VMs have their pages (code and data) secured such that only the
> guest itself has access to the unencrypted version. Each encrypted VM is
> associated with a unique encryption key; if its data is accessed to a
> different entity using a different key the encrypted guests data will be
> incorrectly decrypted, leading to unintelligible data.
>
> Signed-off-by: Brijesh Singh <brijesh.singh at amd.com>
> ---
> docs/formatdomain.html.in | 120 ++++++++++++++++++++++++++++++++++++++++++
> docs/schemas/domaincommon.rng | 39 ++++++++++++++
> src/conf/domain_conf.c | 111 ++++++++++++++++++++++++++++++++++++++
> src/conf/domain_conf.h | 27 ++++++++++
> 4 files changed, 297 insertions(+)
>
> diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
> index 6fd2189cd2f4..830d2a3c59be 100644
> --- a/docs/formatdomain.html.in
> +++ b/docs/formatdomain.html.in
> @@ -8195,6 +8195,126 @@ qemu-kvm -net nic,model=? /dev/null
>
> <p>Note: DEA/TDEA is synonymous with DES/TDES.</p>
>
> + <h3><a id="sev">Secure Encrypted Virtualization (SEV)</a></h3>
> +
> + <p>
> + The contents of the <code><launch-security type='sev'></code> element
> + is used to provide the guest owners input used for creating an encrypted
> + VM using the AMD SEV feature.
> +
> + SEV is an extension to the AMD-V architecture which supports running
> + encrypted virtual machine (VMs) under the control of KVM. Encrypted
> + VMs have their pages (code and data) secured such that only the guest
> + itself has access to the unencrypted version. Each encrypted VM is
> + associated with a unique encryption key; if its data is accessed to a
> + different entity using a different key the encrypted guests data will
> + be incorrectly decrypted, leading to unintelligible data.
> +
> + For more information see various input parameters and its format see SEV API spec
> + <a href="https://support.amd.com/TechDocs/55766_SEV-KM%20API_Specification.pdf"> https://support.amd.com/TechDocs/55766_SEV-KM%20API_Specification.pdf </a>
> + <span class="since">Since 4.2.0</span>
> + </p>
> + <pre>
> +<domain>
> + ...
> + <launch-security type='sev'>
> + <policy> 0 </policy>
> + <cbitpos> 47 </cbitpos>
> + <reduced-phys-bits> 5 </reduced-phys-bits>
> + <session> ... </session>
> + <dh-cert> ... </dh>
> + </sev>
> + ...
> +</domain>
> +</pre>
> +
> + <p>
> + A least <code>cbitpos</code> and <code>reduced-phys-bits</code> must be
> + nested within the <code>launch-security</code> element.
> + </p>
> + <dl>
> + <dt><code>cbitpos</code></dt>
> + <dd>The <code>cbitpos</code> element provides the C-bit (aka encryption bit)
> + location in guest page table entry. The value of <code>cbitpos</code> is
> + hypervisor dependent and can be obtained through the <code>sev</code> element
> + from domaincapabilities.
> + </dd>
> + <dt><code>reduced-phys-bits</code></dt>
> + <dd>The <code>reduced-phys-bits</code> element provides the physical
> + address bit reducation. Similar to <code>cbitpos</code> the value of <code>
> + reduced-phys-bit</code> is hypervisor dependent and can be obtained
> + through the <code>sev</code> element from domaincapabilities.
> + </dd>
> + <dt><code>policy</code></dt>
> + <dd>The optional <code>policy</code> element provides the guest policy
> + which must be maintained by the SEV firmware. This policy is enforced by
> + the firmware and restricts what configuration and operational commands
> + can be performed on this guest by the hypervisor. The guest policy
> + provided during guest launch is bound to the guest and cannot be changed
> + throughout the lifetime of the guest. The policy is also transmitted
> + during snapshot and migration flows and enforced on the destination platform.
> +
> + The guest policy is a 4-byte structure with the fields shown in Table:
> +
> + <table class="top_table">
> + <tr>
> + <th> Bit(s) </th>
> + <th> Description </th>
> + </tr>
> + <tr>
> + <td> 0 </td>
> + <td> Debugging of the guest is disallowed when set </td>
> + </tr>
> + <tr>
> + <td> 1 </td>
> + <td> Sharing keys with other guests is disallowed when set </td>
> + </tr>
> + <tr>
> + <td> 2 </td>
> + <td> SEV-ES is required when set</td>
> + </tr>
> + <tr>
> + <td> 3 </td>
> + <td> Sending the guest to another platform is disallowed when set</td>
> + </tr>
> + <tr>
> + <td> 4 </td>
> + <td> The guest must not be transmitted to another platform that is
> + not in the domain when set. </td>
> + </tr>
> + <tr>
> + <td> 5 </td>
> + <td> The guest must not be transmitted to another platform that is
> + not SEV capable when set. </td>
> + </tr>
> + <tr>
> + <td> 15:6 </td>
> + <td> reserved </td>
> + </tr>
> + <tr>
> + <td> 16:32 </td>
> + <td> The guest must not be transmitted to another platform with a
> + lower firmware version. </td>
> + </tr>
> + </table>
> + Default value is 0x1
> +
> + </dd>
> + <dt><code>dh-cert</code></dt>
> + <dd>The optional <code>dh-cert</code> element provides the guest owners public
> + Diffie-Hellman (DH) key. The key is used to negotiate a master secret
> + key between the SEV firmware and guest owner. This master secret key is
> + then used to establish a trusted channel between SEV firmware and guest
> + owner. The value must be encoded in base64.
> + </dd>
> + <dt><code>session</code></dt>
> + <dd>The optional <code>session</code> element provides the guest owners
> + session blob defined in SEV API spec. The value must be encoded in base64.
> +
> + See SEV spec LAUNCH_START section for session blob format.
> + </dd>
> + </dl>
> +
> <h2><a id="examples">Example configs</a></h2>
>
> <p>
> diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
> index 8165e699d67e..e3dcc69067c2 100644
> --- a/docs/schemas/domaincommon.rng
> +++ b/docs/schemas/domaincommon.rng
> @@ -77,6 +77,9 @@
> <optional>
> <ref name='keywrap'/>
> </optional>
> + <optional>
> + <ref name='launch-security'/>
> + </optional>
> </interleave>
> </element>
> </define>
> @@ -436,6 +439,42 @@
> </element>
> </define>
>
> + <define name="launch-security">
> + <element name="launch-security">
> + <attribute name="type">
> + <value>sev</value>
> + </attribute>
> + <interleave>
> + <element name="cbitpos">
> + <data type='unsignedInt'/>
> + </element>
> + <element name="reduced-phys-bits">
> + <data type='unsignedInt'/>
> + </element>
> + <optional>
> + <element name="policy">
> + <ref name='hexuint'/>
> + </element>
> + </optional>
> + <optional>
> + <element name="handle">
> + <ref name='unsignedInt'/>
> + </element>
> + </optional>
> + <optional>
> + <element name="dh-cert">
> + <data type="string"/>
> + </element>
> + </optional>
> + <optional>
> + <element name="session">
> + <data type="string"/>
> + </element>
> + </optional>
> + </interleave>
> + </element>
> + </define>
> +
> <!--
> Enable or disable perf events for the domain. For each
> of the events the following rules apply:
> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
> index fcafc8b2fafe..52d34de69d45 100644
> --- a/src/conf/domain_conf.c
> +++ b/src/conf/domain_conf.c
> @@ -929,6 +929,10 @@ VIR_ENUM_IMPL(virDomainShmemModel, VIR_DOMAIN_SHMEM_MODEL_LAST,
> "ivshmem-plain",
> "ivshmem-doorbell")
>
> +VIR_ENUM_IMPL(virDomainLaunchSecurity, VIR_DOMAIN_LAUNCH_SECURITY_LAST,
> + "",
> + "sev")
> +
> static virClassPtr virDomainObjClass;
> static virClassPtr virDomainXMLOptionClass;
> static void virDomainObjDispose(void *obj);
> @@ -2897,6 +2901,14 @@ virDomainCachetuneDefFree(virDomainCachetuneDefPtr cachetune)
> VIR_FREE(cachetune);
> }
>
> +static void
> +virDomainSevDefFree(virDomainSevDefPtr def)
> +{
> + VIR_FREE(def->dh_cert);
> + VIR_FREE(def->session);
> +
> + VIR_FREE(def);
> +}
>
> void virDomainDefFree(virDomainDefPtr def)
> {
> @@ -3079,6 +3091,9 @@ void virDomainDefFree(virDomainDefPtr def)
> if (def->namespaceData && def->ns.free)
> (def->ns.free)(def->namespaceData);
>
> + if (def->sev)
> + virDomainSevDefFree(def->sev);
> +
> xmlFreeNode(def->metadata);
>
> VIR_FREE(def);
> @@ -15539,6 +15554,71 @@ virDomainMemoryTargetDefParseXML(xmlNodePtr node,
> return ret;
> }
>
> +static virDomainSevDefPtr
> +virDomainSevDefParseXML(xmlNodePtr sevNode,
> + xmlXPathContextPtr ctxt)
> +{
> + char *tmp = NULL, *type = NULL;
> + xmlNodePtr save = ctxt->node;
> + virDomainSevDefPtr def;
> + unsigned long policy;
> +
> + ctxt->node = sevNode;
> +
> + if (VIR_ALLOC(def) < 0)
> + return NULL;
> +
> + if (!(type = virXMLPropString(sevNode, "type"))) {
> + virReportError(VIR_ERR_XML_ERROR, "%s",
> + _("missing launch-security type"));
> + goto error;
> + }
> +
> + if (virDomainLaunchSecurityTypeFromString(type) !=
> + VIR_DOMAIN_LAUNCH_SECURITY_SEV) {
> + goto error;
> + }
> +
> + if (virXPathInt("string(./cbitpos)", ctxt, &def->cbitpos) < 0) {
> + virReportError(VIR_ERR_XML_ERROR, "%s", _("failed to get cbitpos"));
> + goto error;
> + }
> +
> + if (virXPathInt("string(./reduced-phys-bits)", ctxt,
> + &def->reduced_phys_bits) < 0) {
> + virReportError(VIR_ERR_XML_ERROR, "%s",
> + _("failed to get reduced-phys-bits"));
> + goto error;
> + }
> +
> + if (virXPathULongHex("string(./policy)", ctxt, &policy) < 0)
> + policy = 0x1;
> +
> + def->policy = policy;
> +
> + if ((tmp = virXPathString("string(./dh-cert)", ctxt))) {
> + if (VIR_STRDUP(def->dh_cert, tmp) < 0)
> + goto error;
> +
> + VIR_FREE(tmp);
> + }
> +
> + if ((tmp = virXPathString("string(./session)", ctxt))) {
> + if (VIR_STRDUP(def->session, tmp) < 0)
> + goto error;
> +
> + VIR_FREE(tmp);
> + }
> +
> + ctxt->node = save;
> + return def;
> +
> + error:
> + VIR_FREE(tmp);
> + virDomainSevDefFree(def);
> + ctxt->node = save;
> + return NULL;
> +}
>
> static virDomainMemoryDefPtr
> virDomainMemoryDefParseXML(virDomainXMLOptionPtr xmlopt,
> @@ -20212,6 +20292,13 @@ virDomainDefParseXML(xmlDocPtr xml,
> ctxt->node = node;
> VIR_FREE(nodes);
>
> + /* Check for SEV feature */
> + if ((node = virXPathNode("./launch-security", ctxt)) != NULL) {
> + def->sev = virDomainSevDefParseXML(node, ctxt);
> + if (!def->sev)
> + goto error;
> + }
> +
> /* analysis of memory devices */
> if ((n = virXPathNodeSet("./devices/memory", ctxt, &nodes)) < 0)
> goto error;
> @@ -26102,6 +26189,27 @@ virDomainKeyWrapDefFormat(virBufferPtr buf, virDomainKeyWrapDefPtr keywrap)
> virBufferAddLit(buf, "</keywrap>\n");
> }
>
> +static void
> +virDomainSevDefFormat(virBufferPtr buf, virDomainSevDefPtr sev)
> +{
> + virBufferAddLit(buf, "<launch-security type='sev'>\n");
> + virBufferAdjustIndent(buf, 2);
> +
> + virBufferAsprintf(buf, "<cbitpos>%d</cbitpos>\n", sev->cbitpos);
> + virBufferAsprintf(buf, "<reduced-phys-bits>%d</reduced-phys-bits>\n",
> + sev->reduced_phys_bits);
> + virBufferAsprintf(buf, "<policy>%d</policy>\n", sev->policy);
> + if (sev->dh_cert)
> + virBufferAsprintf(buf, "<dh_cert>%s</dh_cert>\n", sev->dh_cert);
> +
> + if (sev->session)
> + virBufferAsprintf(buf, "<session>%s</session>\n", sev->session);
> +
> + virBufferAdjustIndent(buf, -2);
> + virBufferAddLit(buf, "</launch-security>\n");
> +}
> +
> +
> static void
> virDomainPerfDefFormat(virBufferPtr buf, virDomainPerfDefPtr perf)
> {
> @@ -27274,6 +27382,9 @@ virDomainDefFormatInternal(virDomainDefPtr def,
> if (def->keywrap)
> virDomainKeyWrapDefFormat(buf, def->keywrap);
>
> + if (def->sev)
> + virDomainSevDefFormat(buf, def->sev);
> +
> virBufferAdjustIndent(buf, -2);
> virBufferAddLit(buf, "</domain>\n");
>
> diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
> index 368f16f3fbf9..ff625a0aff1b 100644
> --- a/src/conf/domain_conf.h
> +++ b/src/conf/domain_conf.h
> @@ -142,6 +142,9 @@ typedef virDomainPanicDef *virDomainPanicDefPtr;
> typedef struct _virDomainMemoryDef virDomainMemoryDef;
> typedef virDomainMemoryDef *virDomainMemoryDefPtr;
>
> +typedef struct _virDomainSevDef virDomainSevDef;
> +typedef virDomainSevDef *virDomainSevDefPtr;
> +
> /* forward declarations virDomainChrSourceDef, required by
> * virDomainNetDef
> */
> @@ -2289,6 +2292,26 @@ struct _virDomainKeyWrapDef {
> int dea; /* enum virTristateSwitch */
> };
>
> +typedef enum {
> + VIR_DOMAIN_LAUNCH_SECURITY_NONE,
> + VIR_DOMAIN_LAUNCH_SECURITY_SEV,
> +
> + VIR_DOMAIN_LAUNCH_SECURITY_LAST,
> +} virDomainLaunchSecurity;
> +
> +typedef struct _virDomainSevDef virDomainSevDef;
> +typedef virDomainSevDef *virDomainSevDefPtr;
> +
> +struct _virDomainSevDef {
> + char *dh_cert;
> + char *session;
> + char *configDir;
> + int policy;
> + int cbitpos;
> + int reduced_phys_bits;
> +};
I'd suggested 'unsigned int' for these 3 variables, assuming they
don't ever need -ve values.
Reviewed-by: Daniel P. Berrangé <berrange at redhat.com>
Regards,
Daniel
--
|: https://berrange.com -o- https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org -o- https://fstop138.berrange.com :|
|: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|
More information about the libvir-list
mailing list