提交 e5791a03 编写于 作者: B Brijesh Singh 提交者: Erik Skultety

conf: Introduce launch-security element in domain

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: NBrijesh Singh <brijesh.singh@amd.com>
Reviewed-by: NErik Skultety <eskultet@redhat.com>
上级 6596ac42
...@@ -8458,6 +8458,121 @@ qemu-kvm -net nic,model=? /dev/null ...@@ -8458,6 +8458,121 @@ qemu-kvm -net nic,model=? /dev/null
<p>Note: DEA/TDEA is synonymous with DES/TDES.</p> <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>&lt;launch-security type='sev'&gt;</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>
&lt;domain&gt;
...
&lt;launch-security type='sev'&gt;
&lt;policy&gt; 0x0001 &lt;/policy&gt;
&lt;cbitpos&gt; 47 &lt;/cbitpos&gt;
&lt;reduced-phys-bits&gt; 1 &lt;/reduced-phys-bits&gt;
&lt;session&gt; AAACCCDD=FFFCCCDSDS &lt;/session&gt;
&lt;dh-cert&gt; RBBBSDDD=FDDCCCDDDG &lt;/dh&gt;
&lt;/sev&gt;
...
&lt;/domain&gt;
</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> <h2><a id="examples">Example configs</a></h2>
<p> <p>
......
...@@ -77,6 +77,9 @@ ...@@ -77,6 +77,9 @@
<optional> <optional>
<ref name='keywrap'/> <ref name='keywrap'/>
</optional> </optional>
<optional>
<ref name='launch-security'/>
</optional>
</interleave> </interleave>
</element> </element>
</define> </define>
...@@ -436,6 +439,40 @@ ...@@ -436,6 +439,40 @@
</element> </element>
</define> </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 Enable or disable perf events for the domain. For each
of the events the following rules apply: of the events the following rules apply:
......
...@@ -944,6 +944,10 @@ VIR_ENUM_IMPL(virDomainShmemModel, VIR_DOMAIN_SHMEM_MODEL_LAST, ...@@ -944,6 +944,10 @@ VIR_ENUM_IMPL(virDomainShmemModel, VIR_DOMAIN_SHMEM_MODEL_LAST,
"ivshmem-plain", "ivshmem-plain",
"ivshmem-doorbell") "ivshmem-doorbell")
VIR_ENUM_IMPL(virDomainLaunchSecurity, VIR_DOMAIN_LAUNCH_SECURITY_LAST,
"",
"sev")
static virClassPtr virDomainObjClass; static virClassPtr virDomainObjClass;
static virClassPtr virDomainXMLOptionClass; static virClassPtr virDomainXMLOptionClass;
static void virDomainObjDispose(void *obj); static void virDomainObjDispose(void *obj);
...@@ -2957,6 +2961,19 @@ virDomainCachetuneDefFree(virDomainCachetuneDefPtr cachetune) ...@@ -2957,6 +2961,19 @@ virDomainCachetuneDefFree(virDomainCachetuneDefPtr cachetune)
} }
static void
virDomainSEVDefFree(virDomainSevDefPtr def)
{
if (!def)
return;
VIR_FREE(def->dh_cert);
VIR_FREE(def->session);
VIR_FREE(def);
}
void virDomainDefFree(virDomainDefPtr def) void virDomainDefFree(virDomainDefPtr def)
{ {
size_t i; size_t i;
...@@ -3139,6 +3156,8 @@ void virDomainDefFree(virDomainDefPtr def) ...@@ -3139,6 +3156,8 @@ void virDomainDefFree(virDomainDefPtr def)
if (def->namespaceData && def->ns.free) if (def->namespaceData && def->ns.free)
(def->ns.free)(def->namespaceData); (def->ns.free)(def->namespaceData);
virDomainSEVDefFree(def->sev);
xmlFreeNode(def->metadata); xmlFreeNode(def->metadata);
VIR_FREE(def); VIR_FREE(def);
...@@ -15826,6 +15845,85 @@ virDomainMemoryTargetDefParseXML(xmlNodePtr node, ...@@ -15826,6 +15845,85 @@ virDomainMemoryTargetDefParseXML(xmlNodePtr node,
} }
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 static virDomainMemoryDefPtr
virDomainMemoryDefParseXML(virDomainXMLOptionPtr xmlopt, virDomainMemoryDefParseXML(virDomainXMLOptionPtr xmlopt,
xmlNodePtr memdevNode, xmlNodePtr memdevNode,
...@@ -20631,6 +20729,13 @@ virDomainDefParseXML(xmlDocPtr xml, ...@@ -20631,6 +20729,13 @@ virDomainDefParseXML(xmlDocPtr xml,
ctxt->node = node; ctxt->node = node;
VIR_FREE(nodes); 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 */ /* analysis of memory devices */
if ((n = virXPathNodeSet("./devices/memory", ctxt, &nodes)) < 0) if ((n = virXPathNodeSet("./devices/memory", ctxt, &nodes)) < 0)
goto error; goto error;
...@@ -26642,6 +26747,32 @@ virDomainKeyWrapDefFormat(virBufferPtr buf, virDomainKeyWrapDefPtr keywrap) ...@@ -26642,6 +26747,32 @@ virDomainKeyWrapDefFormat(virBufferPtr buf, virDomainKeyWrapDefPtr keywrap)
virBufferAddLit(buf, "</keywrap>\n"); 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 static void
virDomainPerfDefFormat(virBufferPtr buf, virDomainPerfDefPtr perf) virDomainPerfDefFormat(virBufferPtr buf, virDomainPerfDefPtr perf)
{ {
...@@ -27906,6 +28037,8 @@ virDomainDefFormatInternal(virDomainDefPtr def, ...@@ -27906,6 +28037,8 @@ virDomainDefFormatInternal(virDomainDefPtr def,
if (def->keywrap) if (def->keywrap)
virDomainKeyWrapDefFormat(buf, def->keywrap); virDomainKeyWrapDefFormat(buf, def->keywrap);
virDomainSEVDefFormat(buf, def->sev);
virBufferAdjustIndent(buf, -2); virBufferAdjustIndent(buf, -2);
virBufferAddLit(buf, "</domain>\n"); virBufferAddLit(buf, "</domain>\n");
......
...@@ -142,6 +142,9 @@ typedef virDomainPanicDef *virDomainPanicDefPtr; ...@@ -142,6 +142,9 @@ typedef virDomainPanicDef *virDomainPanicDefPtr;
typedef struct _virDomainMemoryDef virDomainMemoryDef; typedef struct _virDomainMemoryDef virDomainMemoryDef;
typedef virDomainMemoryDef *virDomainMemoryDefPtr; typedef virDomainMemoryDef *virDomainMemoryDefPtr;
typedef struct _virDomainSevDef virDomainSevDef;
typedef virDomainSevDef *virDomainSevDefPtr;
/* forward declarations virDomainChrSourceDef, required by /* forward declarations virDomainChrSourceDef, required by
* virDomainNetDef * virDomainNetDef
*/ */
...@@ -2317,6 +2320,26 @@ struct _virDomainKeyWrapDef { ...@@ -2317,6 +2320,26 @@ struct _virDomainKeyWrapDef {
int dea; /* enum virTristateSwitch */ 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 { typedef enum {
VIR_DOMAIN_IOMMU_MODEL_INTEL, VIR_DOMAIN_IOMMU_MODEL_INTEL,
...@@ -2508,6 +2531,9 @@ struct _virDomainDef { ...@@ -2508,6 +2531,9 @@ struct _virDomainDef {
virDomainKeyWrapDefPtr keywrap; virDomainKeyWrapDefPtr keywrap;
/* SEV-specific domain */
virDomainSevDefPtr sev;
/* Application-specific custom metadata */ /* Application-specific custom metadata */
xmlNodePtr metadata; xmlNodePtr metadata;
...@@ -3418,6 +3444,7 @@ VIR_ENUM_DECL(virDomainMemoryAllocation) ...@@ -3418,6 +3444,7 @@ VIR_ENUM_DECL(virDomainMemoryAllocation)
VIR_ENUM_DECL(virDomainIOMMUModel) VIR_ENUM_DECL(virDomainIOMMUModel)
VIR_ENUM_DECL(virDomainVsockModel) VIR_ENUM_DECL(virDomainVsockModel)
VIR_ENUM_DECL(virDomainShmemModel) VIR_ENUM_DECL(virDomainShmemModel)
VIR_ENUM_DECL(virDomainLaunchSecurity)
/* from libvirt.h */ /* from libvirt.h */
VIR_ENUM_DECL(virDomainState) VIR_ENUM_DECL(virDomainState)
VIR_ENUM_DECL(virDomainNostateReason) VIR_ENUM_DECL(virDomainNostateReason)
......
<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>
...@@ -143,6 +143,8 @@ mymain(void) ...@@ -143,6 +143,8 @@ mymain(void)
DO_TEST("tseg"); DO_TEST("tseg");
DO_TEST("launch-security-sev");
virObjectUnref(caps); virObjectUnref(caps);
virObjectUnref(xmlopt); virObjectUnref(xmlopt);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册