<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 the 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.4.0</span>
+ </p>
+ <pre>
+<domain>
+ ...
+ <launch-security type='sev'>
+ <policy> 0x0001 </policy>
+ <cbitpos> 47 </cbitpos>
+ <reduced-phys-bits> 1 </reduced-phys-bits>
+ <session> AAACCCDD=FFFCCCDSDS </session>
+ <dh-cert> RBBBSDDD=FDDCCCDDDG </dh>
+ </sev>
+ ...
+</domain>
+</pre>
+
+ <dl>
+ <dt><code>cbitpos</code></dt>
+ <dd>The required <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 the domain capabilities.
+ </dd>
+ <dt><code>reduced-phys-bits</code></dt>
+ <dd>The required <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 the domain capabilities.
+ </dd>
+ <dt><code>policy</code></dt>
+ <dd>The required <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 unsigned byte 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> 6:15 </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>
+
+ </dd>
+ <dt><code>dh-cert</code></dt>
+ <dd>The optional <code>dh-cert</code> element provides the guest owners
+ base64 encoded 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.
+ </dd>
+ <dt><code>session</code></dt>
+ <dd>The optional <code>session</code> element provides the guest owners
+ base64 encoded session blob defined in the SEV API spec.
+
+ See SEV spec LAUNCH_START section for the session blob format.
+ </dd>
+ </dl>
+
<h2><a id="examples">Example configs</a></h2>
<p>
<optional>
<ref name='keywrap'/>
</optional>
+ <optional>
+ <ref name='launch-security'/>
+ </optional>
</interleave>
</element>
</define>
</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>
+ <element name="policy">
+ <ref name='hexuint'/>
+ </element>
+ <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:
"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);
}
+static void
+virDomainSEVDefFree(virDomainSevDefPtr def)
+{
+ if (!def)
+ return;
+
+ VIR_FREE(def->dh_cert);
+ VIR_FREE(def->session);
+
+ VIR_FREE(def);
+}
+
+
void virDomainDefFree(virDomainDefPtr def)
{
size_t i;
if (def->namespaceData && def->ns.free)
(def->ns.free)(def->namespaceData);
+ virDomainSEVDefFree(def->sev);
+
xmlFreeNode(def->metadata);
VIR_FREE(def);
}
+static virDomainSevDefPtr
+virDomainSEVDefParseXML(xmlNodePtr sevNode,
+ xmlXPathContextPtr ctxt)
+{
+ char *tmp = NULL;
+ char *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;
+ }
+
+ def->sectype = virDomainLaunchSecurityTypeFromString(type);
+ switch ((virDomainLaunchSecurity) def->sectype) {
+ case VIR_DOMAIN_LAUNCH_SECURITY_SEV:
+ break;
+ case VIR_DOMAIN_LAUNCH_SECURITY_NONE:
+ case VIR_DOMAIN_LAUNCH_SECURITY_LAST:
+ default:
+ virReportError(VIR_ERR_XML_ERROR,
+ _("unsupported launch-security type '%s'"),
+ type);
+ goto error;
+ }
+
+ if (virXPathUInt("string(./cbitpos)", ctxt, &def->cbitpos) < 0) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("failed to get launch-security cbitpos"));
+ goto error;
+ }
+
+ if (virXPathUInt("string(./reduced-phys-bits)", ctxt,
+ &def->reduced_phys_bits) < 0) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("failed to get launch-security reduced-phys-bits"));
+ goto error;
+ }
+
+ if (virXPathULongHex("string(./policy)", ctxt, &policy) < 0) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("failed to get launch-security policy"));
+ goto error;
+ }
+
+ 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,
xmlNodePtr memdevNode,
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;
virBufferAddLit(buf, "</keywrap>\n");
}
+
+static void
+virDomainSEVDefFormat(virBufferPtr buf, virDomainSevDefPtr sev)
+{
+ if (!sev)
+ return;
+
+ virBufferAsprintf(buf, "<launch-security type='%s'>\n",
+ virDomainLaunchSecurityTypeToString(sev->sectype));
+ 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>0x%04x</policy>\n", sev->policy);
+ if (sev->dh_cert)
+ virBufferEscapeString(buf, "<dh-cert>%s</dh-cert>\n", sev->dh_cert);
+
+ if (sev->session)
+ virBufferEscapeString(buf, "<session>%s</session>\n", sev->session);
+
+ virBufferAdjustIndent(buf, -2);
+ virBufferAddLit(buf, "</launch-security>\n");
+}
+
+
static void
virDomainPerfDefFormat(virBufferPtr buf, virDomainPerfDefPtr perf)
{
if (def->keywrap)
virDomainKeyWrapDefFormat(buf, def->keywrap);
+ virDomainSEVDefFormat(buf, def->sev);
+
virBufferAdjustIndent(buf, -2);
virBufferAddLit(buf, "</domain>\n");
typedef struct _virDomainMemoryDef virDomainMemoryDef;
typedef virDomainMemoryDef *virDomainMemoryDefPtr;
+typedef struct _virDomainSevDef virDomainSevDef;
+typedef virDomainSevDef *virDomainSevDefPtr;
+
/* forward declarations virDomainChrSourceDef, required by
* virDomainNetDef
*/
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 {
+ int sectype; /* enum virDomainLaunchSecurity */
+ char *dh_cert;
+ char *session;
+ unsigned int policy;
+ unsigned int cbitpos;
+ unsigned int reduced_phys_bits;
+};
+
+
typedef enum {
VIR_DOMAIN_IOMMU_MODEL_INTEL,
virDomainKeyWrapDefPtr keywrap;
+ /* SEV-specific domain */
+ virDomainSevDefPtr sev;
+
/* Application-specific custom metadata */
xmlNodePtr metadata;
VIR_ENUM_DECL(virDomainIOMMUModel)
VIR_ENUM_DECL(virDomainVsockModel)
VIR_ENUM_DECL(virDomainShmemModel)
+VIR_ENUM_DECL(virDomainLaunchSecurity)
/* from libvirt.h */
VIR_ENUM_DECL(virDomainState)
VIR_ENUM_DECL(virDomainNostateReason)
--- /dev/null
+<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>
+ </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>
DO_TEST("tseg");
+ DO_TEST("launch-security-sev");
+
virObjectUnref(caps);
virObjectUnref(xmlopt);