[PATCH v3 25/26] x86/virt/tdx: Avoid updates during update-sensitive operations

Chao Gao posted 26 patches 2 weeks ago
[PATCH v3 25/26] x86/virt/tdx: Avoid updates during update-sensitive operations
Posted by Chao Gao 2 weeks ago
TDX Module updates may cause TD management operations to fail if they
occur during phases of the TD lifecycle that are sensitive to update
compatibility.

Currently, there are two update-sensitive scenarios:
 - TD build, where TD Measurement Register (TDMR) accumulates over multiple
   TDH.MEM.PAGE.ADD, TDH.MR.EXTEND and TDH.MR.FINALIZE calls.

 - TD migration, where an intermediate crypto state is saved if a state
   migration function (TDH.EXPORT.STATE.* or TDH.IMPORT.STATE.*) is
   interrupted and restored when the function is resumed.

For example, if an update races with TD build operations, the TD
Measurement Register will become incorrect, causing the TD to fail
attestation.

The TDX Module offers two solutions:

1. Avoid updates during update-sensitive times

   The host VMM can instruct TDH.SYS.SHUTDOWN to fail if any of the TDs
   are currently in any update-sensitive cases.

2. Detect incompatibility after updates

   On TDH.SYS.UPDATE, the host VMM can configure the TDX Module to detect
   actual incompatibility cases. The TDX Module will then return a special
   error to signal the incompatibility, allowing the host VMM to restart
   the update-sensitive operations.

Implement option #1 to fail updates if the feature is available. Also,
distinguish this update failure from other failures by returning -EBUSY,
which will be converted to a firmware update error code indicating that the
firmware is busy.

Options like "do nothing" or option #2 are not viable [1] because the
former allows damage to propagate to multiple, potentially unknown
components (adding significant complexity to the whole ecosystem), while
the latter may make existing KVM ioctls unstable.

Based on a reference patch by Vishal [2].

Signed-off-by: Chao Gao <chao.gao@intel.com>
Link: https://lore.kernel.org/linux-coco/aQIbM5m09G0FYTzE@google.com/ # [1]
Link: https://lore.kernel.org/linux-coco/CAGtprH_oR44Vx9Z0cfxvq5-QbyLmy_+Gn3tWm3wzHPmC1nC0eg@mail.gmail.com/ # [2]
---
 arch/x86/include/asm/tdx.h   | 13 +++++++++++--
 arch/x86/kvm/vmx/tdx_errno.h |  2 --
 arch/x86/virt/vmx/tdx/tdx.c  | 23 +++++++++++++++++++----
 3 files changed, 30 insertions(+), 8 deletions(-)

diff --git a/arch/x86/include/asm/tdx.h b/arch/x86/include/asm/tdx.h
index 0cd408f902f4..85746de7c528 100644
--- a/arch/x86/include/asm/tdx.h
+++ b/arch/x86/include/asm/tdx.h
@@ -26,15 +26,19 @@
 #define TDX_SEAMCALL_GP			(TDX_SW_ERROR | X86_TRAP_GP)
 #define TDX_SEAMCALL_UD			(TDX_SW_ERROR | X86_TRAP_UD)
 
+#define TDX_SEAMCALL_STATUS_MASK		0xFFFFFFFF00000000ULL
+
 /*
  * TDX module SEAMCALL leaf function error codes
  */
-#define TDX_SUCCESS		0ULL
-#define TDX_RND_NO_ENTROPY	0x8000020300000000ULL
+#define TDX_SUCCESS			0ULL
+#define TDX_RND_NO_ENTROPY		0x8000020300000000ULL
+#define TDX_UPDATE_COMPAT_SENSITIVE	0x8000051200000000ULL
 
 /* Bit definitions of TDX_FEATURES0 metadata field */
 #define TDX_FEATURES0_TD_PRESERVING	BIT(1)
 #define TDX_FEATURES0_NO_RBP_MOD	BIT(18)
+#define TDX_FEATURES0_UPDATE_COMPAT	BIT_ULL(47)
 #ifndef __ASSEMBLER__
 
 #include <uapi/asm/mce.h>
@@ -111,6 +115,11 @@ static inline bool tdx_supports_runtime_update(const struct tdx_sys_info *sysinf
 	return sysinfo->features.tdx_features0 & TDX_FEATURES0_TD_PRESERVING;
 }
 
+static inline bool tdx_supports_update_compatibility(const struct tdx_sys_info *sysinfo)
+{
+	return sysinfo->features.tdx_features0 & TDX_FEATURES0_UPDATE_COMPAT;
+}
+
 int tdx_guest_keyid_alloc(void);
 u32 tdx_get_nr_guest_keyids(void);
 void tdx_guest_keyid_free(unsigned int keyid);
diff --git a/arch/x86/kvm/vmx/tdx_errno.h b/arch/x86/kvm/vmx/tdx_errno.h
index 6ff4672c4181..215c00d76a94 100644
--- a/arch/x86/kvm/vmx/tdx_errno.h
+++ b/arch/x86/kvm/vmx/tdx_errno.h
@@ -4,8 +4,6 @@
 #ifndef __KVM_X86_TDX_ERRNO_H
 #define __KVM_X86_TDX_ERRNO_H
 
-#define TDX_SEAMCALL_STATUS_MASK		0xFFFFFFFF00000000ULL
-
 /*
  * TDX SEAMCALL Status Codes (returned in RAX)
  */
diff --git a/arch/x86/virt/vmx/tdx/tdx.c b/arch/x86/virt/vmx/tdx/tdx.c
index 5d3f3f3eeb7d..5b562255630b 100644
--- a/arch/x86/virt/vmx/tdx/tdx.c
+++ b/arch/x86/virt/vmx/tdx/tdx.c
@@ -1175,10 +1175,13 @@ int tdx_enable(void)
 }
 EXPORT_SYMBOL_FOR_KVM(tdx_enable);
 
+#define TDX_SYS_SHUTDOWN_AVOID_COMPAT_SENSITIVE BIT(16)
+
 int tdx_module_shutdown(void)
 {
 	struct tdx_module_args args = {};
-	int ret, cpu;
+	u64 ret;
+	int cpu;
 
 	/*
 	 * Shut down the TDX Module and prepare handoff data for the next
@@ -1189,9 +1192,21 @@ int tdx_module_shutdown(void)
 	 * hand-off version.
 	 */
 	args.rcx = tdx_sysinfo.handoff.module_hv;
-	ret = seamcall_prerr(TDH_SYS_SHUTDOWN, &args);
-	if (ret)
-		return ret;
+
+	if (tdx_supports_update_compatibility(&tdx_sysinfo))
+		args.rcx |= TDX_SYS_SHUTDOWN_AVOID_COMPAT_SENSITIVE;
+
+	ret = seamcall(TDH_SYS_SHUTDOWN, &args);
+
+	/*
+	 * Return -EBUSY to signal that there is one or more ongoing flows
+	 * which may not be compatible with an updated TDX module, so that
+	 * userspace can retry on this error.
+	 */
+	if ((ret & TDX_SEAMCALL_STATUS_MASK) == TDX_UPDATE_COMPAT_SENSITIVE)
+		return -EBUSY;
+	else if (ret)
+		return -EIO;
 
 	tdx_module_status = TDX_MODULE_UNINITIALIZED;
 	sysinit_done = false;
-- 
2.47.3
Re: [PATCH v3 25/26] x86/virt/tdx: Avoid updates during update-sensitive operations
Posted by Tony Lindgren 1 week, 4 days ago
On Fri, Jan 23, 2026 at 06:55:33AM -0800, Chao Gao wrote:
> TDX Module updates may cause TD management operations to fail if they
> occur during phases of the TD lifecycle that are sensitive to update
> compatibility.
> 
> Currently, there are two update-sensitive scenarios:
>  - TD build, where TD Measurement Register (TDMR) accumulates over multiple
>    TDH.MEM.PAGE.ADD, TDH.MR.EXTEND and TDH.MR.FINALIZE calls.
> 
>  - TD migration, where an intermediate crypto state is saved if a state
>    migration function (TDH.EXPORT.STATE.* or TDH.IMPORT.STATE.*) is
>    interrupted and restored when the function is resumed.
> 
> For example, if an update races with TD build operations, the TD
> Measurement Register will become incorrect, causing the TD to fail
> attestation.
> 
> The TDX Module offers two solutions:
> 
> 1. Avoid updates during update-sensitive times
> 
>    The host VMM can instruct TDH.SYS.SHUTDOWN to fail if any of the TDs
>    are currently in any update-sensitive cases.
> 
> 2. Detect incompatibility after updates
> 
>    On TDH.SYS.UPDATE, the host VMM can configure the TDX Module to detect
>    actual incompatibility cases. The TDX Module will then return a special
>    error to signal the incompatibility, allowing the host VMM to restart
>    the update-sensitive operations.
> 
> Implement option #1 to fail updates if the feature is available. Also,
> distinguish this update failure from other failures by returning -EBUSY,
> which will be converted to a firmware update error code indicating that the
> firmware is busy.

Looks good to me:

Reviewed-by: Tony Lindgren <tony.lindgren@linux.intel.com>