]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
conf: Add tdx as launch security type
authorZhenzhong Duan <zhenzhong.duan@intel.com>
Thu, 10 Jul 2025 07:21:09 +0000 (03:21 -0400)
committerDaniel P. Berrangé <berrange@redhat.com>
Fri, 25 Jul 2025 10:27:56 +0000 (11:27 +0100)
When 'tdx' is used, the VM will be launched with Intel TDX feature enabled.
TDX feature supports running encrypted VM (Trust Domain, TD) under the
control of KVM. A TD runs in a CPU model which protects the confidentiality
of its memory and its CPU state from other software.

There are four optional child elements. Element policy is 64bit hex, bit 0
is set to enable TDX debug, bit 28 is set to enable sept-ve-disable, other
bits are reserved currently. When policy isn't specified, QEMU will use its
own default value 0x10000000. mrConfigId, mrOwner and mrOwnerConfig are
base64 encoded SHA384 digest string.

For example:

 <launchSecurity type='tdx'>
   <policy>0x10000001</policy>
   <mrConfigId>xxx</mrConfigId>
   <mrOwner>xxx</mrOwner>
   <mrOwnerConfig>xxx</mrOwnerConfig>
 </launchSecurity>

Signed-off-by: Zhenzhong Duan <zhenzhong.duan@intel.com>
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
13 files changed:
src/conf/domain_conf.c
src/conf/domain_conf.h
src/conf/domain_validate.c
src/conf/schemas/domaincommon.rng
src/conf/virconftypes.h
src/qemu/qemu_cgroup.c
src/qemu/qemu_command.c
src/qemu/qemu_driver.c
src/qemu/qemu_firmware.c
src/qemu/qemu_namespace.c
src/qemu/qemu_process.c
src/qemu/qemu_validate.c
src/security/security_dac.c

index 23feb2f4daef327d9fd2be9cf56ebca344343262..37d9e2bf72a9a150f10757af97faf5f5be3489c9 100644 (file)
@@ -1543,6 +1543,7 @@ VIR_ENUM_IMPL(virDomainLaunchSecurity,
               "sev",
               "sev-snp",
               "s390-pv",
+              "tdx",
 );
 
 VIR_ENUM_IMPL(virDomainPstoreBackend,
@@ -3958,6 +3959,11 @@ virDomainSecDefFree(virDomainSecDef *def)
         g_free(def->data.sev_snp.id_auth);
         g_free(def->data.sev_snp.host_data);
         break;
+    case VIR_DOMAIN_LAUNCH_SECURITY_TDX:
+        g_free(def->data.tdx.mrconfigid);
+        g_free(def->data.tdx.mrowner);
+        g_free(def->data.tdx.mrownerconfig);
+        break;
     case VIR_DOMAIN_LAUNCH_SECURITY_PV:
     case VIR_DOMAIN_LAUNCH_SECURITY_NONE:
     case VIR_DOMAIN_LAUNCH_SECURITY_LAST:
@@ -14167,6 +14173,29 @@ virDomainSEVSNPDefParseXML(virDomainSEVSNPDef *def,
 }
 
 
+static int
+virDomainTDXDefParseXML(virDomainTDXDef *def,
+                        xmlXPathContextPtr ctxt)
+{
+    int rc;
+
+    rc = virXPathULongLongBase("string(./policy)", ctxt, 16, &def->policy);
+    if (rc == 0) {
+        def->havePolicy = true;
+    } else if (rc == -2) {
+        virReportError(VIR_ERR_XML_ERROR, "%s",
+                       _("failed to get launch security policy for launch security type TDX"));
+        return -1;
+    }
+
+    def->mrconfigid = virXPathString("string(./mrConfigId)", ctxt);
+    def->mrowner = virXPathString("string(./mrOwner)", ctxt);
+    def->mrownerconfig = virXPathString("string(./mrOwnerConfig)", ctxt);
+
+    return 0;
+}
+
+
 static virDomainSecDef *
 virDomainSecDefParseXML(xmlNodePtr lsecNode,
                         xmlXPathContextPtr ctxt)
@@ -14190,6 +14219,10 @@ virDomainSecDefParseXML(xmlNodePtr lsecNode,
         if (virDomainSEVSNPDefParseXML(&sec->data.sev_snp, ctxt) < 0)
             return NULL;
         break;
+    case VIR_DOMAIN_LAUNCH_SECURITY_TDX:
+        if (virDomainTDXDefParseXML(&sec->data.tdx, ctxt) < 0)
+            return NULL;
+        break;
     case VIR_DOMAIN_LAUNCH_SECURITY_PV:
         break;
     case VIR_DOMAIN_LAUNCH_SECURITY_NONE:
@@ -27663,6 +27696,18 @@ virDomainSEVSNPDefFormat(virBuffer *attrBuf,
 }
 
 
+static void
+virDomainTDXDefFormat(virBuffer *childBuf, virDomainTDXDef *def)
+{
+    if (def->havePolicy)
+        virBufferAsprintf(childBuf, "<policy>0x%llx</policy>\n", def->policy);
+
+    virBufferEscapeString(childBuf, "<mrConfigId>%s</mrConfigId>\n", def->mrconfigid);
+    virBufferEscapeString(childBuf, "<mrOwner>%s</mrOwner>\n", def->mrowner);
+    virBufferEscapeString(childBuf, "<mrOwnerConfig>%s</mrOwnerConfig>\n", def->mrownerconfig);
+}
+
+
 static void
 virDomainSecDefFormat(virBuffer *buf, virDomainSecDef *sec)
 {
@@ -27684,6 +27729,10 @@ virDomainSecDefFormat(virBuffer *buf, virDomainSecDef *sec)
         virDomainSEVSNPDefFormat(&attrBuf, &childBuf, &sec->data.sev_snp);
         break;
 
+    case VIR_DOMAIN_LAUNCH_SECURITY_TDX:
+        virDomainTDXDefFormat(&childBuf, &sec->data.tdx);
+        break;
+
     case VIR_DOMAIN_LAUNCH_SECURITY_PV:
         break;
 
index 6008ec66d3fe6bb7b4f2a7857434056814e45002..5c4e02fb1611254ed1cd4cedcb3a3d9fc48d7f80 100644 (file)
@@ -2965,6 +2965,7 @@ typedef enum {
     VIR_DOMAIN_LAUNCH_SECURITY_SEV,
     VIR_DOMAIN_LAUNCH_SECURITY_SEV_SNP,
     VIR_DOMAIN_LAUNCH_SECURITY_PV,
+    VIR_DOMAIN_LAUNCH_SECURITY_TDX,
 
     VIR_DOMAIN_LAUNCH_SECURITY_LAST,
 } virDomainLaunchSecurity;
@@ -2999,11 +3000,21 @@ struct _virDomainSEVSNPDef {
 };
 
 
+struct _virDomainTDXDef {
+    bool havePolicy;
+    unsigned long long policy;
+    char *mrconfigid;
+    char *mrowner;
+    char *mrownerconfig;
+};
+
+
 struct _virDomainSecDef {
     virDomainLaunchSecurity sectype;
     union {
         virDomainSEVDef sev;
         virDomainSEVSNPDef sev_snp;
+        virDomainTDXDef tdx;
     } data;
 };
 
index c7afdbf7fd13b092d3c9aee223484626e5612081..9b7418ccb5583dc4493bed98fb6b6a0675a85744 100644 (file)
@@ -1936,6 +1936,7 @@ virDomainDefLaunchSecurityValidate(const virDomainDef *def)
     case VIR_DOMAIN_LAUNCH_SECURITY_NONE:
     case VIR_DOMAIN_LAUNCH_SECURITY_SEV:
     case VIR_DOMAIN_LAUNCH_SECURITY_PV:
+    case VIR_DOMAIN_LAUNCH_SECURITY_TDX:
     case VIR_DOMAIN_LAUNCH_SECURITY_LAST:
         break;
     }
index 2d6e15f144451af3dede9958177b4234cef4f759..bb40e1d439394c767380373916e9ca04c520c76d 100644 (file)
             <value>s390-pv</value>
           </attribute>
         </group>
+        <group>
+          <ref name="launchSecurityTDX"/>
+        </group>
       </choice>
     </element>
   </define>
       </optional>
     </interleave>
   </define>
+
+  <define name="launchSecurityTDX">
+    <attribute name="type">
+      <value>tdx</value>
+    </attribute>
+    <interleave>
+      <optional>
+        <element name="policy">
+          <ref name="hexuint"/>
+        </element>
+      </optional>
+      <optional>
+        <element name="mrConfigId">
+          <data type="string"/>
+        </element>
+      </optional>
+      <optional>
+        <element name="mrOwner">
+          <data type="string"/>
+        </element>
+      </optional>
+      <optional>
+        <element name="mrOwnerConfig">
+          <data type="string"/>
+        </element>
+      </optional>
+    </interleave>
+  </define>
+
   <!--
       Enable or disable perf events for the domain. For each
       of the events the following rules apply:
index 8c6fcdbeaabdba97bcaf51ff656505ade29b898f..93fc9c9217ce032adb7587f881e293c00e9a111c 100644 (file)
@@ -220,6 +220,8 @@ typedef struct _virDomainSEVDef virDomainSEVDef;
 
 typedef struct _virDomainSEVSNPDef virDomainSEVSNPDef;
 
+typedef struct _virDomainTDXDef virDomainTDXDef;
+
 typedef struct _virDomainSecDef virDomainSecDef;
 
 typedef struct _virDomainShmemDef virDomainShmemDef;
index 25e42ebfc69564d291475279d4106002e433df15..f10976c2b0d7cb9e4c2c2a45c12c22f602334d60 100644 (file)
@@ -863,6 +863,7 @@ qemuSetupDevicesCgroup(virDomainObj *vm)
                 return -1;
             break;
         case VIR_DOMAIN_LAUNCH_SECURITY_PV:
+        case VIR_DOMAIN_LAUNCH_SECURITY_TDX:
             break;
         case VIR_DOMAIN_LAUNCH_SECURITY_NONE:
         case VIR_DOMAIN_LAUNCH_SECURITY_LAST:
index 4b1e36a4c1d0cf9d4ed69928b1dfa7ca33236aca..9ad3aeb1c89a34e501365dfc5d1ddbb7a16337ca 100644 (file)
@@ -7195,6 +7195,7 @@ qemuBuildMachineCommandLine(virCommand *cmd,
             }
             break;
         case VIR_DOMAIN_LAUNCH_SECURITY_PV:
+        case VIR_DOMAIN_LAUNCH_SECURITY_TDX:
             virBufferAddLit(&buf, ",confidential-guest-support=lsec0");
             break;
         case VIR_DOMAIN_LAUNCH_SECURITY_NONE:
@@ -9974,6 +9975,7 @@ qemuBuildSecCommandLine(virDomainObj *vm, virCommand *cmd,
     case VIR_DOMAIN_LAUNCH_SECURITY_PV:
         return qemuBuildPVCommandLine(cmd);
 
+    case VIR_DOMAIN_LAUNCH_SECURITY_TDX:
     case VIR_DOMAIN_LAUNCH_SECURITY_NONE:
     case VIR_DOMAIN_LAUNCH_SECURITY_LAST:
         virReportEnumRangeError(virDomainLaunchSecurity, sec->sectype);
index a0f770b0532c5e2771e213914d31886bb6befc4b..30c4fadeeb6f2a7c64338a6b80baa7f98111b482 100644 (file)
@@ -19293,6 +19293,7 @@ qemuDomainGetLaunchSecurityInfo(virDomainPtr domain,
             goto cleanup;
         break;
     case VIR_DOMAIN_LAUNCH_SECURITY_PV:
+    case VIR_DOMAIN_LAUNCH_SECURITY_TDX:
         break;
     case VIR_DOMAIN_LAUNCH_SECURITY_NONE:
     case VIR_DOMAIN_LAUNCH_SECURITY_LAST:
index 2d0ec0b4fa228a0bdf996a4301b203f593a28ee0..6c65a2751b763a437c82578a64b21b6b52b3a020 100644 (file)
@@ -1371,6 +1371,7 @@ qemuFirmwareMatchDomain(const virDomainDef *def,
             }
             break;
         case VIR_DOMAIN_LAUNCH_SECURITY_PV:
+        case VIR_DOMAIN_LAUNCH_SECURITY_TDX:
             break;
         case VIR_DOMAIN_LAUNCH_SECURITY_NONE:
         case VIR_DOMAIN_LAUNCH_SECURITY_LAST:
index 59421ec9d15c55f51f326ec5686ca7d706199352..f72da8392974e5ee3a5ab0fb2e331b6bac98087a 100644 (file)
@@ -665,6 +665,7 @@ qemuDomainSetupLaunchSecurity(virDomainObj *vm,
         VIR_DEBUG("Set up launch security for SEV");
         break;
     case VIR_DOMAIN_LAUNCH_SECURITY_PV:
+    case VIR_DOMAIN_LAUNCH_SECURITY_TDX:
         break;
     case VIR_DOMAIN_LAUNCH_SECURITY_NONE:
     case VIR_DOMAIN_LAUNCH_SECURITY_LAST:
index a2872602e879e6748267ca4d9865b8cc103efa6b..7921d17a9e7df4ec5e392ccb5c6fa1007e46b935 100644 (file)
@@ -6872,6 +6872,7 @@ qemuProcessPrepareDomain(virQEMUDriver *driver,
                 return -1;
             break;
         case VIR_DOMAIN_LAUNCH_SECURITY_PV:
+        case VIR_DOMAIN_LAUNCH_SECURITY_TDX:
             break;
         case VIR_DOMAIN_LAUNCH_SECURITY_NONE:
         case VIR_DOMAIN_LAUNCH_SECURITY_LAST:
@@ -6944,6 +6945,7 @@ qemuProcessPrepareLaunchSecurityGuestInput(virDomainObj *vm)
     case VIR_DOMAIN_LAUNCH_SECURITY_SEV_SNP:
         break;
     case VIR_DOMAIN_LAUNCH_SECURITY_PV:
+    case VIR_DOMAIN_LAUNCH_SECURITY_TDX:
         return 0;
     case VIR_DOMAIN_LAUNCH_SECURITY_NONE:
     case VIR_DOMAIN_LAUNCH_SECURITY_LAST:
index 57dc4171fefe123c24865c75067b92c43cb1b559..93e191dd1350f1815189627b5f94ea86c4f1b825 100644 (file)
@@ -1413,6 +1413,7 @@ qemuValidateDomainDef(const virDomainDef *def,
                 return -1;
             }
             break;
+        case VIR_DOMAIN_LAUNCH_SECURITY_TDX:
         case VIR_DOMAIN_LAUNCH_SECURITY_NONE:
         case VIR_DOMAIN_LAUNCH_SECURITY_LAST:
             virReportEnumRangeError(virDomainLaunchSecurity, def->sec->sectype);
index 3ecbc7277d6efa0bc7cc1eaedf4da1c84f191a42..2f788b872ae03dd5a35f43d3fff651ee57330be2 100644 (file)
@@ -2017,6 +2017,7 @@ virSecurityDACRestoreAllLabel(virSecurityManager *mgr,
                 rc = -1;
             break;
         case VIR_DOMAIN_LAUNCH_SECURITY_PV:
+        case VIR_DOMAIN_LAUNCH_SECURITY_TDX:
             break;
         case VIR_DOMAIN_LAUNCH_SECURITY_NONE:
         case VIR_DOMAIN_LAUNCH_SECURITY_LAST:
@@ -2263,6 +2264,7 @@ virSecurityDACSetAllLabel(virSecurityManager *mgr,
                 return -1;
             break;
         case VIR_DOMAIN_LAUNCH_SECURITY_PV:
+        case VIR_DOMAIN_LAUNCH_SECURITY_TDX:
             break;
         case VIR_DOMAIN_LAUNCH_SECURITY_NONE:
         case VIR_DOMAIN_LAUNCH_SECURITY_LAST: