[PATCH rfcv4 00/13] LIBVIRT: X86: TDX support

Hi, This series brings libvirt the x86 TDX support. * What's TDX? TDX stands for Trust Domain Extensions which isolates VMs from the virtual-machine manager (VMM)/hypervisor and any other software on the platform. To support TDX, multiple software components, not only KVM but also QEMU, guest Linux and virtual bios, need to be updated. For more details, please check link[1]. This patchset is another software component to extend libvirt to support TDX, with which one can start a TDX guest from high level rather than running qemu directly. * Misc As QEMU use a software emulated way to reset guest which isn't supported by TDX guest for security reason. We simulate reboot for TDX guest by kill and create a new one in FakeReboot framework. Complete code can be found at [2], matching qemu code can be found at [3]. There is a 'debug' property for tdx-guest object which isn't in matching qemu[3] yet. I keep them intentionally as they will be implemented in qemu as extention series of [3]. * Test start/stop/reboot with virsh stop/reboot trigger in guest stop with on_poweroff=destroy/restart reboot with on_reboot=destroy/restart * Patch organization - patch 1-4: Support query of TDX capabilities. - patch 5-8: Add TDX type to launchsecurity framework. - patch 9-11: Add reboot support to TDX guest - patch 12-13: Add test and docs TODO: - update QEMU capabilities data in tests, depending on qemu TDX merged beforehand - add reconnect logic in virsh command [1] https://lore.kernel.org/kvm/cover.1708933498.git.isaku.yamahata@intel.com [2] https://github.com/intel/libvirt-tdx/commits/tdx_for_upstream_rfcv4 [3] https://github.com/intel/qemu-tdx/tree/tdx-qemu-upstream-v5 Thanks Zhenzhong Changelog: rfcv4: - add a check to tools/virt-host-validate-qemu.c (Daniel) - remove check of q35 (Daniel) - model 'SocktetAddress' QAPI in xml schema (Daniel) - s/Quote-Generation-Service/quoteGenerationService/ (Daniel) - define bits in tdx->policy and add validating logic (Daniel) - presume QEMU choose split kernel irqchip for TDX guest by default (Daniel) - utilize existing FakeReboot framework to do reboot for TDX guest (Daniel) - drop patch11 'conf: Add support to keep same domid for hard reboot' (Daniel) - add test in tests/ to validate parsing and formatting logic (Daniel) - add doc in docs/formatdomain.rst (Daniel) - add R-B rfcv3: - Change to generate qemu cmdline with -bios - drop firmware auto match as -bios is used - add a hard reboot method to reboot TDX guest rfcv3: https://www.mail-archive.com/devel@lists.libvirt.org/msg00385.html rfcv2: - give up using qmp cmd and check TDX directly on host for TDX capabilities. - use launchsecurity framework to support TDX - use <os>.<loader> for general loader - add auto firmware match feature for TDX A example TDVF fimware description file 70-edk2-x86_64-tdx.json: { "description": "UEFI firmware for x86_64, supporting Intel TDX", "interface-types": [ "uefi" ], "mapping": { "device": "generic", "filename": "/usr/share/OVMF/OVMF_CODE-tdx.fd" }, "targets": [ { "architecture": "x86_64", "machines": [ "pc-q35-*" ] } ], "features": [ "intel-tdx", "verbose-dynamic" ], "tags": [ ] } rfcv2: https://www.mail-archive.com/libvir-list@redhat.com/msg219378.html Zhenzhong Duan (13): tools: Secure guest check for Intel in virt-host-validate qemu: Check if INTEL Trust Domain Extention support is enabled qemu: Add TDX capability conf: expose TDX feature in domain capabilities conf: add tdx as launch security type qemu: Add command line and validation for TDX type qemu: force special parameters enabled for TDX guest Add Intel TDX Quote Generation Service(QGS) support qemu: add FakeReboot support for TDX guest qemu: Support reboot command in guest qemu: Avoid duplicate FakeReboot for secure guest Add test cases for Intel TDX docs: domain: Add documentation for Intel TDX guest docs/formatdomain.rst | 68 ++++ docs/formatdomaincaps.rst | 1 + src/conf/domain_capabilities.c | 1 + src/conf/domain_capabilities.h | 1 + src/conf/domain_conf.c | 312 ++++++++++++++++++ src/conf/domain_conf.h | 75 +++++ src/conf/schemas/domaincaps.rng | 9 + src/conf/schemas/domaincommon.rng | 135 ++++++++ src/conf/virconftypes.h | 2 + src/qemu/qemu_capabilities.c | 36 +- src/qemu/qemu_capabilities.h | 1 + src/qemu/qemu_command.c | 139 ++++++++ src/qemu/qemu_firmware.c | 1 + src/qemu/qemu_monitor.c | 28 +- src/qemu/qemu_monitor.h | 2 +- src/qemu/qemu_monitor_json.c | 6 +- src/qemu/qemu_namespace.c | 1 + src/qemu/qemu_process.c | 75 +++++ src/qemu/qemu_validate.c | 44 +++ ...unch-security-tdx-qgs-fd.x86_64-latest.xml | 77 +++++ .../launch-security-tdx-qgs-fd.xml | 30 ++ ...ch-security-tdx-qgs-inet.x86_64-latest.xml | 77 +++++ .../launch-security-tdx-qgs-inet.xml | 30 ++ ...ch-security-tdx-qgs-unix.x86_64-latest.xml | 77 +++++ .../launch-security-tdx-qgs-unix.xml | 30 ++ ...h-security-tdx-qgs-vsock.x86_64-latest.xml | 77 +++++ .../launch-security-tdx-qgs-vsock.xml | 30 ++ tests/qemuxmlconftest.c | 24 ++ tools/virt-host-validate-common.c | 22 +- tools/virt-host-validate-common.h | 1 + 30 files changed, 1407 insertions(+), 5 deletions(-) create mode 100644 tests/qemuxmlconfdata/launch-security-tdx-qgs-fd.x86_64-latest.xml create mode 100644 tests/qemuxmlconfdata/launch-security-tdx-qgs-fd.xml create mode 100644 tests/qemuxmlconfdata/launch-security-tdx-qgs-inet.x86_64-latest.xml create mode 100644 tests/qemuxmlconfdata/launch-security-tdx-qgs-inet.xml create mode 100644 tests/qemuxmlconfdata/launch-security-tdx-qgs-unix.x86_64-latest.xml create mode 100644 tests/qemuxmlconfdata/launch-security-tdx-qgs-unix.xml create mode 100644 tests/qemuxmlconfdata/launch-security-tdx-qgs-vsock.x86_64-latest.xml create mode 100644 tests/qemuxmlconfdata/launch-security-tdx-qgs-vsock.xml -- 2.34.1

Add check in virt-host-validate for secure guest support on x86 for Intel Trust Domain Extentions. Suggested-by: Daniel P. Berrangé <berrange@redhat.com> Signed-off-by: Zhenzhong Duan <zhenzhong.duan@intel.com> --- tools/virt-host-validate-common.c | 22 +++++++++++++++++++++- tools/virt-host-validate-common.h | 1 + 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/tools/virt-host-validate-common.c b/tools/virt-host-validate-common.c index c8a23e2e99..4f0698b8ce 100644 --- a/tools/virt-host-validate-common.c +++ b/tools/virt-host-validate-common.c @@ -43,7 +43,8 @@ VIR_ENUM_IMPL(virHostValidateCPUFlag, "svm", "sie", "158", - "sev"); + "sev", + "tdx_host_platform"); static bool quiet; @@ -471,6 +472,7 @@ int virHostValidateSecureGuests(const char *hvname, g_autoptr(virBitmap) flags = NULL; bool hasFac158 = false; bool hasAMDSev = false; + bool hasIntelTDX = false; virArch arch = virArchFromHost(); g_autofree char *cmdline = NULL; static const char *kIBMValues[] = {"y", "Y", "on", "ON", "oN", "On", "1"}; @@ -482,6 +484,8 @@ int virHostValidateSecureGuests(const char *hvname, hasFac158 = true; else if (flags && virBitmapIsBitSet(flags, VIR_HOST_VALIDATE_CPU_FLAG_SEV)) hasAMDSev = true; + else if (flags && virBitmapIsBitSet(flags, VIR_HOST_VALIDATE_CPU_FLAG_TDX)) + hasIntelTDX = true; virHostMsgCheck(hvname, "%s", _("for secure guest support")); if (ARCH_IS_S390(arch)) { @@ -539,6 +543,22 @@ int virHostValidateSecureGuests(const char *hvname, "disabled in firmware."); return VIR_HOST_VALIDATE_FAILURE(level); } + } else if (hasIntelTDX) { + if (virFileReadValueString(&mod_value, "/sys/module/kvm_intel/parameters/tdx") < 0) { + virHostMsgFail(level, "Intel Trust Domain Extentions not " + "supported by the currently used kernel"); + return VIR_HOST_VALIDATE_FAILURE(level); + } + + if (mod_value[0] != 'Y') { + virHostMsgFail(level, + "Intel Trust Domain Extentions appears to be " + "disabled in kernel. Add kvm_intel.tdx=Y " + "to the kernel cmdline arguments"); + return VIR_HOST_VALIDATE_FAILURE(level); + } + virHostMsgPass(); + return 1; } virHostMsgFail(level, diff --git a/tools/virt-host-validate-common.h b/tools/virt-host-validate-common.h index 9334fa8588..c64f5669dc 100644 --- a/tools/virt-host-validate-common.h +++ b/tools/virt-host-validate-common.h @@ -39,6 +39,7 @@ typedef enum { VIR_HOST_VALIDATE_CPU_FLAG_SIE, VIR_HOST_VALIDATE_CPU_FLAG_FACILITY_158, VIR_HOST_VALIDATE_CPU_FLAG_SEV, + VIR_HOST_VALIDATE_CPU_FLAG_TDX, VIR_HOST_VALIDATE_CPU_FLAG_LAST, } virHostValidateCPUFlag; -- 2.34.1

On Fri, May 24, 2024 at 02:21:16PM +0800, Zhenzhong Duan wrote:
Add check in virt-host-validate for secure guest support on x86 for Intel Trust Domain Extentions.
Suggested-by: Daniel P. Berrangé <berrange@redhat.com> Signed-off-by: Zhenzhong Duan <zhenzhong.duan@intel.com> --- tools/virt-host-validate-common.c | 22 +++++++++++++++++++++- tools/virt-host-validate-common.h | 1 + 2 files changed, 22 insertions(+), 1 deletion(-)
diff --git a/tools/virt-host-validate-common.c b/tools/virt-host-validate-common.c index c8a23e2e99..4f0698b8ce 100644 --- a/tools/virt-host-validate-common.c +++ b/tools/virt-host-validate-common.c @@ -43,7 +43,8 @@ VIR_ENUM_IMPL(virHostValidateCPUFlag, "svm", "sie", "158", - "sev"); + "sev", + "tdx_host_platform");
I don't think we need to be quiet so verbose here. I think it is sufficient to just call it 'tdx'.
static bool quiet;
@@ -471,6 +472,7 @@ int virHostValidateSecureGuests(const char *hvname, g_autoptr(virBitmap) flags = NULL; bool hasFac158 = false; bool hasAMDSev = false; + bool hasIntelTDX = false; virArch arch = virArchFromHost(); g_autofree char *cmdline = NULL; static const char *kIBMValues[] = {"y", "Y", "on", "ON", "oN", "On", "1"}; @@ -482,6 +484,8 @@ int virHostValidateSecureGuests(const char *hvname, hasFac158 = true; else if (flags && virBitmapIsBitSet(flags, VIR_HOST_VALIDATE_CPU_FLAG_SEV)) hasAMDSev = true; + else if (flags && virBitmapIsBitSet(flags, VIR_HOST_VALIDATE_CPU_FLAG_TDX)) + hasIntelTDX = true;
virHostMsgCheck(hvname, "%s", _("for secure guest support")); if (ARCH_IS_S390(arch)) { @@ -539,6 +543,22 @@ int virHostValidateSecureGuests(const char *hvname, "disabled in firmware."); return VIR_HOST_VALIDATE_FAILURE(level); } + } else if (hasIntelTDX) { + if (virFileReadValueString(&mod_value, "/sys/module/kvm_intel/parameters/tdx") < 0) { + virHostMsgFail(level, "Intel Trust Domain Extentions not " + "supported by the currently used kernel"); + return VIR_HOST_VALIDATE_FAILURE(level); + } + + if (mod_value[0] != 'Y') { + virHostMsgFail(level, + "Intel Trust Domain Extentions appears to be " + "disabled in kernel. Add kvm_intel.tdx=Y " + "to the kernel cmdline arguments"); + return VIR_HOST_VALIDATE_FAILURE(level); + } + virHostMsgPass(); + return 1; }
virHostMsgFail(level, diff --git a/tools/virt-host-validate-common.h b/tools/virt-host-validate-common.h index 9334fa8588..c64f5669dc 100644 --- a/tools/virt-host-validate-common.h +++ b/tools/virt-host-validate-common.h @@ -39,6 +39,7 @@ typedef enum { VIR_HOST_VALIDATE_CPU_FLAG_SIE, VIR_HOST_VALIDATE_CPU_FLAG_FACILITY_158, VIR_HOST_VALIDATE_CPU_FLAG_SEV, + VIR_HOST_VALIDATE_CPU_FLAG_TDX,
VIR_HOST_VALIDATE_CPU_FLAG_LAST, } virHostValidateCPUFlag; -- 2.34.1
With 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 :|

-----Original Message----- From: Daniel P. Berrangé <berrange@redhat.com> Subject: Re: [PATCH rfcv4 01/13] tools: Secure guest check for Intel in virt- host-validate
On Fri, May 24, 2024 at 02:21:16PM +0800, Zhenzhong Duan wrote:
Add check in virt-host-validate for secure guest support on x86 for Intel Trust Domain Extentions.
Suggested-by: Daniel P. Berrangé <berrange@redhat.com> Signed-off-by: Zhenzhong Duan <zhenzhong.duan@intel.com> --- tools/virt-host-validate-common.c | 22 +++++++++++++++++++++- tools/virt-host-validate-common.h | 1 + 2 files changed, 22 insertions(+), 1 deletion(-)
diff --git a/tools/virt-host-validate-common.c b/tools/virt-host-validate- common.c index c8a23e2e99..4f0698b8ce 100644 --- a/tools/virt-host-validate-common.c +++ b/tools/virt-host-validate-common.c @@ -43,7 +43,8 @@ VIR_ENUM_IMPL(virHostValidateCPUFlag, "svm", "sie", "158", - "sev"); + "sev", + "tdx_host_platform");
I don't think we need to be quiet so verbose here. I think it is sufficient to just call it 'tdx'.
This string is used to compare with output of /proc/cpuinfo. So we can't use 'tdx', or else string compare will fail. Thanks Zhenzhong

On Thu, Jun 06, 2024 at 10:27:39AM +0000, Duan, Zhenzhong wrote:
-----Original Message----- From: Daniel P. Berrangé <berrange@redhat.com> Subject: Re: [PATCH rfcv4 01/13] tools: Secure guest check for Intel in virt- host-validate
On Fri, May 24, 2024 at 02:21:16PM +0800, Zhenzhong Duan wrote:
Add check in virt-host-validate for secure guest support on x86 for Intel Trust Domain Extentions.
Suggested-by: Daniel P. Berrangé <berrange@redhat.com> Signed-off-by: Zhenzhong Duan <zhenzhong.duan@intel.com> --- tools/virt-host-validate-common.c | 22 +++++++++++++++++++++- tools/virt-host-validate-common.h | 1 + 2 files changed, 22 insertions(+), 1 deletion(-)
diff --git a/tools/virt-host-validate-common.c b/tools/virt-host-validate- common.c index c8a23e2e99..4f0698b8ce 100644 --- a/tools/virt-host-validate-common.c +++ b/tools/virt-host-validate-common.c @@ -43,7 +43,8 @@ VIR_ENUM_IMPL(virHostValidateCPUFlag, "svm", "sie", "158", - "sev"); + "sev", + "tdx_host_platform");
I don't think we need to be quiet so verbose here. I think it is sufficient to just call it 'tdx'.
This string is used to compare with output of /proc/cpuinfo. So we can't use 'tdx', or else string compare will fail.
Ah yes, nevermind then. Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> With 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 :|

Implement TDX check in order to generate domain feature capability correctly in case the availability of the feature changed. For INTEL TDX the verification is: - checking if "/sys/module/kvm_intel/parameters/tdx" contains the value 'Y': meaning TDX is enabled in the host kernel. Signed-off-by: Zhenzhong Duan <zhenzhong.duan@intel.com> Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> --- src/qemu/qemu_capabilities.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 21f93c6774..7cccc28e80 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -5112,6 +5112,24 @@ virQEMUCapsKVMSupportsSecureGuestAMD(void) } +/* + * Check whether INTEL Trust Domain Extention (x86) is enabled + */ +static bool +virQEMUCapsKVMSupportsSecureGuestINTEL(void) +{ + g_autofree char *modValue = NULL; + + if (virFileReadValueString(&modValue, "/sys/module/kvm_intel/parameters/tdx") < 0) + return false; + + if (modValue[0] != 'Y') + return false; + + return true; +} + + /* * Check whether the secure guest functionality is enabled. * See the specific architecture function for details on the verifications made. @@ -5125,7 +5143,8 @@ virQEMUCapsKVMSupportsSecureGuest(void) return virQEMUCapsKVMSupportsSecureGuestS390(); if (ARCH_IS_X86(arch)) - return virQEMUCapsKVMSupportsSecureGuestAMD(); + return virQEMUCapsKVMSupportsSecureGuestAMD() || + virQEMUCapsKVMSupportsSecureGuestINTEL(); return false; } -- 2.34.1

On Fri, May 24, 2024 at 02:21:17PM +0800, Zhenzhong Duan wrote:
Implement TDX check in order to generate domain feature capability correctly in case the availability of the feature changed.
For INTEL TDX the verification is: - checking if "/sys/module/kvm_intel/parameters/tdx" contains the value 'Y': meaning TDX is enabled in the host kernel.
Signed-off-by: Zhenzhong Duan <zhenzhong.duan@intel.com> Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> --- src/qemu/qemu_capabilities.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-)
diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 21f93c6774..7cccc28e80 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -5112,6 +5112,24 @@ virQEMUCapsKVMSupportsSecureGuestAMD(void) }
+/* + * Check whether INTEL Trust Domain Extention (x86) is enabled + */ +static bool +virQEMUCapsKVMSupportsSecureGuestINTEL(void) +{ + g_autofree char *modValue = NULL; + + if (virFileReadValueString(&modValue, "/sys/module/kvm_intel/parameters/tdx") < 0) + return false; + + if (modValue[0] != 'Y') + return false; + + return true; +} + + /* * Check whether the secure guest functionality is enabled. * See the specific architecture function for details on the verifications made. @@ -5125,7 +5143,8 @@ virQEMUCapsKVMSupportsSecureGuest(void) return virQEMUCapsKVMSupportsSecureGuestS390();
if (ARCH_IS_X86(arch)) - return virQEMUCapsKVMSupportsSecureGuestAMD(); + return virQEMUCapsKVMSupportsSecureGuestAMD() || + virQEMUCapsKVMSupportsSecureGuestINTEL();
You were just copying our existing pattern here which is good practice, but I think our existing pattern was wrong. We should have named it after the technology, not the vendor. IOW, lets call your new function virQEMUCapsKVMSupportsSecureGuestTDX() With 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 :|

-----Original Message----- From: Daniel P. Berrangé <berrange@redhat.com> Subject: Re: [PATCH rfcv4 02/13] qemu: Check if INTEL Trust Domain Extention support is enabled
On Fri, May 24, 2024 at 02:21:17PM +0800, Zhenzhong Duan wrote:
Implement TDX check in order to generate domain feature capability correctly in case the availability of the feature changed.
For INTEL TDX the verification is: - checking if "/sys/module/kvm_intel/parameters/tdx" contains the value 'Y': meaning TDX is enabled in the host kernel.
Signed-off-by: Zhenzhong Duan <zhenzhong.duan@intel.com> Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> --- src/qemu/qemu_capabilities.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-)
diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 21f93c6774..7cccc28e80 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -5112,6 +5112,24 @@ virQEMUCapsKVMSupportsSecureGuestAMD(void) }
+/* + * Check whether INTEL Trust Domain Extention (x86) is enabled + */ +static bool +virQEMUCapsKVMSupportsSecureGuestINTEL(void) +{ + g_autofree char *modValue = NULL; + + if (virFileReadValueString(&modValue, "/sys/module/kvm_intel/parameters/tdx") < 0) + return false; + + if (modValue[0] != 'Y') + return false; + + return true; +} + + /* * Check whether the secure guest functionality is enabled. * See the specific architecture function for details on the verifications made. @@ -5125,7 +5143,8 @@ virQEMUCapsKVMSupportsSecureGuest(void) return virQEMUCapsKVMSupportsSecureGuestS390();
if (ARCH_IS_X86(arch)) - return virQEMUCapsKVMSupportsSecureGuestAMD(); + return virQEMUCapsKVMSupportsSecureGuestAMD() || + virQEMUCapsKVMSupportsSecureGuestINTEL();
You were just copying our existing pattern here which is good practice, but I think our existing pattern was wrong. We should have named it after the technology, not the vendor. IOW, lets call your new function
virQEMUCapsKVMSupportsSecureGuestTDX()
Go it. Thanks Zhenzhong

QEMU_CAPS_TDX_GUEST set means TDX supported with this QEMU. Signed-off-by: Chenyi Qiang <chenyi.qiang@intel.com> Signed-off-by: Zhenzhong Duan <zhenzhong.duan@intel.com> Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> --- src/qemu/qemu_capabilities.c | 2 ++ src/qemu/qemu_capabilities.h | 1 + 2 files changed, 3 insertions(+) diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 7cccc28e80..33d2b5f392 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -706,6 +706,7 @@ VIR_ENUM_IMPL(virQEMUCaps, "blockjob.backing-mask-protocol", /* QEMU_CAPS_BLOCKJOB_BACKING_MASK_PROTOCOL */ "display-reload", /* QEMU_CAPS_DISPLAY_RELOAD */ "usb-mtp", /* QEMU_CAPS_DEVICE_USB_MTP */ + "tdx-guest", /* QEMU_CAPS_TDX_GUEST */ ); @@ -1395,6 +1396,7 @@ struct virQEMUCapsStringFlags virQEMUCapsObjectTypes[] = { { "cryptodev-backend-lkcf", QEMU_CAPS_OBJECT_CRYPTO_LKCF }, { "pvpanic-pci", QEMU_CAPS_DEVICE_PANIC_PCI }, { "usb-mtp", QEMU_CAPS_DEVICE_USB_MTP }, + { "tdx-guest", QEMU_CAPS_TDX_GUEST}, }; diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h index 5082967cba..354e8d7958 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -685,6 +685,7 @@ typedef enum { /* virQEMUCapsFlags grouping marker for syntax-check */ QEMU_CAPS_BLOCKJOB_BACKING_MASK_PROTOCOL, /* backing-mask-protocol of block-commit/block-stream */ QEMU_CAPS_DISPLAY_RELOAD, /* 'display-reload' qmp command is supported */ QEMU_CAPS_DEVICE_USB_MTP, /* -device usb-mtp */ + QEMU_CAPS_TDX_GUEST, /* -object tdx-guest,... */ QEMU_CAPS_LAST /* this must always be the last item */ } virQEMUCapsFlags; -- 2.34.1

Extend qemu TDX capability to domain capabilities. Signed-off-by: Chenyi Qiang <chenyi.qiang@intel.com> Signed-off-by: Zhenzhong Duan <zhenzhong.duan@intel.com> --- docs/formatdomaincaps.rst | 1 + src/conf/domain_capabilities.c | 1 + src/conf/domain_capabilities.h | 1 + src/conf/schemas/domaincaps.rng | 9 +++++++++ src/qemu/qemu_capabilities.c | 13 +++++++++++++ 5 files changed, 25 insertions(+) diff --git a/docs/formatdomaincaps.rst b/docs/formatdomaincaps.rst index 609a767189..36d56a433c 100644 --- a/docs/formatdomaincaps.rst +++ b/docs/formatdomaincaps.rst @@ -651,6 +651,7 @@ capabilities. All features occur as children of the main ``features`` element. <backingStoreInput supported='yes'/> <backup supported='yes'/> <async-teardown supported='yes'/> + <tdx supported='yes'/> <sev> <cbitpos>47</cbitpos> <reduced-phys-bits>1</reduced-phys-bits> diff --git a/src/conf/domain_capabilities.c b/src/conf/domain_capabilities.c index 68eb3c9797..8bfe19d774 100644 --- a/src/conf/domain_capabilities.c +++ b/src/conf/domain_capabilities.c @@ -42,6 +42,7 @@ VIR_ENUM_IMPL(virDomainCapsFeature, "backup", "async-teardown", "s390-pv", + "tdx", ); static virClass *virDomainCapsClass; diff --git a/src/conf/domain_capabilities.h b/src/conf/domain_capabilities.h index fadc30cdd7..690e2a1f03 100644 --- a/src/conf/domain_capabilities.h +++ b/src/conf/domain_capabilities.h @@ -250,6 +250,7 @@ typedef enum { VIR_DOMAIN_CAPS_FEATURE_BACKUP, VIR_DOMAIN_CAPS_FEATURE_ASYNC_TEARDOWN, VIR_DOMAIN_CAPS_FEATURE_S390_PV, + VIR_DOMAIN_CAPS_FEATURE_TDX, VIR_DOMAIN_CAPS_FEATURE_LAST } virDomainCapsFeature; diff --git a/src/conf/schemas/domaincaps.rng b/src/conf/schemas/domaincaps.rng index e7aa4a1066..a5522b1e67 100644 --- a/src/conf/schemas/domaincaps.rng +++ b/src/conf/schemas/domaincaps.rng @@ -308,6 +308,9 @@ <optional> <ref name="s390-pv"/> </optional> + <optional> + <ref name="tdx"/> + </optional> <optional> <ref name="sev"/> </optional> @@ -363,6 +366,12 @@ </element> </define> + <define name="tdx"> + <element name="tdx"> + <ref name="supported"/> + </element> + </define> + <define name="sev"> <element name="sev"> <ref name="supported"/> diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 33d2b5f392..53a773b853 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -6675,6 +6675,18 @@ virQEMUCapsFillDomainFeatureHypervCaps(virQEMUCaps *qemuCaps, } +static void +virQEMUCapsFillDomainFeatureTDXCaps(virQEMUCaps *qemuCaps, + virDomainCaps *domCaps) +{ + if (domCaps->arch == VIR_ARCH_X86_64 && + domCaps->virttype == VIR_DOMAIN_VIRT_KVM && + virQEMUCapsGet(qemuCaps, QEMU_CAPS_TDX_GUEST) && + virQEMUCapsGetKVMSupportsSecureGuest(qemuCaps)) + domCaps->features[VIR_DOMAIN_CAPS_FEATURE_TDX] = VIR_TRISTATE_BOOL_YES; +} + + int virQEMUCapsFillDomainCaps(virQEMUCaps *qemuCaps, virArch hostarch, @@ -6734,6 +6746,7 @@ virQEMUCapsFillDomainCaps(virQEMUCaps *qemuCaps, virQEMUCapsFillDomainFeatureSGXCaps(qemuCaps, domCaps); virQEMUCapsFillDomainFeatureHypervCaps(qemuCaps, domCaps); virQEMUCapsFillDomainDeviceCryptoCaps(qemuCaps, crypto); + virQEMUCapsFillDomainFeatureTDXCaps(qemuCaps, domCaps); return 0; } -- 2.34.1

On Fri, May 24, 2024 at 02:21:19PM +0800, Zhenzhong Duan wrote:
Extend qemu TDX capability to domain capabilities.
Signed-off-by: Chenyi Qiang <chenyi.qiang@intel.com> Signed-off-by: Zhenzhong Duan <zhenzhong.duan@intel.com> --- docs/formatdomaincaps.rst | 1 + src/conf/domain_capabilities.c | 1 + src/conf/domain_capabilities.h | 1 + src/conf/schemas/domaincaps.rng | 9 +++++++++ src/qemu/qemu_capabilities.c | 13 +++++++++++++ 5 files changed, 25 insertions(+)
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> With 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 :|

On 5/24/24 00:21, Zhenzhong Duan wrote:
Extend qemu TDX capability to domain capabilities.
Signed-off-by: Chenyi Qiang <chenyi.qiang@intel.com> Signed-off-by: Zhenzhong Duan <zhenzhong.duan@intel.com> --- docs/formatdomaincaps.rst | 1 + src/conf/domain_capabilities.c | 1 + src/conf/domain_capabilities.h | 1 + src/conf/schemas/domaincaps.rng | 9 +++++++++ src/qemu/qemu_capabilities.c | 13 +++++++++++++ 5 files changed, 25 insertions(+)
diff --git a/docs/formatdomaincaps.rst b/docs/formatdomaincaps.rst index 609a767189..36d56a433c 100644 --- a/docs/formatdomaincaps.rst +++ b/docs/formatdomaincaps.rst @@ -651,6 +651,7 @@ capabilities. All features occur as children of the main ``features`` element. <backingStoreInput supported='yes'/> <backup supported='yes'/> <async-teardown supported='yes'/> + <tdx supported='yes'/> <sev> <cbitpos>47</cbitpos> <reduced-phys-bits>1</reduced-phys-bits> diff --git a/src/conf/domain_capabilities.c b/src/conf/domain_capabilities.c index 68eb3c9797..8bfe19d774 100644 --- a/src/conf/domain_capabilities.c +++ b/src/conf/domain_capabilities.c @@ -42,6 +42,7 @@ VIR_ENUM_IMPL(virDomainCapsFeature, "backup", "async-teardown", "s390-pv", + "tdx", );
static virClass *virDomainCapsClass; diff --git a/src/conf/domain_capabilities.h b/src/conf/domain_capabilities.h index fadc30cdd7..690e2a1f03 100644 --- a/src/conf/domain_capabilities.h +++ b/src/conf/domain_capabilities.h @@ -250,6 +250,7 @@ typedef enum { VIR_DOMAIN_CAPS_FEATURE_BACKUP, VIR_DOMAIN_CAPS_FEATURE_ASYNC_TEARDOWN, VIR_DOMAIN_CAPS_FEATURE_S390_PV, + VIR_DOMAIN_CAPS_FEATURE_TDX,
VIR_DOMAIN_CAPS_FEATURE_LAST } virDomainCapsFeature; diff --git a/src/conf/schemas/domaincaps.rng b/src/conf/schemas/domaincaps.rng index e7aa4a1066..a5522b1e67 100644 --- a/src/conf/schemas/domaincaps.rng +++ b/src/conf/schemas/domaincaps.rng @@ -308,6 +308,9 @@ <optional> <ref name="s390-pv"/> </optional> + <optional> + <ref name="tdx"/> + </optional> <optional> <ref name="sev"/> </optional> @@ -363,6 +366,12 @@ </element> </define>
+ <define name="tdx"> + <element name="tdx"> + <ref name="supported"/> + </element> + </define> + <define name="sev"> <element name="sev"> <ref name="supported"/> diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 33d2b5f392..53a773b853 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -6675,6 +6675,18 @@ virQEMUCapsFillDomainFeatureHypervCaps(virQEMUCaps *qemuCaps, }
+static void +virQEMUCapsFillDomainFeatureTDXCaps(virQEMUCaps *qemuCaps, + virDomainCaps *domCaps) +{ + if (domCaps->arch == VIR_ARCH_X86_64 && + domCaps->virttype == VIR_DOMAIN_VIRT_KVM && + virQEMUCapsGet(qemuCaps, QEMU_CAPS_TDX_GUEST) && + virQEMUCapsGetKVMSupportsSecureGuest(qemuCaps)) + domCaps->features[VIR_DOMAIN_CAPS_FEATURE_TDX] = VIR_TRISTATE_BOOL_YES; +} + + int virQEMUCapsFillDomainCaps(virQEMUCaps *qemuCaps, virArch hostarch, @@ -6734,6 +6746,7 @@ virQEMUCapsFillDomainCaps(virQEMUCaps *qemuCaps, virQEMUCapsFillDomainFeatureSGXCaps(qemuCaps, domCaps); virQEMUCapsFillDomainFeatureHypervCaps(qemuCaps, domCaps); virQEMUCapsFillDomainDeviceCryptoCaps(qemuCaps, crypto); + virQEMUCapsFillDomainFeatureTDXCaps(qemuCaps, domCaps);
I'm not sure how you'll want to handle this, but virQEMUCapsFillDomainLaunchSecurity (introduced by commit 66df7992d8e) must also account for TDX. E.g. diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index aeccf877ea..37011d122b 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -6752,6 +6752,8 @@ virQEMUCapsFillDomainLaunchSecurity(virQEMUCaps *qemuCaps, if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_S390_PV_GUEST) && virQEMUCapsGet(qemuCaps, QEMU_CAPS_MACHINE_CONFIDENTAL_GUEST_SUPPORT)) VIR_DOMAIN_CAPS_ENUM_SET(launchSecurity->sectype, VIR_DOMAIN_LAUNCH_SECURITY_PV); + if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_TDX_GUEST)) + VIR_DOMAIN_CAPS_ENUM_SET(launchSecurity->sectype, VIR_DOMAIN_LAUNCH_SECURITY_TDX); if (launchSecurity->sectype.values == 0) { launchSecurity->supported = VIR_TRISTATE_BOOL_NO; But VIR_DOMAIN_LAUNCH_SECURITY_TDX is introduced by the next patch. Maybe swap the order of the patches? Regards, Jim

-----Original Message----- From: Jim Fehlig <jfehlig@suse.com> Subject: Re: [PATCH rfcv4 04/13] conf: expose TDX feature in domain capabilities
On 5/24/24 00:21, Zhenzhong Duan wrote:
Extend qemu TDX capability to domain capabilities.
Signed-off-by: Chenyi Qiang <chenyi.qiang@intel.com> Signed-off-by: Zhenzhong Duan <zhenzhong.duan@intel.com> --- docs/formatdomaincaps.rst | 1 + src/conf/domain_capabilities.c | 1 + src/conf/domain_capabilities.h | 1 + src/conf/schemas/domaincaps.rng | 9 +++++++++ src/qemu/qemu_capabilities.c | 13 +++++++++++++ 5 files changed, 25 insertions(+)
diff --git a/docs/formatdomaincaps.rst b/docs/formatdomaincaps.rst index 609a767189..36d56a433c 100644 --- a/docs/formatdomaincaps.rst +++ b/docs/formatdomaincaps.rst @@ -651,6 +651,7 @@ capabilities. All features occur as children of the main ``features`` element. <backingStoreInput supported='yes'/> <backup supported='yes'/> <async-teardown supported='yes'/> + <tdx supported='yes'/> <sev> <cbitpos>47</cbitpos> <reduced-phys-bits>1</reduced-phys-bits> diff --git a/src/conf/domain_capabilities.c b/src/conf/domain_capabilities.c index 68eb3c9797..8bfe19d774 100644 --- a/src/conf/domain_capabilities.c +++ b/src/conf/domain_capabilities.c @@ -42,6 +42,7 @@ VIR_ENUM_IMPL(virDomainCapsFeature, "backup", "async-teardown", "s390-pv", + "tdx", );
static virClass *virDomainCapsClass; diff --git a/src/conf/domain_capabilities.h b/src/conf/domain_capabilities.h index fadc30cdd7..690e2a1f03 100644 --- a/src/conf/domain_capabilities.h +++ b/src/conf/domain_capabilities.h @@ -250,6 +250,7 @@ typedef enum { VIR_DOMAIN_CAPS_FEATURE_BACKUP, VIR_DOMAIN_CAPS_FEATURE_ASYNC_TEARDOWN, VIR_DOMAIN_CAPS_FEATURE_S390_PV, + VIR_DOMAIN_CAPS_FEATURE_TDX,
VIR_DOMAIN_CAPS_FEATURE_LAST } virDomainCapsFeature; diff --git a/src/conf/schemas/domaincaps.rng b/src/conf/schemas/domaincaps.rng index e7aa4a1066..a5522b1e67 100644 --- a/src/conf/schemas/domaincaps.rng +++ b/src/conf/schemas/domaincaps.rng @@ -308,6 +308,9 @@ <optional> <ref name="s390-pv"/> </optional> + <optional> + <ref name="tdx"/> + </optional> <optional> <ref name="sev"/> </optional> @@ -363,6 +366,12 @@ </element> </define>
+ <define name="tdx"> + <element name="tdx"> + <ref name="supported"/> + </element> + </define> + <define name="sev"> <element name="sev"> <ref name="supported"/> diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 33d2b5f392..53a773b853 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -6675,6 +6675,18 @@ virQEMUCapsFillDomainFeatureHypervCaps(virQEMUCaps *qemuCaps, }
+static void +virQEMUCapsFillDomainFeatureTDXCaps(virQEMUCaps *qemuCaps, + virDomainCaps *domCaps) +{ + if (domCaps->arch == VIR_ARCH_X86_64 && + domCaps->virttype == VIR_DOMAIN_VIRT_KVM && + virQEMUCapsGet(qemuCaps, QEMU_CAPS_TDX_GUEST) && + virQEMUCapsGetKVMSupportsSecureGuest(qemuCaps)) + domCaps->features[VIR_DOMAIN_CAPS_FEATURE_TDX] = VIR_TRISTATE_BOOL_YES; +} + + int virQEMUCapsFillDomainCaps(virQEMUCaps *qemuCaps, virArch hostarch, @@ -6734,6 +6746,7 @@ virQEMUCapsFillDomainCaps(virQEMUCaps *qemuCaps, virQEMUCapsFillDomainFeatureSGXCaps(qemuCaps, domCaps); virQEMUCapsFillDomainFeatureHypervCaps(qemuCaps, domCaps); virQEMUCapsFillDomainDeviceCryptoCaps(qemuCaps, crypto); + virQEMUCapsFillDomainFeatureTDXCaps(qemuCaps, domCaps);
I'm not sure how you'll want to handle this, but virQEMUCapsFillDomainLaunchSecurity (introduced by commit 66df7992d8e) must also account for TDX. E.g.
Yes, it will be in next version, see https://github.com/intel/libvirt-tdx/commit/14ec3e14e07f5cee6f86e9086f0bdee2...
diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index aeccf877ea..37011d122b 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -6752,6 +6752,8 @@ virQEMUCapsFillDomainLaunchSecurity(virQEMUCaps *qemuCaps, if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_S390_PV_GUEST) && virQEMUCapsGet(qemuCaps, QEMU_CAPS_MACHINE_CONFIDENTAL_GUEST_SUPPORT)) VIR_DOMAIN_CAPS_ENUM_SET(launchSecurity->sectype, VIR_DOMAIN_LAUNCH_SECURITY_PV); + if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_TDX_GUEST)) + VIR_DOMAIN_CAPS_ENUM_SET(launchSecurity->sectype, VIR_DOMAIN_LAUNCH_SECURITY_TDX);
if (launchSecurity->sectype.values == 0) { launchSecurity->supported = VIR_TRISTATE_BOOL_NO;
But VIR_DOMAIN_LAUNCH_SECURITY_TDX is introduced by the next patch. Maybe swap the order of the patches?
I put it after patch 'qemu: Add command line and validation for TDX type' as validation check take effect after it and it acts as start point supporting tdx. See https://github.com/intel/libvirt-tdx/commits/tdx_for_upstream_v1.wip/ Thanks Zhenzhong

When 'tdx' is used, the VM will 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 is a child element 'policy' and three optional element for tdx type. In 'policy', bit 0 is set to enable TDX debug, bit 28 set to enable sept-ve-disable, other bits are reserved currently. mrConfigId, mrOwner and mrOwnerConfig are base64 encoded SHA384 digest. 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> --- src/conf/domain_conf.c | 42 +++++++++++++++++++++++++++++++ src/conf/domain_conf.h | 9 +++++++ src/conf/schemas/domaincommon.rng | 29 +++++++++++++++++++++ src/conf/virconftypes.h | 2 ++ src/qemu/qemu_command.c | 2 ++ src/qemu/qemu_firmware.c | 1 + src/qemu/qemu_namespace.c | 1 + src/qemu/qemu_process.c | 1 + src/qemu/qemu_validate.c | 1 + 9 files changed, 88 insertions(+) diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index a0912062ff..c557da0c65 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -1508,6 +1508,7 @@ VIR_ENUM_IMPL(virDomainLaunchSecurity, "", "sev", "s390-pv", + "tdx", ); typedef enum { @@ -3832,6 +3833,10 @@ virDomainSecDefFree(virDomainSecDef *def) g_free(def->data.sev.dh_cert); g_free(def->data.sev.session); 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); case VIR_DOMAIN_LAUNCH_SECURITY_PV: case VIR_DOMAIN_LAUNCH_SECURITY_NONE: case VIR_DOMAIN_LAUNCH_SECURITY_LAST: @@ -13649,6 +13654,24 @@ virDomainSEVDefParseXML(virDomainSEVDef *def, } +static int +virDomainTDXDefParseXML(virDomainTDXDef *def, + xmlXPathContextPtr ctxt) +{ + if (virXPathULongLongBase("string(./policy)", ctxt, 16, &def->policy) < 0) { + 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) @@ -13668,6 +13691,10 @@ virDomainSecDefParseXML(xmlNodePtr lsecNode, if (virDomainSEVDefParseXML(&sec->data.sev, 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: @@ -26661,6 +26688,21 @@ virDomainSecDefFormat(virBuffer *buf, virDomainSecDef *sec) break; } + case VIR_DOMAIN_LAUNCH_SECURITY_TDX: { + virDomainTDXDef *tdx = &sec->data.tdx; + + virBufferAsprintf(&childBuf, "<policy>0x%llx</policy>\n", tdx->policy); + + if (tdx->mrconfigid) + virBufferEscapeString(&childBuf, "<mrConfigId>%s</mrConfigId>\n", tdx->mrconfigid); + if (tdx->mrowner) + virBufferEscapeString(&childBuf, "<mrOwner>%s</mrOwner>\n", tdx->mrowner); + if (tdx->mrownerconfig) + virBufferEscapeString(&childBuf, "<mrOwnerConfig>%s</mrOwnerConfig>\n", tdx->mrownerconfig); + + break; + } + case VIR_DOMAIN_LAUNCH_SECURITY_PV: break; diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 356c25405b..7882b7a75d 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -2856,6 +2856,7 @@ typedef enum { VIR_DOMAIN_LAUNCH_SECURITY_NONE, VIR_DOMAIN_LAUNCH_SECURITY_SEV, VIR_DOMAIN_LAUNCH_SECURITY_PV, + VIR_DOMAIN_LAUNCH_SECURITY_TDX, VIR_DOMAIN_LAUNCH_SECURITY_LAST, } virDomainLaunchSecurity; @@ -2872,10 +2873,18 @@ struct _virDomainSEVDef { virTristateBool kernel_hashes; }; +struct _virDomainTDXDef { + unsigned long long policy; + char *mrconfigid; + char *mrowner; + char *mrownerconfig; +}; + struct _virDomainSecDef { virDomainLaunchSecurity sectype; union { virDomainSEVDef sev; + virDomainTDXDef tdx; } data; }; diff --git a/src/conf/schemas/domaincommon.rng b/src/conf/schemas/domaincommon.rng index d84e030255..f6e1782b33 100644 --- a/src/conf/schemas/domaincommon.rng +++ b/src/conf/schemas/domaincommon.rng @@ -520,6 +520,9 @@ <value>s390-pv</value> </attribute> </group> + <group> + <ref name="launchSecurityTDX"/> + </group> </choice> </element> </define> @@ -565,6 +568,32 @@ </interleave> </define> + <define name="launchSecurityTDX"> + <attribute name="type"> + <value>tdx</value> + </attribute> + <interleave> + <element name="policy"> + <ref name="hexuint"/> + </element> + <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: diff --git a/src/conf/virconftypes.h b/src/conf/virconftypes.h index 0779bc224b..e2e0bba012 100644 --- a/src/conf/virconftypes.h +++ b/src/conf/virconftypes.h @@ -212,6 +212,8 @@ typedef struct _virDomainResourceDef virDomainResourceDef; typedef struct _virDomainSEVDef virDomainSEVDef; +typedef struct _virDomainTDXDef virDomainTDXDef; + typedef struct _virDomainSecDef virDomainSecDef; typedef struct _virDomainShmemDef virDomainShmemDef; diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 8d4442c360..dde2d5fa01 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -7037,6 +7037,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: @@ -9758,6 +9759,7 @@ qemuBuildSecCommandLine(virDomainObj *vm, virCommand *cmd, case VIR_DOMAIN_LAUNCH_SECURITY_PV: return qemuBuildPVCommandLine(vm, cmd); break; + case VIR_DOMAIN_LAUNCH_SECURITY_TDX: case VIR_DOMAIN_LAUNCH_SECURITY_NONE: case VIR_DOMAIN_LAUNCH_SECURITY_LAST: virReportEnumRangeError(virDomainLaunchSecurity, sec->sectype); diff --git a/src/qemu/qemu_firmware.c b/src/qemu/qemu_firmware.c index 78844e3066..7ab10a9286 100644 --- a/src/qemu/qemu_firmware.c +++ b/src/qemu/qemu_firmware.c @@ -1339,6 +1339,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: diff --git a/src/qemu/qemu_namespace.c b/src/qemu/qemu_namespace.c index 915d44310f..ac8a4b5c07 100644 --- a/src/qemu/qemu_namespace.c +++ b/src/qemu/qemu_namespace.c @@ -660,6 +660,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: diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index da2b024f92..bd8624e3f6 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -6781,6 +6781,7 @@ qemuProcessPrepareLaunchSecurityGuestInput(virDomainObj *vm) case VIR_DOMAIN_LAUNCH_SECURITY_SEV: return qemuProcessPrepareSEVGuestInput(vm); 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: diff --git a/src/qemu/qemu_validate.c b/src/qemu/qemu_validate.c index fd7b90e47d..ee25fd70d9 100644 --- a/src/qemu/qemu_validate.c +++ b/src/qemu/qemu_validate.c @@ -1322,6 +1322,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); -- 2.34.1

On Fri, May 24, 2024 at 02:21:20PM +0800, Zhenzhong Duan wrote:
When 'tdx' is used, the VM will 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 is a child element 'policy' and three optional element for tdx type. In 'policy', bit 0 is set to enable TDX debug, bit 28 set to enable sept-ve-disable, other bits are reserved currently. mrConfigId, mrOwner and mrOwnerConfig are base64 encoded SHA384 digest.
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> --- src/conf/domain_conf.c | 42 +++++++++++++++++++++++++++++++ src/conf/domain_conf.h | 9 +++++++ src/conf/schemas/domaincommon.rng | 29 +++++++++++++++++++++ src/conf/virconftypes.h | 2 ++ src/qemu/qemu_command.c | 2 ++ src/qemu/qemu_firmware.c | 1 + src/qemu/qemu_namespace.c | 1 + src/qemu/qemu_process.c | 1 + src/qemu/qemu_validate.c | 1 + 9 files changed, 88 insertions(+)
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index a0912062ff..c557da0c65 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -1508,6 +1508,7 @@ VIR_ENUM_IMPL(virDomainLaunchSecurity, "", "sev", "s390-pv", + "tdx", );
typedef enum { @@ -3832,6 +3833,10 @@ virDomainSecDefFree(virDomainSecDef *def) g_free(def->data.sev.dh_cert); g_free(def->data.sev.session); 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);
Missing 'break' here. I'm surprised the compiler didn't complain, as we have warning flags set to require explicit marking of case fallthroughs.
case VIR_DOMAIN_LAUNCH_SECURITY_PV: case VIR_DOMAIN_LAUNCH_SECURITY_NONE: case VIR_DOMAIN_LAUNCH_SECURITY_LAST:
With 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 :|

-----Original Message----- From: Daniel P. Berrangé <berrange@redhat.com> Subject: Re: [PATCH rfcv4 05/13] conf: add tdx as launch security type
On Fri, May 24, 2024 at 02:21:20PM +0800, Zhenzhong Duan wrote:
When 'tdx' is used, the VM will 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 is a child element 'policy' and three optional element for tdx type. In 'policy', bit 0 is set to enable TDX debug, bit 28 set to enable sept-ve-disable, other bits are reserved currently. mrConfigId, mrOwner and mrOwnerConfig are base64 encoded SHA384 digest.
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> --- src/conf/domain_conf.c | 42 +++++++++++++++++++++++++++++++ src/conf/domain_conf.h | 9 +++++++ src/conf/schemas/domaincommon.rng | 29 +++++++++++++++++++++ src/conf/virconftypes.h | 2 ++ src/qemu/qemu_command.c | 2 ++ src/qemu/qemu_firmware.c | 1 + src/qemu/qemu_namespace.c | 1 + src/qemu/qemu_process.c | 1 + src/qemu/qemu_validate.c | 1 + 9 files changed, 88 insertions(+)
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index a0912062ff..c557da0c65 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -1508,6 +1508,7 @@ VIR_ENUM_IMPL(virDomainLaunchSecurity, "", "sev", "s390-pv", + "tdx", );
typedef enum { @@ -3832,6 +3833,10 @@ virDomainSecDefFree(virDomainSecDef *def) g_free(def->data.sev.dh_cert); g_free(def->data.sev.session); 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);
Missing 'break' here. I'm surprised the compiler didn't complain, as we have warning flags set to require explicit marking of case fallthroughs.
Will do. Thanks Zhenzhong
case VIR_DOMAIN_LAUNCH_SECURITY_PV: case VIR_DOMAIN_LAUNCH_SECURITY_NONE: case VIR_DOMAIN_LAUNCH_SECURITY_LAST:
With 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 :|

On Fri, May 24, 2024 at 02:21:20PM +0800, Zhenzhong Duan wrote:
When 'tdx' is used, the VM will 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 is a child element 'policy' and three optional element for tdx type. In 'policy', bit 0 is set to enable TDX debug, bit 28 set to enable sept-ve-disable, other bits are reserved currently. mrConfigId, mrOwner and mrOwnerConfig are base64 encoded SHA384 digest.
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> --- src/conf/domain_conf.c | 42 +++++++++++++++++++++++++++++++ src/conf/domain_conf.h | 9 +++++++ src/conf/schemas/domaincommon.rng | 29 +++++++++++++++++++++ src/conf/virconftypes.h | 2 ++ src/qemu/qemu_command.c | 2 ++ src/qemu/qemu_firmware.c | 1 + src/qemu/qemu_namespace.c | 1 + src/qemu/qemu_process.c | 1 + src/qemu/qemu_validate.c | 1 + 9 files changed, 88 insertions(+)
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index a0912062ff..c557da0c65 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c
@@ -13649,6 +13654,24 @@ virDomainSEVDefParseXML(virDomainSEVDef *def, }
+static int +virDomainTDXDefParseXML(virDomainTDXDef *def, + xmlXPathContextPtr ctxt) +{ + if (virXPathULongLongBase("string(./policy)", ctxt, 16, &def->policy) < 0) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("failed to get launch security policy for launch security type TDX")); + return -1; + }
This makes the 'policy' attribute mandatory, but QEMU is quite happy with it being unset, so we should not require this in libvirt either.
+ + def->mrconfigid = virXPathString("string(./mrConfigId)", ctxt); + def->mrowner = virXPathString("string(./mrOwner)", ctxt); + def->mrownerconfig = virXPathString("string(./mrOwnerConfig)", ctxt); + + return 0; +}
diff --git a/src/conf/schemas/domaincommon.rng b/src/conf/schemas/domaincommon.rng index d84e030255..f6e1782b33 100644 --- a/src/conf/schemas/domaincommon.rng +++ b/src/conf/schemas/domaincommon.rng @@ -520,6 +520,9 @@ <value>s390-pv</value> </attribute> </group> + <group> + <ref name="launchSecurityTDX"/> + </group> </choice> </element> </define> @@ -565,6 +568,32 @@ </interleave> </define>
+ <define name="launchSecurityTDX"> + <attribute name="type"> + <value>tdx</value> + </attribute> + <interleave> + <element name="policy"> + <ref name="hexuint"/> + </element>
This should be marked <optional> too.
+ <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:
With 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 :|

-----Original Message----- From: Daniel P. Berrangé <berrange@redhat.com> Subject: Re: [PATCH rfcv4 05/13] conf: add tdx as launch security type
On Fri, May 24, 2024 at 02:21:20PM +0800, Zhenzhong Duan wrote:
When 'tdx' is used, the VM will 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 is a child element 'policy' and three optional element for tdx type. In 'policy', bit 0 is set to enable TDX debug, bit 28 set to enable sept-ve-disable, other bits are reserved currently. mrConfigId, mrOwner and mrOwnerConfig are base64 encoded SHA384 digest.
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> --- src/conf/domain_conf.c | 42 +++++++++++++++++++++++++++++++ src/conf/domain_conf.h | 9 +++++++ src/conf/schemas/domaincommon.rng | 29 +++++++++++++++++++++ src/conf/virconftypes.h | 2 ++ src/qemu/qemu_command.c | 2 ++ src/qemu/qemu_firmware.c | 1 + src/qemu/qemu_namespace.c | 1 + src/qemu/qemu_process.c | 1 + src/qemu/qemu_validate.c | 1 + 9 files changed, 88 insertions(+)
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index a0912062ff..c557da0c65 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c
@@ -13649,6 +13654,24 @@ virDomainSEVDefParseXML(virDomainSEVDef *def, }
+static int +virDomainTDXDefParseXML(virDomainTDXDef *def, + xmlXPathContextPtr ctxt) +{ + if (virXPathULongLongBase("string(./policy)", ctxt, 16, &def->policy) < 0) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("failed to get launch security policy for launch security type TDX")); + return -1; + }
This makes the 'policy' attribute mandatory, but QEMU is quite happy with it being unset, so we should not require this in libvirt either.
Yes, but I am trying to align with SEV which has same issue. So aligning with SEV vs. making TDX's 'policy' optional, you prefer the 2nd? Pls confirm. Thanks Zhenzhong
+ + def->mrconfigid = virXPathString("string(./mrConfigId)", ctxt); + def->mrowner = virXPathString("string(./mrOwner)", ctxt); + def->mrownerconfig = virXPathString("string(./mrOwnerConfig)", ctxt); + + return 0; +}
diff --git a/src/conf/schemas/domaincommon.rng b/src/conf/schemas/domaincommon.rng index d84e030255..f6e1782b33 100644 --- a/src/conf/schemas/domaincommon.rng +++ b/src/conf/schemas/domaincommon.rng @@ -520,6 +520,9 @@ <value>s390-pv</value> </attribute> </group> + <group> + <ref name="launchSecurityTDX"/> + </group> </choice> </element> </define> @@ -565,6 +568,32 @@ </interleave> </define>
+ <define name="launchSecurityTDX"> + <attribute name="type"> + <value>tdx</value> + </attribute> + <interleave> + <element name="policy"> + <ref name="hexuint"/> + </element>
This should be marked <optional> too.
+ <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:
With 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 :|

On Wed, Mar 26, 2025 at 02:45:55AM +0000, Duan, Zhenzhong wrote:
-----Original Message----- From: Daniel P. Berrangé <berrange@redhat.com> Subject: Re: [PATCH rfcv4 05/13] conf: add tdx as launch security type
On Fri, May 24, 2024 at 02:21:20PM +0800, Zhenzhong Duan wrote:
When 'tdx' is used, the VM will 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 is a child element 'policy' and three optional element for tdx type. In 'policy', bit 0 is set to enable TDX debug, bit 28 set to enable sept-ve-disable, other bits are reserved currently. mrConfigId, mrOwner and mrOwnerConfig are base64 encoded SHA384 digest.
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> --- src/conf/domain_conf.c | 42 +++++++++++++++++++++++++++++++ src/conf/domain_conf.h | 9 +++++++ src/conf/schemas/domaincommon.rng | 29 +++++++++++++++++++++ src/conf/virconftypes.h | 2 ++ src/qemu/qemu_command.c | 2 ++ src/qemu/qemu_firmware.c | 1 + src/qemu/qemu_namespace.c | 1 + src/qemu/qemu_process.c | 1 + src/qemu/qemu_validate.c | 1 + 9 files changed, 88 insertions(+)
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index a0912062ff..c557da0c65 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c
@@ -13649,6 +13654,24 @@ virDomainSEVDefParseXML(virDomainSEVDef *def, }
+static int +virDomainTDXDefParseXML(virDomainTDXDef *def, + xmlXPathContextPtr ctxt) +{ + if (virXPathULongLongBase("string(./policy)", ctxt, 16, &def->policy) < 0) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("failed to get launch security policy for launch security type TDX")); + return -1; + }
This makes the 'policy' attribute mandatory, but QEMU is quite happy with it being unset, so we should not require this in libvirt either.
Yes, but I am trying to align with SEV which has same issue. So aligning with SEV vs. making TDX's 'policy' optional, you prefer the 2nd? Pls confirm.
Yes, consistency is good. So if QEMU's sev/snp object lets policy be optional, then we should make the same change in libvirt's SEV parsing code too. With 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 :|

-----Original Message----- From: Daniel P. Berrangé <berrange@redhat.com> Subject: Re: [PATCH rfcv4 05/13] conf: add tdx as launch security type
On Wed, Mar 26, 2025 at 02:45:55AM +0000, Duan, Zhenzhong wrote:
-----Original Message----- From: Daniel P. Berrangé <berrange@redhat.com> Subject: Re: [PATCH rfcv4 05/13] conf: add tdx as launch security type
On Fri, May 24, 2024 at 02:21:20PM +0800, Zhenzhong Duan wrote:
When 'tdx' is used, the VM will 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 is a child element 'policy' and three optional element for tdx type. In 'policy', bit 0 is set to enable TDX debug, bit 28 set to enable sept-ve-disable, other bits are reserved currently. mrConfigId, mrOwner and mrOwnerConfig are base64 encoded SHA384 digest.
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> --- src/conf/domain_conf.c | 42 +++++++++++++++++++++++++++++++ src/conf/domain_conf.h | 9 +++++++ src/conf/schemas/domaincommon.rng | 29 +++++++++++++++++++++ src/conf/virconftypes.h | 2 ++ src/qemu/qemu_command.c | 2 ++ src/qemu/qemu_firmware.c | 1 + src/qemu/qemu_namespace.c | 1 + src/qemu/qemu_process.c | 1 + src/qemu/qemu_validate.c | 1 + 9 files changed, 88 insertions(+)
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index a0912062ff..c557da0c65 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c
@@ -13649,6 +13654,24 @@ virDomainSEVDefParseXML(virDomainSEVDef *def, }
+static int +virDomainTDXDefParseXML(virDomainTDXDef *def, + xmlXPathContextPtr ctxt) +{ + if (virXPathULongLongBase("string(./policy)", ctxt, 16, &def->policy) < 0) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("failed to get launch security policy for launch security type TDX")); + return -1; + }
This makes the 'policy' attribute mandatory, but QEMU is quite happy with it being unset, so we should not require this in libvirt either.
Yes, but I am trying to align with SEV which has same issue. So aligning with SEV vs. making TDX's 'policy' optional, you prefer the 2nd? Pls
confirm.
Yes, consistency is good. So if QEMU's sev/snp object lets policy be optional, then we should make the same change in libvirt's SEV parsing code too.
Got it, will do. Thanks Zhenzhong

QEMU will provides 'tdx-guest' object which is used to launch encrypted VMs on Intel platform using TDX feature. Command line looks like: $QEMU ... \ -object '{"qom-type":"tdx-guest","id":"lsec0","debug":true,"sept-ve-disable":false,"mrconfigid":"xxx","mrowner":"xxx","mrownerconfig":"xxx"}' \ -machine pc-q35-6.0,confidential-guest-support=lsec0 Signed-off-by: Zhenzhong Duan <zhenzhong.duan@intel.com> --- src/conf/domain_conf.h | 5 +++++ src/qemu/qemu_command.c | 31 +++++++++++++++++++++++++++++++ src/qemu/qemu_validate.c | 11 +++++++++++ 3 files changed, 47 insertions(+) diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 7882b7a75d..bb4973fce8 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -2880,6 +2880,11 @@ struct _virDomainTDXDef { char *mrownerconfig; }; +#define VIR_DOMAIN_TDX_POLICY_DEBUG 0x1 +#define VIR_DOMAIN_TDX_POLICY_SEPT_VE_DISABLE 0x10000000 +#define VIR_DOMAIN_TDX_POLICY_ALLOWED_MASK (VIR_DOMAIN_TDX_POLICY_DEBUG | \ + VIR_DOMAIN_TDX_POLICY_SEPT_VE_DISABLE) + struct _virDomainSecDef { virDomainLaunchSecurity sectype; union { diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index dde2d5fa01..d212d80038 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -9745,6 +9745,36 @@ qemuBuildPVCommandLine(virDomainObj *vm, virCommand *cmd) } +static int +qemuBuildTDXCommandLine(virDomainObj *vm, virCommand *cmd, + virDomainTDXDef *tdx) +{ + g_autoptr(virJSONValue) props = NULL; + qemuDomainObjPrivate *priv = vm->privateData; + bool sept_ve_disable = tdx->policy & VIR_DOMAIN_TDX_POLICY_SEPT_VE_DISABLE; + + VIR_DEBUG("policy=0x%llx", tdx->policy); + + if (qemuMonitorCreateObjectProps(&props, "tdx-guest", "lsec0", + "B:debug", !!(tdx->policy & VIR_DOMAIN_TDX_POLICY_DEBUG), + "S:mrconfigid", tdx->mrconfigid, + "S:mrowner", tdx->mrowner, + "S:mrownerconfig", tdx->mrownerconfig, + NULL) < 0) + return -1; + + /* By default, QEMU set sept-ve-disable which is required by linux kernel */ + if (!sept_ve_disable && + virJSONValueObjectAdd(&props, "b:sept-ve-disable", false, NULL) < 0) + return -1; + + if (qemuBuildObjectCommandlineFromJSON(cmd, props, priv->qemuCaps) < 0) + return -1; + + return 0; +} + + static int qemuBuildSecCommandLine(virDomainObj *vm, virCommand *cmd, virDomainSecDef *sec) @@ -9760,6 +9790,7 @@ qemuBuildSecCommandLine(virDomainObj *vm, virCommand *cmd, return qemuBuildPVCommandLine(vm, cmd); break; case VIR_DOMAIN_LAUNCH_SECURITY_TDX: + return qemuBuildTDXCommandLine(vm, cmd, &sec->data.tdx); case VIR_DOMAIN_LAUNCH_SECURITY_NONE: case VIR_DOMAIN_LAUNCH_SECURITY_LAST: virReportEnumRangeError(virDomainLaunchSecurity, sec->sectype); diff --git a/src/qemu/qemu_validate.c b/src/qemu/qemu_validate.c index ee25fd70d9..db8493be68 100644 --- a/src/qemu/qemu_validate.c +++ b/src/qemu/qemu_validate.c @@ -1323,6 +1323,17 @@ qemuValidateDomainDef(const virDomainDef *def, } break; case VIR_DOMAIN_LAUNCH_SECURITY_TDX: + if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_TDX_GUEST)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Intel TDX launch security is not supported with this QEMU binary")); + return -1; + } + if (def->sec->data.tdx.policy & ~VIR_DOMAIN_TDX_POLICY_ALLOWED_MASK) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Only bit0(debug) and bit28(sept-ve-disable) are supported intel TDX launch security policy")); + return -1; + } + break; case VIR_DOMAIN_LAUNCH_SECURITY_NONE: case VIR_DOMAIN_LAUNCH_SECURITY_LAST: virReportEnumRangeError(virDomainLaunchSecurity, def->sec->sectype); -- 2.34.1

On Fri, May 24, 2024 at 02:21:21PM +0800, Zhenzhong Duan wrote:
QEMU will provides 'tdx-guest' object which is used to launch encrypted VMs on Intel platform using TDX feature.
Command line looks like: $QEMU ... \ -object '{"qom-type":"tdx-guest","id":"lsec0","debug":true,"sept-ve-disable":false,"mrconfigid":"xxx","mrowner":"xxx","mrownerconfig":"xxx"}' \ -machine pc-q35-6.0,confidential-guest-support=lsec0
Signed-off-by: Zhenzhong Duan <zhenzhong.duan@intel.com> --- src/conf/domain_conf.h | 5 +++++ src/qemu/qemu_command.c | 31 +++++++++++++++++++++++++++++++ src/qemu/qemu_validate.c | 11 +++++++++++ 3 files changed, 47 insertions(+)
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 7882b7a75d..bb4973fce8 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -2880,6 +2880,11 @@ struct _virDomainTDXDef { char *mrownerconfig; };
+#define VIR_DOMAIN_TDX_POLICY_DEBUG 0x1 +#define VIR_DOMAIN_TDX_POLICY_SEPT_VE_DISABLE 0x10000000 +#define VIR_DOMAIN_TDX_POLICY_ALLOWED_MASK (VIR_DOMAIN_TDX_POLICY_DEBUG | \ + VIR_DOMAIN_TDX_POLICY_SEPT_VE_DISABLE) + struct _virDomainSecDef { virDomainLaunchSecurity sectype; union { diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index dde2d5fa01..d212d80038 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -9745,6 +9745,36 @@ qemuBuildPVCommandLine(virDomainObj *vm, virCommand *cmd) }
+static int +qemuBuildTDXCommandLine(virDomainObj *vm, virCommand *cmd, + virDomainTDXDef *tdx) +{ + g_autoptr(virJSONValue) props = NULL; + qemuDomainObjPrivate *priv = vm->privateData; + bool sept_ve_disable = tdx->policy & VIR_DOMAIN_TDX_POLICY_SEPT_VE_DISABLE; + + VIR_DEBUG("policy=0x%llx", tdx->policy); + + if (qemuMonitorCreateObjectProps(&props, "tdx-guest", "lsec0", + "B:debug", !!(tdx->policy & VIR_DOMAIN_TDX_POLICY_DEBUG), + "S:mrconfigid", tdx->mrconfigid, + "S:mrowner", tdx->mrowner, + "S:mrownerconfig", tdx->mrownerconfig, + NULL) < 0) + return -1;
I like that you've just exposed the "policy" as an int field in libvirt, but find it unpleasant that we have to unpack it to pass bits to QEMU, whereupon QEMU re-packs it into the original int field we already had. I think this is a mistake in the QEMU QAPI design - QEMU shoud just accept the policy in 'int' format. I've CC'd you on a mail to qemu-devel where I raise this point.
+ + /* By default, QEMU set sept-ve-disable which is required by linux kernel */ + if (!sept_ve_disable && + virJSONValueObjectAdd(&props, "b:sept-ve-disable", false, NULL) < 0) + return -1; + + if (qemuBuildObjectCommandlineFromJSON(cmd, props, priv->qemuCaps) < 0) + return -1; + + return 0; +} + + static int qemuBuildSecCommandLine(virDomainObj *vm, virCommand *cmd, virDomainSecDef *sec) @@ -9760,6 +9790,7 @@ qemuBuildSecCommandLine(virDomainObj *vm, virCommand *cmd, return qemuBuildPVCommandLine(vm, cmd); break; case VIR_DOMAIN_LAUNCH_SECURITY_TDX: + return qemuBuildTDXCommandLine(vm, cmd, &sec->data.tdx); case VIR_DOMAIN_LAUNCH_SECURITY_NONE: case VIR_DOMAIN_LAUNCH_SECURITY_LAST: virReportEnumRangeError(virDomainLaunchSecurity, sec->sectype); diff --git a/src/qemu/qemu_validate.c b/src/qemu/qemu_validate.c index ee25fd70d9..db8493be68 100644 --- a/src/qemu/qemu_validate.c +++ b/src/qemu/qemu_validate.c @@ -1323,6 +1323,17 @@ qemuValidateDomainDef(const virDomainDef *def, } break; case VIR_DOMAIN_LAUNCH_SECURITY_TDX: + if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_TDX_GUEST)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Intel TDX launch security is not supported with this QEMU binary")); + return -1; + } + if (def->sec->data.tdx.policy & ~VIR_DOMAIN_TDX_POLICY_ALLOWED_MASK) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Only bit0(debug) and bit28(sept-ve-disable) are supported intel TDX launch security policy")); + return -1; + } + break; case VIR_DOMAIN_LAUNCH_SECURITY_NONE: case VIR_DOMAIN_LAUNCH_SECURITY_LAST: virReportEnumRangeError(virDomainLaunchSecurity, def->sec->sectype); -- 2.34.1
With 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 :|

-----Original Message----- From: Daniel P. Berrangé <berrange@redhat.com> Subject: Re: [PATCH rfcv4 06/13] qemu: Add command line and validation for TDX type
On Fri, May 24, 2024 at 02:21:21PM +0800, Zhenzhong Duan wrote:
QEMU will provides 'tdx-guest' object which is used to launch encrypted VMs on Intel platform using TDX feature.
Command line looks like: $QEMU ... \ -object '{"qom-type":"tdx-guest","id":"lsec0","debug":true,"sept-ve- disable":false,"mrconfigid":"xxx","mrowner":"xxx","mrownerconfig":"xxx"}' \ -machine pc-q35-6.0,confidential-guest-support=lsec0
Signed-off-by: Zhenzhong Duan <zhenzhong.duan@intel.com> --- src/conf/domain_conf.h | 5 +++++ src/qemu/qemu_command.c | 31 +++++++++++++++++++++++++++++++ src/qemu/qemu_validate.c | 11 +++++++++++ 3 files changed, 47 insertions(+)
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 7882b7a75d..bb4973fce8 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -2880,6 +2880,11 @@ struct _virDomainTDXDef { char *mrownerconfig; };
+#define VIR_DOMAIN_TDX_POLICY_DEBUG 0x1 +#define VIR_DOMAIN_TDX_POLICY_SEPT_VE_DISABLE 0x10000000 +#define VIR_DOMAIN_TDX_POLICY_ALLOWED_MASK (VIR_DOMAIN_TDX_POLICY_DEBUG | \ + VIR_DOMAIN_TDX_POLICY_SEPT_VE_DISABLE) + struct _virDomainSecDef { virDomainLaunchSecurity sectype; union { diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index dde2d5fa01..d212d80038 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -9745,6 +9745,36 @@ qemuBuildPVCommandLine(virDomainObj *vm, virCommand *cmd) }
+static int +qemuBuildTDXCommandLine(virDomainObj *vm, virCommand *cmd, + virDomainTDXDef *tdx) +{ + g_autoptr(virJSONValue) props = NULL; + qemuDomainObjPrivate *priv = vm->privateData; + bool sept_ve_disable = tdx->policy & VIR_DOMAIN_TDX_POLICY_SEPT_VE_DISABLE; + + VIR_DEBUG("policy=0x%llx", tdx->policy); + + if (qemuMonitorCreateObjectProps(&props, "tdx-guest", "lsec0", + "B:debug", !!(tdx->policy & VIR_DOMAIN_TDX_POLICY_DEBUG), + "S:mrconfigid", tdx->mrconfigid, + "S:mrowner", tdx->mrowner, + "S:mrownerconfig", tdx->mrownerconfig, + NULL) < 0) + return -1;
I like that you've just exposed the "policy" as an int field in libvirt, but find it unpleasant that we have to unpack it to pass bits to QEMU, whereupon QEMU re-packs it into the original int field we already had.
Yes.
I think this is a mistake in the QEMU QAPI design - QEMU shoud just accept the policy in 'int' format. I've CC'd you on a mail to qemu-devel where I raise this point.
Agree with your point. Thanks Zhenzhong

On 5/24/24 00:21, Zhenzhong Duan wrote:
QEMU will provides 'tdx-guest' object which is used to launch encrypted VMs on Intel platform using TDX feature.
Command line looks like: $QEMU ... \ -object '{"qom-type":"tdx-guest","id":"lsec0","debug":true,"sept-ve-disable":false,"mrconfigid":"xxx","mrowner":"xxx","mrownerconfig":"xxx"}' \ -machine pc-q35-6.0,confidential-guest-support=lsec0
Signed-off-by: Zhenzhong Duan <zhenzhong.duan@intel.com> --- src/conf/domain_conf.h | 5 +++++ src/qemu/qemu_command.c | 31 +++++++++++++++++++++++++++++++ src/qemu/qemu_validate.c | 11 +++++++++++ 3 files changed, 47 insertions(+)
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 7882b7a75d..bb4973fce8 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -2880,6 +2880,11 @@ struct _virDomainTDXDef { char *mrownerconfig; };
+#define VIR_DOMAIN_TDX_POLICY_DEBUG 0x1 +#define VIR_DOMAIN_TDX_POLICY_SEPT_VE_DISABLE 0x10000000 +#define VIR_DOMAIN_TDX_POLICY_ALLOWED_MASK (VIR_DOMAIN_TDX_POLICY_DEBUG | \ + VIR_DOMAIN_TDX_POLICY_SEPT_VE_DISABLE) + struct _virDomainSecDef { virDomainLaunchSecurity sectype; union { diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index dde2d5fa01..d212d80038 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -9745,6 +9745,36 @@ qemuBuildPVCommandLine(virDomainObj *vm, virCommand *cmd) }
+static int +qemuBuildTDXCommandLine(virDomainObj *vm, virCommand *cmd, + virDomainTDXDef *tdx) +{ + g_autoptr(virJSONValue) props = NULL; + qemuDomainObjPrivate *priv = vm->privateData; + bool sept_ve_disable = tdx->policy & VIR_DOMAIN_TDX_POLICY_SEPT_VE_DISABLE; + + VIR_DEBUG("policy=0x%llx", tdx->policy); + + if (qemuMonitorCreateObjectProps(&props, "tdx-guest", "lsec0", + "B:debug", !!(tdx->policy & VIR_DOMAIN_TDX_POLICY_DEBUG),
I recall Daniel suggesting a change to the QAPI for this field. It appears his suggestion was incorporated in V7 of the QEMU patches, where this field is now named 'attributes' and typed as uint64 https://mail.gnu.org/archive/html/qemu-devel/2025-01/msg04476.html Regards, Jim
+ "S:mrconfigid", tdx->mrconfigid, + "S:mrowner", tdx->mrowner, + "S:mrownerconfig", tdx->mrownerconfig, + NULL) < 0) + return -1; + + /* By default, QEMU set sept-ve-disable which is required by linux kernel */ + if (!sept_ve_disable && + virJSONValueObjectAdd(&props, "b:sept-ve-disable", false, NULL) < 0) + return -1; + + if (qemuBuildObjectCommandlineFromJSON(cmd, props, priv->qemuCaps) < 0) + return -1; + + return 0; +} + + static int qemuBuildSecCommandLine(virDomainObj *vm, virCommand *cmd, virDomainSecDef *sec) @@ -9760,6 +9790,7 @@ qemuBuildSecCommandLine(virDomainObj *vm, virCommand *cmd, return qemuBuildPVCommandLine(vm, cmd); break; case VIR_DOMAIN_LAUNCH_SECURITY_TDX: + return qemuBuildTDXCommandLine(vm, cmd, &sec->data.tdx); case VIR_DOMAIN_LAUNCH_SECURITY_NONE: case VIR_DOMAIN_LAUNCH_SECURITY_LAST: virReportEnumRangeError(virDomainLaunchSecurity, sec->sectype); diff --git a/src/qemu/qemu_validate.c b/src/qemu/qemu_validate.c index ee25fd70d9..db8493be68 100644 --- a/src/qemu/qemu_validate.c +++ b/src/qemu/qemu_validate.c @@ -1323,6 +1323,17 @@ qemuValidateDomainDef(const virDomainDef *def, } break; case VIR_DOMAIN_LAUNCH_SECURITY_TDX: + if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_TDX_GUEST)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Intel TDX launch security is not supported with this QEMU binary")); + return -1; + } + if (def->sec->data.tdx.policy & ~VIR_DOMAIN_TDX_POLICY_ALLOWED_MASK) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Only bit0(debug) and bit28(sept-ve-disable) are supported intel TDX launch security policy")); + return -1; + } + break; case VIR_DOMAIN_LAUNCH_SECURITY_NONE: case VIR_DOMAIN_LAUNCH_SECURITY_LAST: virReportEnumRangeError(virDomainLaunchSecurity, def->sec->sectype);

-----Original Message----- From: Jim Fehlig <jfehlig@suse.com> Subject: Re: [PATCH rfcv4 06/13] qemu: Add command line and validation for TDX type
On 5/24/24 00:21, Zhenzhong Duan wrote:
QEMU will provides 'tdx-guest' object which is used to launch encrypted VMs on Intel platform using TDX feature.
Command line looks like: $QEMU ... \ -object '{"qom-type":"tdx-guest","id":"lsec0","debug":true,"sept-ve- disable":false,"mrconfigid":"xxx","mrowner":"xxx","mrownerconfig":"xxx"}' \ -machine pc-q35-6.0,confidential-guest-support=lsec0
Signed-off-by: Zhenzhong Duan <zhenzhong.duan@intel.com> --- src/conf/domain_conf.h | 5 +++++ src/qemu/qemu_command.c | 31 +++++++++++++++++++++++++++++++ src/qemu/qemu_validate.c | 11 +++++++++++ 3 files changed, 47 insertions(+)
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 7882b7a75d..bb4973fce8 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -2880,6 +2880,11 @@ struct _virDomainTDXDef { char *mrownerconfig; };
+#define VIR_DOMAIN_TDX_POLICY_DEBUG 0x1 +#define VIR_DOMAIN_TDX_POLICY_SEPT_VE_DISABLE 0x10000000 +#define VIR_DOMAIN_TDX_POLICY_ALLOWED_MASK (VIR_DOMAIN_TDX_POLICY_DEBUG | \ + VIR_DOMAIN_TDX_POLICY_SEPT_VE_DISABLE) + struct _virDomainSecDef { virDomainLaunchSecurity sectype; union { diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index dde2d5fa01..d212d80038 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -9745,6 +9745,36 @@ qemuBuildPVCommandLine(virDomainObj *vm, virCommand *cmd) }
+static int +qemuBuildTDXCommandLine(virDomainObj *vm, virCommand *cmd, + virDomainTDXDef *tdx) +{ + g_autoptr(virJSONValue) props = NULL; + qemuDomainObjPrivate *priv = vm->privateData; + bool sept_ve_disable = tdx->policy & VIR_DOMAIN_TDX_POLICY_SEPT_VE_DISABLE; + + VIR_DEBUG("policy=0x%llx", tdx->policy); + + if (qemuMonitorCreateObjectProps(&props, "tdx-guest", "lsec0", + "B:debug", !!(tdx->policy & VIR_DOMAIN_TDX_POLICY_DEBUG),
I recall Daniel suggesting a change to the QAPI for this field. It appears his suggestion was incorporated in V7 of the QEMU patches, where this field is now named 'attributes' and typed as uint64
https://mail.gnu.org/archive/html/qemu-devel/2025-01/msg04476.html
Yes, corresponding change is also added in https://github.com/intel/libvirt-tdx/commits/tdx_for_upstream_v1.wip/ Thanks Zhenzhong

TDX guest requires some special parameters to boot, currently: "kernel_irqchip=split" "pmu!=on" "smm!=on" "-bios" If not specified explicitly, QEMU should configure this option implicitly when start a TDX guest. Signed-off-by: Zhenzhong Duan <zhenzhong.duan@intel.com> --- src/qemu/qemu_validate.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/qemu/qemu_validate.c b/src/qemu/qemu_validate.c index db8493be68..8a3a64227e 100644 --- a/src/qemu/qemu_validate.c +++ b/src/qemu/qemu_validate.c @@ -1333,6 +1333,38 @@ qemuValidateDomainDef(const virDomainDef *def, _("Only bit0(debug) and bit28(sept-ve-disable) are supported intel TDX launch security policy")); return -1; } + if (def->features[VIR_DOMAIN_FEATURE_IOAPIC] == VIR_DOMAIN_IOAPIC_KVM) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Intel TDX launch security needs split kernel irqchip")); + return -1; + } + /* Current KVM doesn't support PMU for TD guest. It returns + * error if TD is created with PMU bit being set in attributes. + * By default, QEMU disable PMU for TD guest. + */ + if (def->features[VIR_DOMAIN_FEATURE_PMU] == VIR_TRISTATE_SWITCH_ON) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Intel TDX launch security is not supported with PMU enabled")); + return -1; + } + /* TDX doesn't support SMM and VMM cannot emulate SMM for TDX VMs + * because VMM cannot manipulate TDX VM's memory. + * By default, QEMU disable SMM for TD guest. + */ + if (def->features[VIR_DOMAIN_FEATURE_SMM] == VIR_TRISTATE_SWITCH_ON) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Intel TDX launch security is not supported with SMM enabled")); + return -1; + } + /* TDVF(OVMF) needs to run at private memory for TD guest. TDX cannot + * support pflash device since it doesn't support read-only private memory. + * Thus load TDVF(OVMF) with -bios option for TDs. + */ + if (def->os.loader && def->os.loader->type == VIR_DOMAIN_LOADER_TYPE_PFLASH) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Intel TDX launch security is not supported with pflash loader")); + return -1; + } break; case VIR_DOMAIN_LAUNCH_SECURITY_NONE: case VIR_DOMAIN_LAUNCH_SECURITY_LAST: -- 2.34.1

On Fri, May 24, 2024 at 02:21:22PM +0800, Zhenzhong Duan wrote:
TDX guest requires some special parameters to boot, currently:
"kernel_irqchip=split" "pmu!=on" "smm!=on" "-bios"
If not specified explicitly, QEMU should configure this option implicitly when start a TDX guest.
Signed-off-by: Zhenzhong Duan <zhenzhong.duan@intel.com> --- src/qemu/qemu_validate.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+)
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> With 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 :|

Add element "quoteGenerationService" to tdx launch security type. Currently it contains only one sub-element "SocketAddress". "SocketAddress" is modelized according to QEMU QAPI, supporting inet, unix, vsock and fd type and variant attributes depending on type. XML example: <launchSecurity type='tdx'> <policy>0x0</policy> <mrConfigId>xxx</mrConfigId> <mrOwner>xxx</mrOwner> <mrOwnerConfig>xxx</mrOwnerConfig> <quoteGenerationService> <SocketAddress type='vsock' cid='xxx' port='xxx'/> </quoteGenerationService> </launchSecurity> QEMU command line example: qemu-system-x86_64 \ -object '{"qom-type":"tdx-guest","id":"lsec0","sept-ve-disable":false,"mrconfigid":"xxx","mrowner":"xxx","mrownerconfig":"xxx","quote-generation-socket":{"type":"vsock","cid":"xxx","port":"xxx"}}' \ -machine pc-q35-6.0,confidential-guest-support=lsec0 Signed-off-by: Zhenzhong Duan <zhenzhong.duan@intel.com> --- src/conf/domain_conf.c | 272 +++++++++++++++++++++++++++++- src/conf/domain_conf.h | 61 +++++++ src/conf/schemas/domaincommon.rng | 106 ++++++++++++ src/qemu/qemu_command.c | 106 ++++++++++++ 4 files changed, 544 insertions(+), 1 deletion(-) diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index c557da0c65..e1ae8295e5 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -1511,6 +1511,15 @@ VIR_ENUM_IMPL(virDomainLaunchSecurity, "tdx", ); +VIR_ENUM_IMPL(virDomainSocketAddress, + VIR_DOMAIN_SOCKET_ADDRESS_LAST, + "", + "inet", + "unix", + "vsock", + "fd", +); + typedef enum { VIR_DOMAIN_NET_VHOSTUSER_MODE_NONE, VIR_DOMAIN_NET_VHOSTUSER_MODE_CLIENT, @@ -13654,6 +13663,190 @@ virDomainSEVDefParseXML(virDomainSEVDef *def, } +static int +virDomainInetSocketAddressDefParseXML(InetSocketAddress *inet, + xmlNodePtr node) +{ + int ret; + + if (!(inet->host = virXMLPropString(node, "host"))) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("missing host for inet socket address")); + return -1; + } + + if (!(inet->port = virXMLPropString(node, "port"))) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("missing port for inet socket address")); + return -1; + } + + if (virXMLPropTristateBool(node, "numeric", VIR_XML_PROP_NONE, + &inet->numeric) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("wrong attribute numeric for inet socket address")); + return -1; + } + + if ((ret = virXMLPropUInt(node, "to", 10, VIR_XML_PROP_NONE, + &inet->to)) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("wrong attribute to for inet socket address")); + return -1; + } + if (!ret) + inet->has_to = true; + + if (virXMLPropTristateBool(node, "ipv4", VIR_XML_PROP_NONE, + &inet->ipv4) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("wrong attribute ipv4 for inet socket address")); + return -1; + } + + if (virXMLPropTristateBool(node, "ipv6", VIR_XML_PROP_NONE, + &inet->ipv6) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("wrong attribute ipv6 for inet socket address")); + return -1; + } + + if (virXMLPropTristateBool(node, "keep_alive", VIR_XML_PROP_NONE, + &inet->keep_alive) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("wrong attribute keep_alive for inet socket address")); + return -1; + } + + if (virXMLPropTristateBool(node, "mptcp", VIR_XML_PROP_NONE, + &inet->mptcp) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("wrong attribute mptcp for inet socket address")); + return -1; + } + + return 0; +} + + +static int +virDomainUnixSocketAddressDefParseXML(UnixSocketAddress *Unix, + xmlNodePtr node) +{ + if (!(Unix->path = virXMLPropString(node, "path"))) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("missing path for unix socket address")); + return -1; + } + + if (virXMLPropTristateBool(node, "abstract", VIR_XML_PROP_NONE, + &Unix->abstract) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("wrong attribute abstract for unix socket address")); + return -1; + } + + if (virXMLPropTristateBool(node, "tight", VIR_XML_PROP_NONE, + &Unix->tight) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("wrong attribute tight for unix socket address")); + return -1; + } + + return 0; +} + + +static int +virDomainVsockSocketAddressDefParseXML(VsockSocketAddress *vsock, + xmlNodePtr node) +{ + if (!(vsock->cid = virXMLPropString(node, "cid"))) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("missing cid for vsock socket address")); + return -1; + } + + if (!(vsock->port = virXMLPropString(node, "port"))) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("missing port for vsock socket address")); + return -1; + } + + return 0; +} + + +static int +virDomainFdSocketAddressDefParseXML(FdSocketAddress *fd, + xmlNodePtr node) +{ + if (!(fd->str = virXMLPropString(node, "str"))) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("missing fd for fd socket address")); + return -1; + } + + return 0; +} + + +static int +virDomainTDXQGSDefParseXML(virDomainTDXDef *def, xmlXPathContextPtr ctxt) +{ + g_autofree xmlNodePtr *nodes = NULL; + SocketAddress *sa = &def->qgs_sa; + xmlNodePtr node; + int n; + + if ((n = virXPathNodeSet("./quoteGenerationService/SocketAddress", + ctxt, &nodes)) < 0) + return -1; + + if (!n) + return 0; + + if (n > 1) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("only a single QGS element is supported")); + return -1; + } + node = nodes[0]; + + if (virXMLPropEnum(node, "type", virDomainSocketAddressTypeFromString, + VIR_XML_PROP_REQUIRED, &sa->type) < 0) + return -1; + + switch ((virDomainSocketAddress) def->qgs_sa.type) { + case VIR_DOMAIN_SOCKET_ADDRESS_INET: + if (virDomainInetSocketAddressDefParseXML(&sa->u.inet, node) < 0) + return -1; + break; + case VIR_DOMAIN_SOCKET_ADDRESS_UNIX: + if (virDomainUnixSocketAddressDefParseXML(&sa->u.Unix, node) < 0) + return -1; + break; + case VIR_DOMAIN_SOCKET_ADDRESS_VSOCK: + if (virDomainVsockSocketAddressDefParseXML(&sa->u.vsock, node) < 0) + return -1; + break; + case VIR_DOMAIN_SOCKET_ADDRESS_FD: + if (virDomainFdSocketAddressDefParseXML(&sa->u.fd, node) < 0) + return -1; + break; + case VIR_DOMAIN_SOCKET_ADDRESS_NONE: + case VIR_DOMAIN_SOCKET_ADDRESS_LAST: + default: + virReportError(VIR_ERR_XML_ERROR, + _("unsupported socket address type '%1$s'"), + virDomainSocketAddressTypeToString(def->qgs_sa.type)); + return -1; + } + + return 0; +} + + static int virDomainTDXDefParseXML(virDomainTDXDef *def, xmlXPathContextPtr ctxt) @@ -13668,7 +13861,7 @@ virDomainTDXDefParseXML(virDomainTDXDef *def, def->mrowner = virXPathString("string(./mrOwner)", ctxt); def->mrownerconfig = virXPathString("string(./mrOwnerConfig)", ctxt); - return 0; + return virDomainTDXQGSDefParseXML(def, ctxt); } @@ -26652,6 +26845,82 @@ virDomainKeyWrapDefFormat(virBuffer *buf, virDomainKeyWrapDef *keywrap) } +static void +virDomainTDXQGSDefFormat(virBuffer *buf, virDomainTDXDef *tdx) +{ + SocketAddress *sa = &tdx->qgs_sa; + + if (sa->type == VIR_DOMAIN_SOCKET_ADDRESS_NONE) + return; + + virBufferAddLit(buf, "<quoteGenerationService>\n"); + virBufferAdjustIndent(buf, 2); + virBufferAsprintf(buf, "<SocketAddress type='%s'", + virDomainSocketAddressTypeToString(sa->type)); + + switch ((virDomainSocketAddress) sa->type) { + case VIR_DOMAIN_SOCKET_ADDRESS_INET: + { + InetSocketAddress *inet = &sa->u.inet; + + virBufferAsprintf(buf, " host='%s' port='%s'", inet->host, inet->port); + if (inet->numeric != VIR_TRISTATE_BOOL_ABSENT) + virBufferAsprintf(buf, " numeric='%s'", + virTristateBoolTypeToString(inet->numeric)); + if (inet->to) + virBufferAsprintf(buf, " to='%d'", inet->to); + if (inet->ipv4 != VIR_TRISTATE_BOOL_ABSENT) + virBufferAsprintf(buf, " ipv4='%s'", + virTristateBoolTypeToString(inet->ipv4)); + if (inet->ipv6 != VIR_TRISTATE_BOOL_ABSENT) + virBufferAsprintf(buf, " ipv6='%s'", + virTristateBoolTypeToString(inet->ipv6)); + if (inet->keep_alive != VIR_TRISTATE_BOOL_ABSENT) + virBufferAsprintf(buf, " keep_alive='%s'", + virTristateBoolTypeToString(inet->keep_alive)); + if (inet->mptcp != VIR_TRISTATE_BOOL_ABSENT) + virBufferAsprintf(buf, " mptcp='%s'", + virTristateBoolTypeToString(inet->mptcp)); + break; + } + case VIR_DOMAIN_SOCKET_ADDRESS_UNIX: + { + UnixSocketAddress *Unix = &sa->u.Unix; + + virBufferAsprintf(buf, " path='%s'", Unix->path); + if (Unix->abstract != VIR_TRISTATE_BOOL_ABSENT) + virBufferAsprintf(buf, " abstract='%s'", + virTristateBoolTypeToString(Unix->abstract)); + if (Unix->tight != VIR_TRISTATE_BOOL_ABSENT) + virBufferAsprintf(buf, " tight='%s'", + virTristateBoolTypeToString(Unix->tight)); + break; + } + case VIR_DOMAIN_SOCKET_ADDRESS_VSOCK: + { + VsockSocketAddress *vsock = &sa->u.vsock; + + virBufferAsprintf(buf, " cid='%s' port='%s'", vsock->cid, vsock->port); + break; + } + case VIR_DOMAIN_SOCKET_ADDRESS_FD: + { + FdSocketAddress *fd = &sa->u.fd; + + virBufferAsprintf(buf, " str='%s'", fd->str); + break; + } + case VIR_DOMAIN_SOCKET_ADDRESS_NONE: + case VIR_DOMAIN_SOCKET_ADDRESS_LAST: + default: + break; + } + virBufferAddLit(buf, "/>\n"); + virBufferAdjustIndent(buf, -2); + virBufferAddLit(buf, "</quoteGenerationService>\n"); +} + + static void virDomainSecDefFormat(virBuffer *buf, virDomainSecDef *sec) { @@ -26699,6 +26968,7 @@ virDomainSecDefFormat(virBuffer *buf, virDomainSecDef *sec) virBufferEscapeString(&childBuf, "<mrOwner>%s</mrOwner>\n", tdx->mrowner); if (tdx->mrownerconfig) virBufferEscapeString(&childBuf, "<mrOwnerConfig>%s</mrOwnerConfig>\n", tdx->mrownerconfig); + virDomainTDXQGSDefFormat(&childBuf, tdx); break; } diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index bb4973fce8..15cdb3e0e6 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -2852,6 +2852,55 @@ struct _virDomainKeyWrapDef { virTristateSwitch dea; }; +typedef enum { + VIR_DOMAIN_SOCKET_ADDRESS_NONE, + VIR_DOMAIN_SOCKET_ADDRESS_INET, + VIR_DOMAIN_SOCKET_ADDRESS_UNIX, + VIR_DOMAIN_SOCKET_ADDRESS_VSOCK, + VIR_DOMAIN_SOCKET_ADDRESS_FD, + + VIR_DOMAIN_SOCKET_ADDRESS_LAST +} virDomainSocketAddress; + +typedef struct _InetSocketAddress InetSocketAddress; +typedef struct _UnixSocketAddress UnixSocketAddress; +typedef struct _VsockSocketAddress VsockSocketAddress; +typedef struct _FdSocketAddress FdSocketAddress; + +struct _InetSocketAddress { + char *host; + char *port; + bool has_numeric; + virTristateBool numeric; + bool has_to; + unsigned int to; + bool has_ipv4; + virTristateBool ipv4; + bool has_ipv6; + virTristateBool ipv6; + bool has_keep_alive; + virTristateBool keep_alive; + bool has_mptcp; + virTristateBool mptcp; +}; + +struct _UnixSocketAddress { + char *path; + bool has_abstract; + virTristateBool abstract; + bool has_tight; + virTristateBool tight; +}; + +struct _VsockSocketAddress { + char *cid; + char *port; +}; + +struct _FdSocketAddress { + char *str; +}; + typedef enum { VIR_DOMAIN_LAUNCH_SECURITY_NONE, VIR_DOMAIN_LAUNCH_SECURITY_SEV, @@ -2873,11 +2922,22 @@ struct _virDomainSEVDef { virTristateBool kernel_hashes; }; +typedef struct SocketAddress { + virDomainSocketAddress type; + union { + InetSocketAddress inet; + UnixSocketAddress Unix; + VsockSocketAddress vsock; + FdSocketAddress fd; + } u; +} SocketAddress; + struct _virDomainTDXDef { unsigned long long policy; char *mrconfigid; char *mrowner; char *mrownerconfig; + SocketAddress qgs_sa; }; #define VIR_DOMAIN_TDX_POLICY_DEBUG 0x1 @@ -4258,6 +4318,7 @@ VIR_ENUM_DECL(virDomainCryptoBackend); VIR_ENUM_DECL(virDomainShmemModel); VIR_ENUM_DECL(virDomainShmemRole); VIR_ENUM_DECL(virDomainLaunchSecurity); +VIR_ENUM_DECL(virDomainSocketAddress); /* from libvirt.h */ VIR_ENUM_DECL(virDomainState); VIR_ENUM_DECL(virDomainNostateReason); diff --git a/src/conf/schemas/domaincommon.rng b/src/conf/schemas/domaincommon.rng index f6e1782b33..e8cc78992a 100644 --- a/src/conf/schemas/domaincommon.rng +++ b/src/conf/schemas/domaincommon.rng @@ -591,9 +591,115 @@ <data type="string"/> </element> </optional> + <optional> + <element name="quoteGenerationService"> + <ref name="SocketAddress"/> + </element> + </optional> </interleave> </define> + <define name="SocketAddress"> + <element name="SocketAddress"> + <choice> + <group> + <ref name="InetSocketAddress"/> + </group> + <group> + <ref name="UnixSocketAddress"/> + </group> + <group> + <ref name="VsockSocketAddress"/> + </group> + <group> + <ref name="FdSocketAddress"/> + </group> + </choice> + </element> + </define> + + <define name="InetSocketAddress"> + <attribute name="type"> + <value>inet</value> + </attribute> + <attribute name="host"> + <data type="string"/> + </attribute> + <attribute name="port"> + <data type="string"/> + </attribute> + <optional> + <attribute name="numeric"> + <ref name="virYesNo"/> + </attribute> + </optional> + <optional> + <attribute name="to"> + <ref name="uint16"/> + </attribute> + </optional> + <optional> + <attribute name="ipv4"> + <ref name="virYesNo"/> + </attribute> + </optional> + <optional> + <attribute name="ipv6"> + <ref name="virYesNo"/> + </attribute> + </optional> + <optional> + <attribute name="keep_alive"> + <ref name="virYesNo"/> + </attribute> + </optional> + <optional> + <attribute name="mptcp"> + <ref name="virYesNo"/> + </attribute> + </optional> + </define> + + <define name="UnixSocketAddress"> + <attribute name="type"> + <value>unix</value> + </attribute> + <attribute name="path"> + <data type="string"/> + </attribute> + <optional> + <attribute name="abstract"> + <ref name="virYesNo"/> + </attribute> + </optional> + <optional> + <attribute name="tight"> + <ref name="virYesNo"/> + </attribute> + </optional> + </define> + + <define name="VsockSocketAddress"> + <attribute name="type"> + <value>vsock</value> + </attribute> + <attribute name="cid"> + <data type="string"/> + </attribute> + <attribute name="port"> + <data type="string"/> + </attribute> + </define> + + <define name="FdSocketAddress"> + <attribute name="type"> + <value>fd</value> + </attribute> + <attribute name="str"> + <data type="string"/> + </attribute> + </define> + <!-- Enable or disable perf events for the domain. For each of the events the following rules apply: diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index d212d80038..05fec05cd5 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -9745,21 +9745,127 @@ qemuBuildPVCommandLine(virDomainObj *vm, virCommand *cmd) } +static virJSONValue * +qemuJSONBuildInetSocketAddress(const InetSocketAddress *inet) +{ + g_autoptr(virJSONValue) addr = NULL; + g_autoptr(virJSONValue) data = NULL; + + if (virJSONValueObjectAdd(&addr, + "s:type", "inet", + "s:host", inet->host, + "s:port", inet->port, + "T:numeric", inet->numeric, + "p:to", inet->to, + "T:ipv4", inet->ipv4, + "T:ipv6", inet->ipv6, + "T:keep-alive", inet->keep_alive, + "T:mptcp", inet->mptcp, + NULL) < 0) + return NULL; + + return g_steal_pointer(&addr); +} + + +static virJSONValue * +qemuJSONBuildUnixSocketAddress(const UnixSocketAddress *Unix) +{ + g_autoptr(virJSONValue) addr = NULL; + g_autoptr(virJSONValue) data = NULL; + + if (virJSONValueObjectAdd(&addr, + "s:type", "unix", + "s:path", Unix->path, + "T:abstract", Unix->abstract, + "T:tight", Unix->tight, + NULL) < 0) + return NULL; + + return g_steal_pointer(&addr); +} + + +static virJSONValue * +qemuJSONBuildVsockSocketAddress(const VsockSocketAddress *vsock) +{ + g_autoptr(virJSONValue) addr = NULL; + g_autoptr(virJSONValue) data = NULL; + + if (virJSONValueObjectAdd(&addr, + "s:type", "vsock", + "s:cid", vsock->cid, + "s:port", vsock->port, + NULL) < 0) + return NULL; + + return g_steal_pointer(&addr); +} + + +static virJSONValue * +qemuJSONBuildFdSocketAddress(const FdSocketAddress *fd) +{ + g_autoptr(virJSONValue) addr = NULL; + g_autoptr(virJSONValue) data = NULL; + + if (virJSONValueObjectAdd(&addr, + "s:type", "fd", + "s:str", fd->str, + NULL) < 0) + return NULL; + + return g_steal_pointer(&addr); +} + + +static virJSONValue * +qemuBuildTDXQGSCommandLine(virDomainTDXDef *tdx) +{ + g_autoptr(virJSONValue) addr = NULL; + + switch ((virDomainSocketAddress) tdx->qgs_sa.type) { + case VIR_DOMAIN_SOCKET_ADDRESS_INET: + addr = qemuJSONBuildInetSocketAddress(&tdx->qgs_sa.u.inet); + break; + case VIR_DOMAIN_SOCKET_ADDRESS_UNIX: + addr = qemuJSONBuildUnixSocketAddress(&tdx->qgs_sa.u.Unix); + break; + case VIR_DOMAIN_SOCKET_ADDRESS_VSOCK: + addr = qemuJSONBuildVsockSocketAddress(&tdx->qgs_sa.u.vsock); + break; + case VIR_DOMAIN_SOCKET_ADDRESS_FD: + addr = qemuJSONBuildFdSocketAddress(&tdx->qgs_sa.u.fd); + break; + case VIR_DOMAIN_SOCKET_ADDRESS_NONE: + case VIR_DOMAIN_SOCKET_ADDRESS_LAST: + default: + return NULL; + } + + return g_steal_pointer(&addr); +} + + static int qemuBuildTDXCommandLine(virDomainObj *vm, virCommand *cmd, virDomainTDXDef *tdx) { + g_autoptr(virJSONValue) addr = NULL; g_autoptr(virJSONValue) props = NULL; qemuDomainObjPrivate *priv = vm->privateData; bool sept_ve_disable = tdx->policy & VIR_DOMAIN_TDX_POLICY_SEPT_VE_DISABLE; VIR_DEBUG("policy=0x%llx", tdx->policy); + addr = qemuBuildTDXQGSCommandLine(tdx); + if (qemuMonitorCreateObjectProps(&props, "tdx-guest", "lsec0", "B:debug", !!(tdx->policy & VIR_DOMAIN_TDX_POLICY_DEBUG), "S:mrconfigid", tdx->mrconfigid, "S:mrowner", tdx->mrowner, "S:mrownerconfig", tdx->mrownerconfig, + "A:quote-generation-socket", &addr, NULL) < 0) return -1; -- 2.34.1

On Fri, May 24, 2024 at 02:21:23PM +0800, Zhenzhong Duan wrote:
Add element "quoteGenerationService" to tdx launch security type. Currently it contains only one sub-element "SocketAddress".
"SocketAddress" is modelized according to QEMU QAPI, supporting inet, unix, vsock and fd type and variant attributes depending on type.
XML example:
<launchSecurity type='tdx'> <policy>0x0</policy> <mrConfigId>xxx</mrConfigId> <mrOwner>xxx</mrOwner> <mrOwnerConfig>xxx</mrOwnerConfig> <quoteGenerationService> <SocketAddress type='vsock' cid='xxx' port='xxx'/>
Libvirt doesn't usually have initial capitals in any XML elements/attrs. I think everything from <SocketAddress> could be put on the <quoteGenerationService> element directly.
</quoteGenerationService> </launchSecurity>
QEMU command line example: qemu-system-x86_64 \ -object '{"qom-type":"tdx-guest","id":"lsec0","sept-ve-disable":false,"mrconfigid":"xxx","mrowner":"xxx","mrownerconfig":"xxx","quote-generation-socket":{"type":"vsock","cid":"xxx","port":"xxx"}}' \ -machine pc-q35-6.0,confidential-guest-support=lsec0
Signed-off-by: Zhenzhong Duan <zhenzhong.duan@intel.com> --- src/conf/domain_conf.c | 272 +++++++++++++++++++++++++++++- src/conf/domain_conf.h | 61 +++++++ src/conf/schemas/domaincommon.rng | 106 ++++++++++++ src/qemu/qemu_command.c | 106 ++++++++++++ 4 files changed, 544 insertions(+), 1 deletion(-)
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index bb4973fce8..15cdb3e0e6 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -2852,6 +2852,55 @@ struct _virDomainKeyWrapDef { virTristateSwitch dea; };
+typedef enum { + VIR_DOMAIN_SOCKET_ADDRESS_NONE, + VIR_DOMAIN_SOCKET_ADDRESS_INET, + VIR_DOMAIN_SOCKET_ADDRESS_UNIX, + VIR_DOMAIN_SOCKET_ADDRESS_VSOCK, + VIR_DOMAIN_SOCKET_ADDRESS_FD, + + VIR_DOMAIN_SOCKET_ADDRESS_LAST +} virDomainSocketAddress; + +typedef struct _InetSocketAddress InetSocketAddress; +typedef struct _UnixSocketAddress UnixSocketAddress; +typedef struct _VsockSocketAddress VsockSocketAddress; +typedef struct _FdSocketAddress FdSocketAddress; + +struct _InetSocketAddress { + char *host; + char *port; + bool has_numeric; + virTristateBool numeric; + bool has_to; + unsigned int to; + bool has_ipv4; + virTristateBool ipv4; + bool has_ipv6; + virTristateBool ipv6; + bool has_keep_alive; + virTristateBool keep_alive; + bool has_mptcp; + virTristateBool mptcp; +}; + +struct _UnixSocketAddress { + char *path; + bool has_abstract; + virTristateBool abstract; + bool has_tight; + virTristateBool tight; +};
All of these "has_XXX" fields are redundant. Only 'has_to' is ever set, and it is never read after that, so that's a dead store.
+ +struct _VsockSocketAddress { + char *cid; + char *port; +}; + +struct _FdSocketAddress { + char *str; +}; + typedef enum { VIR_DOMAIN_LAUNCH_SECURITY_NONE, VIR_DOMAIN_LAUNCH_SECURITY_SEV, @@ -2873,11 +2922,22 @@ struct _virDomainSEVDef { virTristateBool kernel_hashes; };
+typedef struct SocketAddress { + virDomainSocketAddress type; + union { + InetSocketAddress inet; + UnixSocketAddress Unix; + VsockSocketAddress vsock; + FdSocketAddress fd; + } u; +} SocketAddress; + struct _virDomainTDXDef { unsigned long long policy; char *mrconfigid; char *mrowner; char *mrownerconfig; + SocketAddress qgs_sa; };
#define VIR_DOMAIN_TDX_POLICY_DEBUG 0x1
With 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 :|

-----Original Message----- From: Daniel P. Berrangé <berrange@redhat.com> Subject: Re: [PATCH rfcv4 08/13] Add Intel TDX Quote Generation Service(QGS) support
On Fri, May 24, 2024 at 02:21:23PM +0800, Zhenzhong Duan wrote:
Add element "quoteGenerationService" to tdx launch security type. Currently it contains only one sub-element "SocketAddress".
"SocketAddress" is modelized according to QEMU QAPI, supporting inet, unix, vsock and fd type and variant attributes depending on type.
XML example:
<launchSecurity type='tdx'> <policy>0x0</policy> <mrConfigId>xxx</mrConfigId> <mrOwner>xxx</mrOwner> <mrOwnerConfig>xxx</mrOwnerConfig> <quoteGenerationService> <SocketAddress type='vsock' cid='xxx' port='xxx'/>
Libvirt doesn't usually have initial capitals in any XML elements/attrs. I think everything from <SocketAddress> could be put on the <quoteGenerationService> element directly.
Got it, will do.
</quoteGenerationService> </launchSecurity>
QEMU command line example: qemu-system-x86_64 \ -object '{"qom-type":"tdx-guest","id":"lsec0","sept-ve-
disable":false,"mrconfigid":"xxx","mrowner":"xxx","mrownerconfig":"xxx","q uote-generation-socket":{"type":"vsock","cid":"xxx","port":"xxx"}}' \
-machine pc-q35-6.0,confidential-guest-support=lsec0
Signed-off-by: Zhenzhong Duan <zhenzhong.duan@intel.com> --- src/conf/domain_conf.c | 272
+++++++++++++++++++++++++++++-
src/conf/domain_conf.h | 61 +++++++ src/conf/schemas/domaincommon.rng | 106 ++++++++++++ src/qemu/qemu_command.c | 106 ++++++++++++ 4 files changed, 544 insertions(+), 1 deletion(-)
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index bb4973fce8..15cdb3e0e6 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -2852,6 +2852,55 @@ struct _virDomainKeyWrapDef { virTristateSwitch dea; };
+typedef enum { + VIR_DOMAIN_SOCKET_ADDRESS_NONE, + VIR_DOMAIN_SOCKET_ADDRESS_INET, + VIR_DOMAIN_SOCKET_ADDRESS_UNIX, + VIR_DOMAIN_SOCKET_ADDRESS_VSOCK, + VIR_DOMAIN_SOCKET_ADDRESS_FD, + + VIR_DOMAIN_SOCKET_ADDRESS_LAST +} virDomainSocketAddress; + +typedef struct _InetSocketAddress InetSocketAddress; +typedef struct _UnixSocketAddress UnixSocketAddress; +typedef struct _VsockSocketAddress VsockSocketAddress; +typedef struct _FdSocketAddress FdSocketAddress; + +struct _InetSocketAddress { + char *host; + char *port; + bool has_numeric; + virTristateBool numeric; + bool has_to; + unsigned int to; + bool has_ipv4; + virTristateBool ipv4; + bool has_ipv6; + virTristateBool ipv6; + bool has_keep_alive; + virTristateBool keep_alive; + bool has_mptcp; + virTristateBool mptcp; +}; + +struct _UnixSocketAddress { + char *path; + bool has_abstract; + virTristateBool abstract; + bool has_tight; + virTristateBool tight; +};
All of these "has_XXX" fields are redundant. Only 'has_to' is ever set, and it is never read after that, so that's a dead store.
Good catch, I copied from qemu QAPI but forgot to cleanup. I'll remove them all except 'has_to'. Thanks Zhenzhong

On Fri, May 24, 2024 at 02:21:23PM +0800, Zhenzhong Duan wrote:
Add element "quoteGenerationService" to tdx launch security type. Currently it contains only one sub-element "SocketAddress".
"SocketAddress" is modelized according to QEMU QAPI, supporting inet, unix, vsock and fd type and variant attributes depending on type.
XML example:
<launchSecurity type='tdx'> <policy>0x0</policy> <mrConfigId>xxx</mrConfigId> <mrOwner>xxx</mrOwner> <mrOwnerConfig>xxx</mrOwnerConfig> <quoteGenerationService> <SocketAddress type='vsock' cid='xxx' port='xxx'/> </quoteGenerationService> </launchSecurity>
QEMU command line example: qemu-system-x86_64 \ -object '{"qom-type":"tdx-guest","id":"lsec0","sept-ve-disable":false,"mrconfigid":"xxx","mrowner":"xxx","mrownerconfig":"xxx","quote-generation-socket":{"type":"vsock","cid":"xxx","port":"xxx"}}' \ -machine pc-q35-6.0,confidential-guest-support=lsec0
Signed-off-by: Zhenzhong Duan <zhenzhong.duan@intel.com> --- src/conf/domain_conf.c | 272 +++++++++++++++++++++++++++++- src/conf/domain_conf.h | 61 +++++++ src/conf/schemas/domaincommon.rng | 106 ++++++++++++ src/qemu/qemu_command.c | 106 ++++++++++++ 4 files changed, 544 insertions(+), 1 deletion(-)
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index bb4973fce8..15cdb3e0e6 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -2852,6 +2852,55 @@ struct _virDomainKeyWrapDef { virTristateSwitch dea; };
+typedef enum { + VIR_DOMAIN_SOCKET_ADDRESS_NONE, + VIR_DOMAIN_SOCKET_ADDRESS_INET, + VIR_DOMAIN_SOCKET_ADDRESS_UNIX, + VIR_DOMAIN_SOCKET_ADDRESS_VSOCK, + VIR_DOMAIN_SOCKET_ADDRESS_FD, + + VIR_DOMAIN_SOCKET_ADDRESS_LAST +} virDomainSocketAddress; + +typedef struct _InetSocketAddress InetSocketAddress; +typedef struct _UnixSocketAddress UnixSocketAddress; +typedef struct _VsockSocketAddress VsockSocketAddress; +typedef struct _FdSocketAddress FdSocketAddress; + +struct _InetSocketAddress { + char *host; + char *port; + bool has_numeric; + virTristateBool numeric; + bool has_to; + unsigned int to; + bool has_ipv4; + virTristateBool ipv4; + bool has_ipv6; + virTristateBool ipv6; + bool has_keep_alive; + virTristateBool keep_alive; + bool has_mptcp; + virTristateBool mptcp; +}; + +struct _UnixSocketAddress { + char *path; + bool has_abstract; + virTristateBool abstract; + bool has_tight; + virTristateBool tight; +}; + +struct _VsockSocketAddress { + char *cid; + char *port; +}; + +struct _FdSocketAddress { + char *str; +}; + typedef enum { VIR_DOMAIN_LAUNCH_SECURITY_NONE, VIR_DOMAIN_LAUNCH_SECURITY_SEV, @@ -2873,11 +2922,22 @@ struct _virDomainSEVDef { virTristateBool kernel_hashes; };
+typedef struct SocketAddress { + virDomainSocketAddress type; + union { + InetSocketAddress inet; + UnixSocketAddress Unix; + VsockSocketAddress vsock; + FdSocketAddress fd;
The 'fd' socket type does not make sense to expose in libvirt XML. FD passing is something handled privately between libvirt & QEMU, not a end user choice. Going further I don't think InetSocketAddress makes sense to expose, as QGS has no ability to listen on IP sockets. It can only do UNIX sockets or VSock AFAICT. Even vsock looks like a remnant of the old way of doing attestation before it was integrated into Linux via sysfs with the kernel making a call into QEMU. IOW, AFAICT, for QGS all we actually need is the ability to set a UNIX socket path in libvirt. eg <quoteGenerationService path="/var/run/tdx-qgs/qgs.socket"/> and probably libvirt should allow 'path' to be optional so an app can just do <quoteGenerationService/> and libvirt would fill in the default path which QGS listens on out of the box.... With 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 :|

-----Original Message----- From: Daniel P. Berrangé <berrange@redhat.com> Subject: Re: [PATCH rfcv4 08/13] Add Intel TDX Quote Generation Service(QGS) support
On Fri, May 24, 2024 at 02:21:23PM +0800, Zhenzhong Duan wrote:
Add element "quoteGenerationService" to tdx launch security type. Currently it contains only one sub-element "SocketAddress".
"SocketAddress" is modelized according to QEMU QAPI, supporting inet, unix, vsock and fd type and variant attributes depending on type.
XML example:
<launchSecurity type='tdx'> <policy>0x0</policy> <mrConfigId>xxx</mrConfigId> <mrOwner>xxx</mrOwner> <mrOwnerConfig>xxx</mrOwnerConfig> <quoteGenerationService> <SocketAddress type='vsock' cid='xxx' port='xxx'/> </quoteGenerationService> </launchSecurity>
QEMU command line example: qemu-system-x86_64 \ -object '{"qom-type":"tdx-guest","id":"lsec0","sept-ve- disable":false,"mrconfigid":"xxx","mrowner":"xxx","mrownerconfig":"xxx","quot e-generation-socket":{"type":"vsock","cid":"xxx","port":"xxx"}}' \ -machine pc-q35-6.0,confidential-guest-support=lsec0
Signed-off-by: Zhenzhong Duan <zhenzhong.duan@intel.com> --- src/conf/domain_conf.c | 272 +++++++++++++++++++++++++++++- src/conf/domain_conf.h | 61 +++++++ src/conf/schemas/domaincommon.rng | 106 ++++++++++++ src/qemu/qemu_command.c | 106 ++++++++++++ 4 files changed, 544 insertions(+), 1 deletion(-)
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index bb4973fce8..15cdb3e0e6 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -2852,6 +2852,55 @@ struct _virDomainKeyWrapDef { virTristateSwitch dea; };
+typedef enum { + VIR_DOMAIN_SOCKET_ADDRESS_NONE, + VIR_DOMAIN_SOCKET_ADDRESS_INET, + VIR_DOMAIN_SOCKET_ADDRESS_UNIX, + VIR_DOMAIN_SOCKET_ADDRESS_VSOCK, + VIR_DOMAIN_SOCKET_ADDRESS_FD, + + VIR_DOMAIN_SOCKET_ADDRESS_LAST +} virDomainSocketAddress; + +typedef struct _InetSocketAddress InetSocketAddress; +typedef struct _UnixSocketAddress UnixSocketAddress; +typedef struct _VsockSocketAddress VsockSocketAddress; +typedef struct _FdSocketAddress FdSocketAddress; + +struct _InetSocketAddress { + char *host; + char *port; + bool has_numeric; + virTristateBool numeric; + bool has_to; + unsigned int to; + bool has_ipv4; + virTristateBool ipv4; + bool has_ipv6; + virTristateBool ipv6; + bool has_keep_alive; + virTristateBool keep_alive; + bool has_mptcp; + virTristateBool mptcp; +}; + +struct _UnixSocketAddress { + char *path; + bool has_abstract; + virTristateBool abstract; + bool has_tight; + virTristateBool tight; +}; + +struct _VsockSocketAddress { + char *cid; + char *port; +}; + +struct _FdSocketAddress { + char *str; +}; + typedef enum { VIR_DOMAIN_LAUNCH_SECURITY_NONE, VIR_DOMAIN_LAUNCH_SECURITY_SEV, @@ -2873,11 +2922,22 @@ struct _virDomainSEVDef { virTristateBool kernel_hashes; };
+typedef struct SocketAddress { + virDomainSocketAddress type; + union { + InetSocketAddress inet; + UnixSocketAddress Unix; + VsockSocketAddress vsock; + FdSocketAddress fd;
The 'fd' socket type does not make sense to expose in libvirt XML. FD passing is something handled privately between libvirt & QEMU, not a end user choice.
Yes, I can remove ' FdSocketAddress fd'.
Going further I don't think InetSocketAddress makes sense to expose, as QGS has no ability to listen on IP sockets. It can only do UNIX sockets or VSock AFAICT.
Why can't qemu connect to QGS on a remote host? Even if connect to QGS on localhost, 127.0.0.1 can be used.
Even vsock looks like a remnant of the old way of doing attestation before it was integrated into Linux via sysfs with the kernel making a call into QEMU.
Not get, qemu does support vsock, see https://lore.kernel.org/qemu-devel/20240229063726.610065-50-xiaoyao.li@intel...
IOW, AFAICT, for QGS all we actually need is the ability to set a UNIX socket path in libvirt. eg
<quoteGenerationService path="/var/run/tdx-qgs/qgs.socket"/>
Hmm, then we go back to opaque string, do you change your mind? See https://lists.libvirt.org/archives/list/devel@lists.libvirt.org/message/XCE4...
and probably libvirt should allow 'path' to be optional so an app can just do
<quoteGenerationService/>
and libvirt would fill in the default path which QGS listens on out of the box....
Yes if we have such default QGS path, do we? Thanks Zhenzhong

On Wed, Mar 26, 2025 at 03:29:04AM +0000, Duan, Zhenzhong wrote:
-----Original Message----- From: Daniel P. Berrangé <berrange@redhat.com> Subject: Re: [PATCH rfcv4 08/13] Add Intel TDX Quote Generation Service(QGS) support
On Fri, May 24, 2024 at 02:21:23PM +0800, Zhenzhong Duan wrote:
Add element "quoteGenerationService" to tdx launch security type. Currently it contains only one sub-element "SocketAddress".
"SocketAddress" is modelized according to QEMU QAPI, supporting inet, unix, vsock and fd type and variant attributes depending on type.
The 'fd' socket type does not make sense to expose in libvirt XML. FD passing is something handled privately between libvirt & QEMU, not a end user choice.
Yes, I can remove ' FdSocketAddress fd'.
Going further I don't think InetSocketAddress makes sense to expose, as QGS has no ability to listen on IP sockets. It can only do UNIX sockets or VSock AFAICT.
Why can't qemu connect to QGS on a remote hoste?
QGS has no IP support, and the work that QGS performs to create a signed attestation report has to be done on the same host that the VM runs on.
Even if connect to QGS on localhost, 127.0.0.1 can be used.
Again QGS has no IP support, and 127.0.0.1 offers no benefits over UNIX sockets, while having worse security.
Even vsock looks like a remnant of the old way of doing attestation before it was integrated into Linux via sysfs with the kernel making a call into QEMU.
Not get, qemu does support vsock, see https://lore.kernel.org/qemu-devel/20240229063726.610065-50-xiaoyao.li@intel...
That's simply an artifact of the QEMU patches using QEMU's generic socket APIs. The QGS vsock support dates from the earlier days of TDX development, where the guest VM would be directly connecting to QGS. With QEMU & the kernel mediating access to QGS, enabling VSOCK is not required. VSOCK decreases security of the host - it allows any running guest (whether confidential or not) to directly attack QGS via any of its protocol messages. With QEMU mediating QGS access, the malicious guest would need to compromise the kernel, and QEMU before it can access QGS. I'm not seeing a compelling functional reason to enable QEMU to connect to QGS over VSOCK in libvirt, when UNIX sockets offer the required functionality with greater security.
IOW, AFAICT, for QGS all we actually need is the ability to set a UNIX socket path in libvirt. eg
<quoteGenerationService path="/var/run/tdx-qgs/qgs.socket"/>
Hmm, then we go back to opaque string, do you change your mind? See https://lists.libvirt.org/archives/list/devel@lists.libvirt.org/message/XCE4...
The original patch was an opaque string, because it was encoding various different socket address types in one string. What I'm proposing is different. Do NOT support different socket address types initially, only support UNIX sockets, and the only attribute is thus the bare UNIX socket path. If we start with only supporting: <quoteGenerationService path="/var/run/tdx-qgs/qgs.socket"/> then in the unlikely even we need more socket types we can extend this, by adding a "type" attribute defaulting to "unix" if omitted, so we can then allow a choice <quoteGenerationService type="unix" path="/var/run/tdx-qgs/qgs.socket"/> or <quoteGenerationService type="vsock" cid="...." port="..."/> but hopefully we'll never need this, as UNIX sockets should suffice.
and probably libvirt should allow 'path' to be optional so an app can just do
<quoteGenerationService/>
and libvirt would fill in the default path which QGS listens on out of the box....
Yes if we have such default QGS path, do we?
Yes, it is hardcoded in QGS source code: $ git grep '#define QGS_UNIX_SOCKET_FILE' server_main.cpp:#define QGS_UNIX_SOCKET_FILE "/var/run/tdx-qgs/qgs.socket" With 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 :|

-----Original Message----- From: Daniel P. Berrangé <berrange@redhat.com> Subject: Re: [PATCH rfcv4 08/13] Add Intel TDX Quote Generation Service(QGS) support
On Wed, Mar 26, 2025 at 03:29:04AM +0000, Duan, Zhenzhong wrote:
-----Original Message----- From: Daniel P. Berrangé <berrange@redhat.com> Subject: Re: [PATCH rfcv4 08/13] Add Intel TDX Quote Generation Service(QGS) support
On Fri, May 24, 2024 at 02:21:23PM +0800, Zhenzhong Duan wrote:
Add element "quoteGenerationService" to tdx launch security type. Currently it contains only one sub-element "SocketAddress".
"SocketAddress" is modelized according to QEMU QAPI, supporting inet, unix, vsock and fd type and variant attributes depending on type.
The 'fd' socket type does not make sense to expose in libvirt XML. FD passing is something handled privately between libvirt & QEMU, not a end user choice.
Yes, I can remove ' FdSocketAddress fd'.
Going further I don't think InetSocketAddress makes sense to expose, as QGS has no ability to listen on IP sockets. It can only do UNIX sockets or VSock AFAICT.
Why can't qemu connect to QGS on a remote hoste?
QGS has no IP support, and the work that QGS performs to create a signed attestation report has to be done on the same host that the VM runs on.
Even if connect to QGS on localhost, 127.0.0.1 can be used.
Again QGS has no IP support, and 127.0.0.1 offers no benefits over UNIX sockets, while having worse security.
Clear.
Even vsock looks like a remnant of the old way of doing attestation before it was integrated into Linux via sysfs with the kernel making a call into QEMU.
Not get, qemu does support vsock, see https://lore.kernel.org/qemu- devel/20240229063726.610065-50-xiaoyao.li@intel.com/
That's simply an artifact of the QEMU patches using QEMU's generic socket APIs. The QGS vsock support dates from the earlier days of TDX development, where the guest VM would be directly connecting to QGS. With QEMU & the kernel mediating access to QGS, enabling VSOCK is not required. VSOCK decreases security of the host - it allows any running guest (whether confidential or not) to directly attack QGS via any of its protocol messages. With QEMU mediating QGS access, the malicious guest would need to compromise the kernel, and QEMU before it can access QGS.
Understood.
I'm not seeing a compelling functional reason to enable QEMU to connect to QGS over VSOCK in libvirt, when UNIX sockets offer the required functionality with greater
OK.
security.
IOW, AFAICT, for QGS all we actually need is the ability to set a UNIX socket path in libvirt. eg
<quoteGenerationService path="/var/run/tdx-qgs/qgs.socket"/>
Hmm, then we go back to opaque string, do you change your mind? See https://lists.libvirt.org/archives/list/devel@lists.libvirt.org/message/XCE4... P7IVZCFPB6RDWLEWXXT2G/
The original patch was an opaque string, because it was encoding various different socket address types in one string.
What I'm proposing is different. Do NOT support different socket address types initially, only support UNIX sockets, and the only attribute is thus the bare UNIX socket path.
If we start with only supporting:
<quoteGenerationService path="/var/run/tdx-qgs/qgs.socket"/>
then in the unlikely even we need more socket types we can extend this, by adding a "type" attribute defaulting to "unix" if omitted, so we can then allow a choice
<quoteGenerationService type="unix" path="/var/run/tdx-qgs/qgs.socket"/>
or
<quoteGenerationService type="vsock" cid="...." port="..."/>
but hopefully we'll never need this, as UNIX sockets should suffice.
Sounds good, will do this way.
and probably libvirt should allow 'path' to be optional so an app can just do
<quoteGenerationService/>
and libvirt would fill in the default path which QGS listens on out of the box....
Yes if we have such default QGS path, do we?
Yes, it is hardcoded in QGS source code:
$ git grep '#define QGS_UNIX_SOCKET_FILE' server_main.cpp:#define QGS_UNIX_SOCKET_FILE "/var/run/tdx-qgs/qgs.socket"
OK, will do. Thanks Zhenzhong

Utilize the existing fake reboot mechanism to do reboot for TDX guest. Different from normal guest, TDX guest doesn't support system_reset, so have to kill the old guest and start a new one to simulate the reboot. Co-developed-by: Chenyi Qiang <chenyi.qiang@intel.com> Signed-off-by: Zhenzhong Duan <zhenzhong.duan@intel.com> --- src/qemu/qemu_process.c | 74 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index bd8624e3f6..35758d882f 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -441,6 +441,75 @@ qemuProcessHandleReset(qemuMonitor *mon G_GNUC_UNUSED, } +static void +qemuProcessSecFakeReboot(void *opaque) +{ + virDomainObj *vm = opaque; + qemuDomainObjPrivate *priv = vm->privateData; + virQEMUDriver *driver = priv->driver; + unsigned int stopFlags = 0; + virObjectEvent *event = NULL; + virObjectEvent * event2 = NULL; + + VIR_DEBUG("Handle secure guest reboot: destroy phase"); + + virObjectLock(vm); + if (qemuProcessBeginStopJob(vm, VIR_JOB_DESTROY, 0) < 0) + goto cleanup; + + if (virDomainObjCheckActive(vm) < 0) { + virDomainObjEndJob(vm); + goto cleanup; + } + + if (vm->job->asyncJob == VIR_ASYNC_JOB_MIGRATION_IN) + stopFlags |= VIR_QEMU_PROCESS_STOP_MIGRATED; + + qemuProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_DESTROYED, + VIR_ASYNC_JOB_NONE, stopFlags); + virDomainAuditStop(vm, "destroyed"); + + event = virDomainEventLifecycleNewFromObj(vm, + VIR_DOMAIN_EVENT_STOPPED, + VIR_DOMAIN_EVENT_STOPPED_DESTROYED); + + virObjectEventStateQueue(driver->domainEventState, event); + /* skip remove inactive domain from active list */ + virDomainObjEndJob(vm); + + VIR_DEBUG("Handle secure guest reboot: boot phase"); + + if (qemuProcessBeginJob(vm, VIR_DOMAIN_JOB_OPERATION_START, 0) < 0) { + qemuDomainRemoveInactive(driver, vm, 0, false); + goto cleanup; + } + + if (qemuProcessStart(NULL, driver, vm, NULL, VIR_ASYNC_JOB_START, + NULL, -1, NULL, NULL, + VIR_NETDEV_VPORT_PROFILE_OP_CREATE, + 0) < 0) { + virDomainAuditStart(vm, "booted", false); + qemuDomainRemoveInactive(driver, vm, 0, false); + goto endjob; + } + + virDomainAuditStart(vm, "booted", true); + event2 = virDomainEventLifecycleNewFromObj(vm, + VIR_DOMAIN_EVENT_STARTED, + VIR_DOMAIN_EVENT_STARTED_BOOTED); + virObjectEventStateQueue(driver->domainEventState, event2); + + qemuDomainSaveStatus(vm); + + endjob: + qemuProcessEndJob(vm); + + cleanup: + qemuDomainSetFakeReboot(vm, false); + virDomainObjEndAPI(&vm); +} + + /* * Since we have the '-no-shutdown' flag set, the * QEMU process will currently have guest OS shutdown @@ -459,6 +528,11 @@ qemuProcessFakeReboot(void *opaque) int ret = -1, rc; VIR_DEBUG("vm=%p", vm); + + if (vm->def->sec && + vm->def->sec->sectype == VIR_DOMAIN_LAUNCH_SECURITY_TDX) + return qemuProcessSecFakeReboot(opaque); + virObjectLock(vm); if (virDomainObjBeginJob(vm, VIR_JOB_MODIFY) < 0) goto cleanup; -- 2.34.1

On Fri, May 24, 2024 at 02:21:24PM +0800, Zhenzhong Duan wrote:
Utilize the existing fake reboot mechanism to do reboot for TDX guest.
Different from normal guest, TDX guest doesn't support system_reset, so have to kill the old guest and start a new one to simulate the reboot.
Co-developed-by: Chenyi Qiang <chenyi.qiang@intel.com> Signed-off-by: Zhenzhong Duan <zhenzhong.duan@intel.com> --- src/qemu/qemu_process.c | 74 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+)
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index bd8624e3f6..35758d882f 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -441,6 +441,75 @@ qemuProcessHandleReset(qemuMonitor *mon G_GNUC_UNUSED, }
+static void +qemuProcessSecFakeReboot(void *opaque) +{
snip
+} + + /* * Since we have the '-no-shutdown' flag set, the * QEMU process will currently have guest OS shutdown @@ -459,6 +528,11 @@ qemuProcessFakeReboot(void *opaque) int ret = -1, rc;
VIR_DEBUG("vm=%p", vm); + + if (vm->def->sec && + vm->def->sec->sectype == VIR_DOMAIN_LAUNCH_SECURITY_TDX) + return qemuProcessSecFakeReboot(opaque); + virObjectLock(vm); if (virDomainObjBeginJob(vm, VIR_JOB_MODIFY) < 0) goto cleanup;
So the 'qemuProcessFakeReboot' currently fakes reboot via a machine CPU reset. This new code fakes reboot via QEMU re-creation. I'd suggest that the current method gets renamed to qemuProcessFakeRebootViaReset(), then your new qemuProcessSecFakeReboot() gets renamed to qemuProcessFakeRebootViaRecreate(). Then create a qemuProcessFakeReboot, that calls into either qemuProcessFakeRebootViaReset or qemuProcessFakeRebootViaRecreate as appropriate. With 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 :|

Hello Zhenzhong and Daniel, With this implementation, upon TD reboot, some events VIR_DOMAIN_EVENT_ID_LIFECYCLE are emitted (STARTED, STOPPED and probably SHUTDOWN and RESUMED). For normal VM, only the event VIR_DOMAIN_EVENT_ID_REBOOT is emitted. Do you think it is good to align the API for TD VM and normal VM ? So the reboot of a TD VM will be transparent to existing control plane software ? I would like to ask because we have a complaint about control plane software being broken because it only expects to receive the event VIR_DOMAIN_EVENT_ID_REBOOT. Best regards

On Mon, Oct 21, 2024 at 12:34:23PM -0000, hector.cao@canonical.com wrote:
Hello Zhenzhong and Daniel,
With this implementation, upon TD reboot, some events VIR_DOMAIN_EVENT_ID_LIFECYCLE are emitted (STARTED, STOPPED and probably SHUTDOWN and RESUMED).
For normal VM, only the event VIR_DOMAIN_EVENT_ID_REBOOT is emitted.
Do you think it is good to align the API for TD VM and normal VM ? So the reboot of a TD VM will be transparent to existing control plane software ?
I would like to ask because we have a complaint about control plane software being broken because it only expects to receive the event VIR_DOMAIN_EVENT_ID_REBOOT.
I think the difference in events, while annoying, is the right thing to have, becasue the fact that QEMU is shutoff & re-spawned can have implications for integration into the system & thus should be reflected. To make it slightly nicer though, we should make sure that the lifecycle event "reason" detail, reports "REBOOTED" as the cause. That would let control plane software understand that these events are from a fake reboot. With 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 :|

By "REBOOTED", do you mean VIR_DOMAIN_EVENT_STARTED_REBOOTED ? If yes, do you suggest adding this detail/reason to each lifecycle event caused by a reboot ? Then, we will also have : - VIR_DOMAIN_EVENT_SHUTDOWN_REBOOTED - VIR_DOMAIN_EVENT_STOPPED_REBOOTED - VIR_DOMAIN_EVENT_RESUMED_REBOOTED Best regards, On Mon, Oct 21, 2024 at 2:40 PM Daniel P. Berrangé <berrange@redhat.com> wrote:
Hello Zhenzhong and Daniel,
With this implementation, upon TD reboot, some events VIR_DOMAIN_EVENT_ID_LIFECYCLE are emitted (STARTED, STOPPED and probably SHUTDOWN and RESUMED).
For normal VM, only the event VIR_DOMAIN_EVENT_ID_REBOOT is emitted.
Do you think it is good to align the API for TD VM and normal VM ? So
On Mon, Oct 21, 2024 at 12:34:23PM -0000, hector.cao@canonical.com wrote: the reboot of a TD VM will be transparent to existing control plane software ?
I would like to ask because we have a complaint about control plane
software being broken because it only expects to receive the event VIR_DOMAIN_EVENT_ID_REBOOT.
I think the difference in events, while annoying, is the right thing to have, becasue the fact that QEMU is shutoff & re-spawned can have implications for integration into the system & thus should be reflected.
To make it slightly nicer though, we should make sure that the lifecycle event "reason" detail, reports "REBOOTED" as the cause. That would let control plane software understand that these events are from a fake reboot.
With 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 :|
-- Hector CAO Software Engineer – Partner Engineering Team hector.cao@canonical.com https://launc <https://launchpad.net/~hectorcao>hpad.net/~hectorcao <https://launchpad.net/~hectorcao> <https://launchpad.net/~hectorcao>

On Mon, Oct 21, 2024 at 03:14:13PM +0200, Hector Cao wrote:
By "REBOOTED", do you mean VIR_DOMAIN_EVENT_STARTED_REBOOTED ?
If yes, do you suggest adding this detail/reason to each lifecycle event caused by a reboot ?
Then, we will also have : - VIR_DOMAIN_EVENT_SHUTDOWN_REBOOTED - VIR_DOMAIN_EVENT_STOPPED_REBOOTED - VIR_DOMAIN_EVENT_RESUMED_REBOOTED
Yeah, that's what I meant. With 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 :|

We can reboot a TDX guest with 'virsh reboot' or 'virsh shutdown' if action for onPoweroff is 'restart'. But running reboot command in guest shell will always lead to shutdown. This behavior is not consistent with normal guest, fix it by checking shutdown reason and action configuration to trigger FakeReboot. Signed-off-by: Zhenzhong Duan <zhenzhong.duan@intel.com> --- src/qemu/qemu_monitor.c | 18 +++++++++++++++++- src/qemu/qemu_monitor.h | 2 +- src/qemu/qemu_monitor_json.c | 6 +++++- 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index 34e2ccab97..7f7053054f 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -1062,10 +1062,26 @@ qemuMonitorEmitEvent(qemuMonitor *mon, const char *event, void -qemuMonitorEmitShutdown(qemuMonitor *mon, virTristateBool guest) +qemuMonitorEmitShutdown(qemuMonitor *mon, virTristateBool guest, + const char *reason) { + virDomainObj *vm = mon->vm; + VIR_DEBUG("mon=%p guest=%u", mon, guest); + /* This isn't best place to set FakeReboot but we need to access + * mon->vm which is defined in this file. Reboot command in guest + * will trigger SHUTDOWN event for TDX guest, so we has to deal + * with it here. */ + if (vm->def->sec && + vm->def->sec->sectype == VIR_DOMAIN_LAUNCH_SECURITY_TDX) { + if ((STREQ_NULLABLE(reason, "guest-shutdown") && + vm->def->onPoweroff == VIR_DOMAIN_LIFECYCLE_ACTION_RESTART) || + (STREQ_NULLABLE(reason, "guest-reset") && + vm->def->onReboot == VIR_DOMAIN_LIFECYCLE_ACTION_RESTART)) + qemuDomainSetFakeReboot(vm, true); + } + QEMU_MONITOR_CALLBACK(mon, domainShutdown, mon->vm, guest); } diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index 6e81945201..226bd672ea 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -443,7 +443,7 @@ int qemuMonitorUpdateVideoVram64Size(qemuMonitor *mon, void qemuMonitorEmitEvent(qemuMonitor *mon, const char *event, long long seconds, unsigned int micros, const char *details); -void qemuMonitorEmitShutdown(qemuMonitor *mon, virTristateBool guest); +void qemuMonitorEmitShutdown(qemuMonitor *mon, virTristateBool guest, const char *reason); void qemuMonitorEmitReset(qemuMonitor *mon); void qemuMonitorEmitStop(qemuMonitor *mon); void qemuMonitorEmitResume(qemuMonitor *mon); diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index eb84a3d938..bcddabffa0 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -546,12 +546,16 @@ qemuMonitorJSONMakeCommand(const char *cmdname, static void qemuMonitorJSONHandleShutdown(qemuMonitor *mon, virJSONValue *data) { bool guest = false; + const char *reason = NULL; virTristateBool guest_initiated = VIR_TRISTATE_BOOL_ABSENT; if (data && virJSONValueObjectGetBoolean(data, "guest", &guest) == 0) guest_initiated = virTristateBoolFromBool(guest); - qemuMonitorEmitShutdown(mon, guest_initiated); + if (data) + reason = virJSONValueObjectGetString(data, "reason"); + + qemuMonitorEmitShutdown(mon, guest_initiated, reason); } static void qemuMonitorJSONHandleReset(qemuMonitor *mon, virJSONValue *data G_GNUC_UNUSED) -- 2.34.1

On Fri, May 24, 2024 at 02:21:25PM +0800, Zhenzhong Duan wrote:
We can reboot a TDX guest with 'virsh reboot' or 'virsh shutdown' if action for onPoweroff is 'restart'. But running reboot command in guest shell will always lead to shutdown.
This behavior is not consistent with normal guest, fix it by checking shutdown reason and action configuration to trigger FakeReboot.
Signed-off-by: Zhenzhong Duan <zhenzhong.duan@intel.com> --- src/qemu/qemu_monitor.c | 18 +++++++++++++++++- src/qemu/qemu_monitor.h | 2 +- src/qemu/qemu_monitor_json.c | 6 +++++- 3 files changed, 23 insertions(+), 3 deletions(-)
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> With 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 :|

For secure guest, FakeReboot kills original QEMU instance and create new one. During this process, QEMU send SHUTDOWN event with "host-signal" reason which can trigger another FakeReboot. Check if a FakeReboot is ongoing and bypass "host-signal" processing which is originally come from FakeReboot. Signed-off-by: Zhenzhong Duan <zhenzhong.duan@intel.com> --- src/qemu/qemu_monitor.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index 7f7053054f..3aadd89aec 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -1075,6 +1075,16 @@ qemuMonitorEmitShutdown(qemuMonitor *mon, virTristateBool guest, * with it here. */ if (vm->def->sec && vm->def->sec->sectype == VIR_DOMAIN_LAUNCH_SECURITY_TDX) { + qemuDomainObjPrivate *priv = vm->privateData; + + /* For secure guest, FakeReboot kills original QEMU instance and + * create new one. During this process, QEMU send SHUTDOWN event + * with "host-signal" reason which can trigger another FakeReboot. + * Check if a FakeReboot is ongoing and bypass "host-signal" + * processing which is originally come from FakeReboot. */ + if (priv->fakeReboot && STREQ_NULLABLE(reason, "host-signal")) + return; + if ((STREQ_NULLABLE(reason, "guest-shutdown") && vm->def->onPoweroff == VIR_DOMAIN_LIFECYCLE_ACTION_RESTART) || (STREQ_NULLABLE(reason, "guest-reset") && -- 2.34.1

On Fri, May 24, 2024 at 02:21:26PM +0800, Zhenzhong Duan wrote:
For secure guest, FakeReboot kills original QEMU instance and create new one. During this process, QEMU send SHUTDOWN event with "host-signal" reason which can trigger another FakeReboot.
Check if a FakeReboot is ongoing and bypass "host-signal" processing which is originally come from FakeReboot.
Signed-off-by: Zhenzhong Duan <zhenzhong.duan@intel.com> --- src/qemu/qemu_monitor.c | 10 ++++++++++ 1 file changed, 10 insertions(+)
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> With 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 :|

Currently support 'def parse', 'def -> XML' and 'OUT -> XML'. Test data for qemucapabilitiestest, domaincapstest and qemuxml2argvtest aren't added yet because that depends on TDX is accepted on QEMU side to generate those data. Signed-off-by: Zhenzhong Duan <zhenzhong.duan@intel.com> --- ...unch-security-tdx-qgs-fd.x86_64-latest.xml | 77 +++++++++++++++++++ .../launch-security-tdx-qgs-fd.xml | 30 ++++++++ ...ch-security-tdx-qgs-inet.x86_64-latest.xml | 77 +++++++++++++++++++ .../launch-security-tdx-qgs-inet.xml | 30 ++++++++ ...ch-security-tdx-qgs-unix.x86_64-latest.xml | 77 +++++++++++++++++++ .../launch-security-tdx-qgs-unix.xml | 30 ++++++++ ...h-security-tdx-qgs-vsock.x86_64-latest.xml | 77 +++++++++++++++++++ .../launch-security-tdx-qgs-vsock.xml | 30 ++++++++ tests/qemuxmlconftest.c | 24 ++++++ 9 files changed, 452 insertions(+) create mode 100644 tests/qemuxmlconfdata/launch-security-tdx-qgs-fd.x86_64-latest.xml create mode 100644 tests/qemuxmlconfdata/launch-security-tdx-qgs-fd.xml create mode 100644 tests/qemuxmlconfdata/launch-security-tdx-qgs-inet.x86_64-latest.xml create mode 100644 tests/qemuxmlconfdata/launch-security-tdx-qgs-inet.xml create mode 100644 tests/qemuxmlconfdata/launch-security-tdx-qgs-unix.x86_64-latest.xml create mode 100644 tests/qemuxmlconfdata/launch-security-tdx-qgs-unix.xml create mode 100644 tests/qemuxmlconfdata/launch-security-tdx-qgs-vsock.x86_64-latest.xml create mode 100644 tests/qemuxmlconfdata/launch-security-tdx-qgs-vsock.xml diff --git a/tests/qemuxmlconfdata/launch-security-tdx-qgs-fd.x86_64-latest.xml b/tests/qemuxmlconfdata/launch-security-tdx-qgs-fd.x86_64-latest.xml new file mode 100644 index 0000000000..952615082e --- /dev/null +++ b/tests/qemuxmlconfdata/launch-security-tdx-qgs-fd.x86_64-latest.xml @@ -0,0 +1,77 @@ +<domain type='qemu'> + <name>guest</name> + <uuid>1ccfd97d-5eb4-478a-bbe6-88d254c16db7</uuid> + <memory unit='KiB'>4194304</memory> + <currentMemory unit='KiB'>4194304</currentMemory> + <vcpu placement='static'>4</vcpu> + <os> + <type arch='x86_64' machine='q35'>hvm</type> + <boot dev='hd'/> + </os> + <cpu mode='custom' match='exact' check='none'> + <model fallback='forbid'>qemu64</model> + </cpu> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu-system-x86_64</emulator> + <controller type='usb' index='0' model='piix3-uhci'> + <address type='pci' domain='0x0000' bus='0x02' slot='0x02' function='0x0'/> + </controller> + <controller type='scsi' index='0' model='lsilogic'> + <address type='pci' domain='0x0000' bus='0x02' slot='0x03' function='0x0'/> + </controller> + <controller type='sata' index='0'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x1f' function='0x2'/> + </controller> + <controller type='pci' index='0' model='pcie-root'/> + <controller type='pci' index='1' model='pcie-root-port'> + <model name='pcie-root-port'/> + <target chassis='1' port='0x10'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0' multifunction='on'/> + </controller> + <controller type='pci' index='2' model='pcie-to-pci-bridge'> + <model name='pcie-pci-bridge'/> + <address type='pci' domain='0x0000' bus='0x01' slot='0x00' function='0x0'/> + </controller> + <controller type='pci' index='3' model='pcie-root-port'> + <model name='pcie-root-port'/> + <target chassis='3' port='0x11'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x1'/> + </controller> + <interface type='user'> + <mac address='52:54:00:09:a4:37'/> + <model type='rtl8139'/> + <address type='pci' domain='0x0000' bus='0x02' slot='0x01' function='0x0'/> + </interface> + <serial type='pty'> + <target type='isa-serial' port='0'> + <model name='isa-serial'/> + </target> + </serial> + <console type='pty'> + <target type='serial' port='0'/> + </console> + <input type='mouse' bus='ps2'/> + <input type='keyboard' bus='ps2'/> + <audio id='1' type='none'/> + <video> + <model type='cirrus' vram='16384' heads='1' primary='yes'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0'/> + </video> + <watchdog model='itco' action='reset'/> + <memballoon model='none'/> + <panic model='isa'/> + </devices> + <launchSecurity type='tdx'> + <policy>0x1</policy> + <mrConfigId>xxx</mrConfigId> + <mrOwner>xxx</mrOwner> + <mrOwnerConfig>xxx</mrOwnerConfig> + <quoteGenerationService> + <SocketAddress type='fd' str='xxx'/> + </quoteGenerationService> + </launchSecurity> +</domain> diff --git a/tests/qemuxmlconfdata/launch-security-tdx-qgs-fd.xml b/tests/qemuxmlconfdata/launch-security-tdx-qgs-fd.xml new file mode 100644 index 0000000000..60e3e5b8a7 --- /dev/null +++ b/tests/qemuxmlconfdata/launch-security-tdx-qgs-fd.xml @@ -0,0 +1,30 @@ +<domain type='qemu'> + <name>guest</name> + <uuid>1ccfd97d-5eb4-478a-bbe6-88d254c16db7</uuid> + <memory>4194304</memory> + <vcpu>4</vcpu> + <os> + <type arch='x86_64' machine='q35'>hvm</type> + </os> + <devices> + <emulator>/usr/bin/qemu-system-x86_64</emulator> + <controller type='usb'/> + <controller type='scsi'/> + <interface type='user'> + <mac address='52:54:00:09:a4:37'/> + </interface> + <serial type='pty'/> + <video/> + <memballoon model='none'/> + <panic/> + </devices> + <launchSecurity type='tdx'> + <policy>0x1</policy> + <mrConfigId>xxx</mrConfigId> + <mrOwner>xxx</mrOwner> + <mrOwnerConfig>xxx</mrOwnerConfig> + <quoteGenerationService> + <SocketAddress type='fd' str='xxx'/> + </quoteGenerationService> + </launchSecurity> +</domain> diff --git a/tests/qemuxmlconfdata/launch-security-tdx-qgs-inet.x86_64-latest.xml b/tests/qemuxmlconfdata/launch-security-tdx-qgs-inet.x86_64-latest.xml new file mode 100644 index 0000000000..860b47f306 --- /dev/null +++ b/tests/qemuxmlconfdata/launch-security-tdx-qgs-inet.x86_64-latest.xml @@ -0,0 +1,77 @@ +<domain type='qemu'> + <name>guest</name> + <uuid>1ccfd97d-5eb4-478a-bbe6-88d254c16db7</uuid> + <memory unit='KiB'>4194304</memory> + <currentMemory unit='KiB'>4194304</currentMemory> + <vcpu placement='static'>4</vcpu> + <os> + <type arch='x86_64' machine='q35'>hvm</type> + <boot dev='hd'/> + </os> + <cpu mode='custom' match='exact' check='none'> + <model fallback='forbid'>qemu64</model> + </cpu> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu-system-x86_64</emulator> + <controller type='usb' index='0' model='piix3-uhci'> + <address type='pci' domain='0x0000' bus='0x02' slot='0x02' function='0x0'/> + </controller> + <controller type='scsi' index='0' model='lsilogic'> + <address type='pci' domain='0x0000' bus='0x02' slot='0x03' function='0x0'/> + </controller> + <controller type='sata' index='0'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x1f' function='0x2'/> + </controller> + <controller type='pci' index='0' model='pcie-root'/> + <controller type='pci' index='1' model='pcie-root-port'> + <model name='pcie-root-port'/> + <target chassis='1' port='0x10'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0' multifunction='on'/> + </controller> + <controller type='pci' index='2' model='pcie-to-pci-bridge'> + <model name='pcie-pci-bridge'/> + <address type='pci' domain='0x0000' bus='0x01' slot='0x00' function='0x0'/> + </controller> + <controller type='pci' index='3' model='pcie-root-port'> + <model name='pcie-root-port'/> + <target chassis='3' port='0x11'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x1'/> + </controller> + <interface type='user'> + <mac address='52:54:00:09:a4:37'/> + <model type='rtl8139'/> + <address type='pci' domain='0x0000' bus='0x02' slot='0x01' function='0x0'/> + </interface> + <serial type='pty'> + <target type='isa-serial' port='0'> + <model name='isa-serial'/> + </target> + </serial> + <console type='pty'> + <target type='serial' port='0'/> + </console> + <input type='mouse' bus='ps2'/> + <input type='keyboard' bus='ps2'/> + <audio id='1' type='none'/> + <video> + <model type='cirrus' vram='16384' heads='1' primary='yes'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0'/> + </video> + <watchdog model='itco' action='reset'/> + <memballoon model='none'/> + <panic model='isa'/> + </devices> + <launchSecurity type='tdx'> + <policy>0x1</policy> + <mrConfigId>xxx</mrConfigId> + <mrOwner>xxx</mrOwner> + <mrOwnerConfig>xxx</mrOwnerConfig> + <quoteGenerationService> + <SocketAddress type='inet' host='xxx' port='xxx' numeric='yes' to='1' ipv4='yes' ipv6='no' keep_alive='yes' mptcp='yes'/> + </quoteGenerationService> + </launchSecurity> +</domain> diff --git a/tests/qemuxmlconfdata/launch-security-tdx-qgs-inet.xml b/tests/qemuxmlconfdata/launch-security-tdx-qgs-inet.xml new file mode 100644 index 0000000000..eb6f53baf9 --- /dev/null +++ b/tests/qemuxmlconfdata/launch-security-tdx-qgs-inet.xml @@ -0,0 +1,30 @@ +<domain type='qemu'> + <name>guest</name> + <uuid>1ccfd97d-5eb4-478a-bbe6-88d254c16db7</uuid> + <memory>4194304</memory> + <vcpu>4</vcpu> + <os> + <type arch='x86_64' machine='q35'>hvm</type> + </os> + <devices> + <emulator>/usr/bin/qemu-system-x86_64</emulator> + <controller type='usb'/> + <controller type='scsi'/> + <interface type='user'> + <mac address='52:54:00:09:a4:37'/> + </interface> + <serial type='pty'/> + <video/> + <memballoon model='none'/> + <panic/> + </devices> + <launchSecurity type='tdx'> + <policy>0x1</policy> + <mrConfigId>xxx</mrConfigId> + <mrOwner>xxx</mrOwner> + <mrOwnerConfig>xxx</mrOwnerConfig> + <quoteGenerationService> + <SocketAddress type='inet' host='xxx' port='xxx' numeric='yes' to='1' ipv4='yes' ipv6='no' keep_alive='yes' mptcp='yes'/> + </quoteGenerationService> + </launchSecurity> +</domain> diff --git a/tests/qemuxmlconfdata/launch-security-tdx-qgs-unix.x86_64-latest.xml b/tests/qemuxmlconfdata/launch-security-tdx-qgs-unix.x86_64-latest.xml new file mode 100644 index 0000000000..b18910b1d5 --- /dev/null +++ b/tests/qemuxmlconfdata/launch-security-tdx-qgs-unix.x86_64-latest.xml @@ -0,0 +1,77 @@ +<domain type='qemu'> + <name>guest</name> + <uuid>1ccfd97d-5eb4-478a-bbe6-88d254c16db7</uuid> + <memory unit='KiB'>4194304</memory> + <currentMemory unit='KiB'>4194304</currentMemory> + <vcpu placement='static'>4</vcpu> + <os> + <type arch='x86_64' machine='q35'>hvm</type> + <boot dev='hd'/> + </os> + <cpu mode='custom' match='exact' check='none'> + <model fallback='forbid'>qemu64</model> + </cpu> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu-system-x86_64</emulator> + <controller type='usb' index='0' model='piix3-uhci'> + <address type='pci' domain='0x0000' bus='0x02' slot='0x02' function='0x0'/> + </controller> + <controller type='scsi' index='0' model='lsilogic'> + <address type='pci' domain='0x0000' bus='0x02' slot='0x03' function='0x0'/> + </controller> + <controller type='sata' index='0'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x1f' function='0x2'/> + </controller> + <controller type='pci' index='0' model='pcie-root'/> + <controller type='pci' index='1' model='pcie-root-port'> + <model name='pcie-root-port'/> + <target chassis='1' port='0x10'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0' multifunction='on'/> + </controller> + <controller type='pci' index='2' model='pcie-to-pci-bridge'> + <model name='pcie-pci-bridge'/> + <address type='pci' domain='0x0000' bus='0x01' slot='0x00' function='0x0'/> + </controller> + <controller type='pci' index='3' model='pcie-root-port'> + <model name='pcie-root-port'/> + <target chassis='3' port='0x11'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x1'/> + </controller> + <interface type='user'> + <mac address='52:54:00:09:a4:37'/> + <model type='rtl8139'/> + <address type='pci' domain='0x0000' bus='0x02' slot='0x01' function='0x0'/> + </interface> + <serial type='pty'> + <target type='isa-serial' port='0'> + <model name='isa-serial'/> + </target> + </serial> + <console type='pty'> + <target type='serial' port='0'/> + </console> + <input type='mouse' bus='ps2'/> + <input type='keyboard' bus='ps2'/> + <audio id='1' type='none'/> + <video> + <model type='cirrus' vram='16384' heads='1' primary='yes'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0'/> + </video> + <watchdog model='itco' action='reset'/> + <memballoon model='none'/> + <panic model='isa'/> + </devices> + <launchSecurity type='tdx'> + <policy>0x1</policy> + <mrConfigId>xxx</mrConfigId> + <mrOwner>xxx</mrOwner> + <mrOwnerConfig>xxx</mrOwnerConfig> + <quoteGenerationService> + <SocketAddress type='unix' path='xxx' abstract='yes' tight='yes'/> + </quoteGenerationService> + </launchSecurity> +</domain> diff --git a/tests/qemuxmlconfdata/launch-security-tdx-qgs-unix.xml b/tests/qemuxmlconfdata/launch-security-tdx-qgs-unix.xml new file mode 100644 index 0000000000..daeee80939 --- /dev/null +++ b/tests/qemuxmlconfdata/launch-security-tdx-qgs-unix.xml @@ -0,0 +1,30 @@ +<domain type='qemu'> + <name>guest</name> + <uuid>1ccfd97d-5eb4-478a-bbe6-88d254c16db7</uuid> + <memory>4194304</memory> + <vcpu>4</vcpu> + <os> + <type arch='x86_64' machine='q35'>hvm</type> + </os> + <devices> + <emulator>/usr/bin/qemu-system-x86_64</emulator> + <controller type='usb'/> + <controller type='scsi'/> + <interface type='user'> + <mac address='52:54:00:09:a4:37'/> + </interface> + <serial type='pty'/> + <video/> + <memballoon model='none'/> + <panic/> + </devices> + <launchSecurity type='tdx'> + <policy>0x1</policy> + <mrConfigId>xxx</mrConfigId> + <mrOwner>xxx</mrOwner> + <mrOwnerConfig>xxx</mrOwnerConfig> + <quoteGenerationService> + <SocketAddress type='unix' path='xxx' abstract='yes' tight='yes'/> + </quoteGenerationService> + </launchSecurity> +</domain> diff --git a/tests/qemuxmlconfdata/launch-security-tdx-qgs-vsock.x86_64-latest.xml b/tests/qemuxmlconfdata/launch-security-tdx-qgs-vsock.x86_64-latest.xml new file mode 100644 index 0000000000..dfc0b744d8 --- /dev/null +++ b/tests/qemuxmlconfdata/launch-security-tdx-qgs-vsock.x86_64-latest.xml @@ -0,0 +1,77 @@ +<domain type='qemu'> + <name>guest</name> + <uuid>1ccfd97d-5eb4-478a-bbe6-88d254c16db7</uuid> + <memory unit='KiB'>4194304</memory> + <currentMemory unit='KiB'>4194304</currentMemory> + <vcpu placement='static'>4</vcpu> + <os> + <type arch='x86_64' machine='q35'>hvm</type> + <boot dev='hd'/> + </os> + <cpu mode='custom' match='exact' check='none'> + <model fallback='forbid'>qemu64</model> + </cpu> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu-system-x86_64</emulator> + <controller type='usb' index='0' model='piix3-uhci'> + <address type='pci' domain='0x0000' bus='0x02' slot='0x02' function='0x0'/> + </controller> + <controller type='scsi' index='0' model='lsilogic'> + <address type='pci' domain='0x0000' bus='0x02' slot='0x03' function='0x0'/> + </controller> + <controller type='sata' index='0'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x1f' function='0x2'/> + </controller> + <controller type='pci' index='0' model='pcie-root'/> + <controller type='pci' index='1' model='pcie-root-port'> + <model name='pcie-root-port'/> + <target chassis='1' port='0x10'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0' multifunction='on'/> + </controller> + <controller type='pci' index='2' model='pcie-to-pci-bridge'> + <model name='pcie-pci-bridge'/> + <address type='pci' domain='0x0000' bus='0x01' slot='0x00' function='0x0'/> + </controller> + <controller type='pci' index='3' model='pcie-root-port'> + <model name='pcie-root-port'/> + <target chassis='3' port='0x11'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x1'/> + </controller> + <interface type='user'> + <mac address='52:54:00:09:a4:37'/> + <model type='rtl8139'/> + <address type='pci' domain='0x0000' bus='0x02' slot='0x01' function='0x0'/> + </interface> + <serial type='pty'> + <target type='isa-serial' port='0'> + <model name='isa-serial'/> + </target> + </serial> + <console type='pty'> + <target type='serial' port='0'/> + </console> + <input type='mouse' bus='ps2'/> + <input type='keyboard' bus='ps2'/> + <audio id='1' type='none'/> + <video> + <model type='cirrus' vram='16384' heads='1' primary='yes'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0'/> + </video> + <watchdog model='itco' action='reset'/> + <memballoon model='none'/> + <panic model='isa'/> + </devices> + <launchSecurity type='tdx'> + <policy>0x1</policy> + <mrConfigId>xxx</mrConfigId> + <mrOwner>xxx</mrOwner> + <mrOwnerConfig>xxx</mrOwnerConfig> + <quoteGenerationService> + <SocketAddress type='vsock' cid='xxx' port='xxx'/> + </quoteGenerationService> + </launchSecurity> +</domain> diff --git a/tests/qemuxmlconfdata/launch-security-tdx-qgs-vsock.xml b/tests/qemuxmlconfdata/launch-security-tdx-qgs-vsock.xml new file mode 100644 index 0000000000..576714ae98 --- /dev/null +++ b/tests/qemuxmlconfdata/launch-security-tdx-qgs-vsock.xml @@ -0,0 +1,30 @@ +<domain type='qemu'> + <name>guest</name> + <uuid>1ccfd97d-5eb4-478a-bbe6-88d254c16db7</uuid> + <memory>4194304</memory> + <vcpu>4</vcpu> + <os> + <type arch='x86_64' machine='q35'>hvm</type> + </os> + <devices> + <emulator>/usr/bin/qemu-system-x86_64</emulator> + <controller type='usb'/> + <controller type='scsi'/> + <interface type='user'> + <mac address='52:54:00:09:a4:37'/> + </interface> + <serial type='pty'/> + <video/> + <memballoon model='none'/> + <panic/> + </devices> + <launchSecurity type='tdx'> + <policy>0x1</policy> + <mrConfigId>xxx</mrConfigId> + <mrOwner>xxx</mrOwner> + <mrOwnerConfig>xxx</mrOwnerConfig> + <quoteGenerationService> + <SocketAddress type='vsock' cid='xxx' port='xxx'/> + </quoteGenerationService> + </launchSecurity> +</domain> diff --git a/tests/qemuxmlconftest.c b/tests/qemuxmlconftest.c index 1f9e8edef9..0476821342 100644 --- a/tests/qemuxmlconftest.c +++ b/tests/qemuxmlconftest.c @@ -2848,6 +2848,30 @@ mymain(void) QEMU_CAPS_SEV_GUEST, QEMU_CAPS_LAST); + DO_TEST_CAPS_ARCH_LATEST_FULL("launch-security-tdx-qgs-inet", + "x86_64", + ARG_QEMU_CAPS, + QEMU_CAPS_TDX_GUEST, + QEMU_CAPS_LAST); + + DO_TEST_CAPS_ARCH_LATEST_FULL("launch-security-tdx-qgs-unix", + "x86_64", + ARG_QEMU_CAPS, + QEMU_CAPS_TDX_GUEST, + QEMU_CAPS_LAST); + + DO_TEST_CAPS_ARCH_LATEST_FULL("launch-security-tdx-qgs-vsock", + "x86_64", + ARG_QEMU_CAPS, + QEMU_CAPS_TDX_GUEST, + QEMU_CAPS_LAST); + + DO_TEST_CAPS_ARCH_LATEST_FULL("launch-security-tdx-qgs-fd", + "x86_64", + ARG_QEMU_CAPS, + QEMU_CAPS_TDX_GUEST, + QEMU_CAPS_LAST); + DO_TEST_CAPS_ARCH_LATEST("launch-security-s390-pv", "s390x"); DO_TEST_CAPS_LATEST("vhost-user-fs-fd-memory"); -- 2.34.1

Signed-off-by: Zhenzhong Duan <zhenzhong.duan@intel.com> --- docs/formatdomain.rst | 68 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/docs/formatdomain.rst b/docs/formatdomain.rst index 83c1405c17..5ee9f3a426 100644 --- a/docs/formatdomain.rst +++ b/docs/formatdomain.rst @@ -8851,6 +8851,74 @@ spec <https://support.amd.com/TechDocs/55766_SEV-KM_API_Specification.pdf>`__ session blob defined in the SEV API spec. See SEV spec LAUNCH_START section for the session blob format. + +The contents of the ``<launchSecurity type='tdx'>`` element is used to provide +the guest owners input used for creating an encrypted VM using the Intel TDX +(Trusted Domain eXtensions). Intel TDX refers to an Intel technology that +extends Virtual Machine Extensions (VMX) and Multi-Key Total Memory Encryption +(MKTME) with a new kind of virtual machine guest called a Trust Domain (TD). +A TD runs in a CPU mode that is designed to protect the confidentiality of its +memory contents and its CPU state from any other software, including the hosting +Virtual Machine Monitor (VMM), unless explicitly shared by the TD itself. + +:: + + <domain> + ... + <launchSecurity type='tdx'> + <policy>0x10000001</policy> + <mrConfigId>xxx</mrConfigId> + <mrOwner>xxx</mrOwner> + <mrOwnerConfig>xxx</mrOwnerConfig> + <quoteGenerationService> + <SocketAddress type='vsock' cid='xxx' port='xxx'/> + </quoteGenerationService> + ... + </domain> + +``policy`` + The required ``policy`` element provides the guest TD attributes which is + passed by the host VMM as a guest TD initialization parameter as part of + TD_PARAMS, it exactly matches the definition of TD_PARAMS.ATTRIBUTES in + (Intel TDX Module Spec Table 22.2: ATTRIBUTES Definition). It is reported + to the guest TD by TDG.VP.INFO and as part of TDREPORT_STRUCT returned by + TDG.MR.REPORT. The guest policy is a 8 unsigned byte with the fields shown + in Table: + + ====== ==================================================================================== + Bit(s) Description + ====== ==================================================================================== + 0 Guest TD runs in off-TD debug mode when set + 1:27 reserved + 28 Disable EPT violation conversion to #VE on guest TD access of PENDING pages when set + 29:63 reserved + ====== ==================================================================================== + +``mrConfigId`` + The optional ``mrConfigId`` element provides ID for non-owner-defined + configuration of the guest TD, e.g., run-time or OS configuration + (base64 encoded SHA384 digest). + +``@mrowner`` + The optional ``@mrowner`` element provides ID for the guest TD’s owner + (base64 encoded SHA384 digest). + +``mrownerconfig`` + The optional ``mrownerconfig`` element provides ID for owner-defined + configuration of the guest TD, e.g., specific to the workload rather than + the run-time or OS (base64 encoded SHA384 digest). + +``quoteGenerationService`` + The optional ``quoteGenerationService`` subelement provides Quote + Generation Service(QGS) related configuration. QGS is a daemon running + on the host. User in TD guest cannot get TD quoting for attestation if + QGS is not provided. Currently only one subelement ``SocketAddress``. + + ``SocketAddress`` + The required ``SocketAddress`` element provides socket address for QGS. + Different properties of ``SocketAddress`` are supported depending on + value of ``type`` property which can be "inet", "unix", "vsock" and "fd". + Example configs =============== -- 2.34.1
participants (6)
-
Daniel P. Berrangé
-
Duan, Zhenzhong
-
Hector Cao
-
hector.cao@canonical.com
-
Jim Fehlig
-
Zhenzhong Duan