[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