Old TDX modules can clobber RBP in the TDH.VP.ENTER SEAMCALL. However
RBP is used as frame pointer in the x86_64 calling convention, and
clobbering RBP could result in bad things like being unable to unwind
the stack if any non-maskable exceptions (NMI, #MC etc) happens in that
gap.
A new "NO_RBP_MOD" feature was introduced to more recent TDX modules to
not clobber RBP. This feature is reported in the TDX_FEATURES0 global
metadata field via bit 18.
Don't initialize the TDX module if this feature is not supported [1].
Note the bit definitions of TDX_FEATURES0 are not auto-generated in
tdx_global_metadata.h. Manually define a macro for it in "tdx.h".
Link: https://lore.kernel.org/all/fc0e8ab7-86d4-4428-be31-82e1ece6dd21@intel.com/ [1]
Signed-off-by: Kai Huang <kai.huang@intel.com>
Reviewed-by: Nikolay Borisov <nik.borisov@suse.com>
Reviewed-by: Adrian Hunter <adrian.hunter@intel.com>
Reviewed-by: Dan Williams <dan.j.williams@intel.com>
---
arch/x86/virt/vmx/tdx/tdx.c | 17 +++++++++++++++++
arch/x86/virt/vmx/tdx/tdx.h | 4 ++++
2 files changed, 21 insertions(+)
diff --git a/arch/x86/virt/vmx/tdx/tdx.c b/arch/x86/virt/vmx/tdx/tdx.c
index 9acb12c75e9b..9bc827a6cee8 100644
--- a/arch/x86/virt/vmx/tdx/tdx.c
+++ b/arch/x86/virt/vmx/tdx/tdx.c
@@ -326,6 +326,18 @@ static int init_tdx_sys_info(struct tdx_sys_info *sysinfo)
return 0;
}
+static int check_features(struct tdx_sys_info *sysinfo)
+{
+ u64 tdx_features0 = sysinfo->features.tdx_features0;
+
+ if (!(tdx_features0 & TDX_FEATURES0_NO_RBP_MOD)) {
+ pr_err("frame pointer (RBP) clobber bug present, upgrade TDX module\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
/* Calculate the actual TDMR size */
static int tdmr_size_single(u16 max_reserved_per_tdmr)
{
@@ -1109,6 +1121,11 @@ static int init_tdx_module(void)
if (ret)
return ret;
+ /* Check whether the kernel can support this module */
+ ret = check_features(&sysinfo);
+ if (ret)
+ return ret;
+
/*
* To keep things simple, assume that all TDX-protected memory
* will come from the page allocator. Make sure all pages in the
diff --git a/arch/x86/virt/vmx/tdx/tdx.h b/arch/x86/virt/vmx/tdx/tdx.h
index 0128b963b723..c8be00f6b15a 100644
--- a/arch/x86/virt/vmx/tdx/tdx.h
+++ b/arch/x86/virt/vmx/tdx/tdx.h
@@ -5,6 +5,7 @@
#include <linux/types.h>
#include <linux/compiler_attributes.h>
#include <linux/stddef.h>
+#include <linux/bits.h>
#include "tdx_global_metadata.h"
/*
@@ -54,6 +55,9 @@ struct tdmr_info {
DECLARE_FLEX_ARRAY(struct tdmr_reserved_area, reserved_areas);
} __packed __aligned(TDMR_INFO_ALIGNMENT);
+/* Bit definitions of TDX_FEATURES0 metadata field */
+#define TDX_FEATURES0_NO_RBP_MOD BIT(18)
+
/*
* Do not put any hardware-defined TDX structure representations below
* this comment!
--
2.46.2