diff mbox series

KVM: VMX: pass TME information to guests

Message ID 20220203181432.34911-1-faresx@amazon.de (mailing list archive)
State New, archived
Headers show
Series KVM: VMX: pass TME information to guests | expand

Commit Message

Fares Mehanna Feb. 3, 2022, 6:14 p.m. UTC
Guests running on IceLake have TME-EN disabled in CPUID, and they can't read TME
related MSRs [IA32_TME_CAPABILITY, IA32_TME_ACTIVATE, IA32_TME_EXCLUDE_MASK,
IA32_TME_EXCLUDE_BASE].

So guests don't know if they are running with TME enabled or not.

In this patch, TME information is passed to the guest if the host has `TME-EN`
enabled in CPUID and TME MSRs are locked and the exclusion range is disabled.

This will guarantee that hardware supports TME, MSRs are locked, so host can't
change them and exclusion range is disabled, so TME rules apply on all host
memory.

In IA32_TME_CAPABILITY and IA32_TME_ACTIVATE we mask out the reserved bits and
MKTME related bits.

So in IA32_TME_CAPABILITY, we are passing:
Bit[0]:  Support for AES-XTS 128-bit encryption algorithm
Bit[2]:  Support for AES-XTS 256-bit encryption algorithm
Bit[31]: TME encryption bypass supported

And in IA32_TME_ACTIVATE, we are passing:
Bit[0]:   Lock RO
Bit[1]:   TME Enable RWL
Bit[2]:   Key select
Bit[3]:   Save TME key for Standby
Bit[4:7]: Encryption Algorithm
Bit[31]:  TME Encryption Bypass Enable

However IA32_TME_EXCLUDE_MASK and IA32_TME_EXCLUDE_BASE are read by the guest as
zero, since we will only pass TME information if the exclusion range is
disabled.

Those information are helpful for the guest to determine if TME is enabled by
the BIOS or not.

Signed-off-by: Fares Mehanna <faresx@amazon.de>
---
 arch/x86/include/asm/msr-index.h |  6 ++++++
 arch/x86/include/asm/processor.h | 14 ++++++++++++++
 arch/x86/kernel/cpu/intel.c      | 15 +--------------
 arch/x86/kvm/cpuid.c             | 19 ++++++++++++++++++-
 arch/x86/kvm/vmx/vmx.c           | 20 ++++++++++++++++++++
 5 files changed, 59 insertions(+), 15 deletions(-)

Comments

Dave Hansen Feb. 3, 2022, 6:40 p.m. UTC | #1
On 2/3/22 10:14, Fares Mehanna wrote:
> This will guarantee that hardware supports TME, MSRs are locked, so host can't
> change them and exclusion range is disabled, so TME rules apply on all host
> memory.

But, what's the point?  Guests can't trust this information.  The host
can lie all it wants about it.

Also, your assumptions about TME rules applying to *all* host memory are
a bit aggressive.

Even if the guest knew for sure that it was reading an MSR directly, it
doesn't mean that any guest memory is actually TME-protected.  The
memory could be from a non-TME range like persistent memory.  There are
some weasel words in the spec about this:

> Upon activation, all memory (except in TME Exclusion range) attached
> to CPU/SoC is encrypted using AES-XTS 128 bit ephemeral key (platform
> key) that is generated by the CPU on every boot.

The important part here is "attached to the CPU/SoC".  I guess they
don't count persistent memory as "attached".  This also obviously would
not apply to non-CPU-attached memory that was attached by something like
CXL[1].

The extra fun part of all this is that the architecture doesn't provide
a way to tell if the memory is "attached to the CPU/SoC".  That makes it
impossible to get any guarantees out of all this.

In other words, you can't trust the exclusion range in the MSR to be the
*ONLY* non-TME-protected area.

1. https://www.computeexpresslink.org/
diff mbox series

Patch

diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h
index 3faf0f97edb1..908aad1a7cad 100644
--- a/arch/x86/include/asm/msr-index.h
+++ b/arch/x86/include/asm/msr-index.h
@@ -438,6 +438,12 @@ 
 #define MSR_RELOAD_PMC0			0x000014c1
 #define MSR_RELOAD_FIXED_CTR0		0x00001309
 
+/* Memory encryption MSRs */
+#define MSR_IA32_TME_CAPABILITY		0x981
+#define MSR_IA32_TME_ACTIVATE		0x982
+#define MSR_IA32_TME_EXCLUDE_MASK	0x983
+#define MSR_IA32_TME_EXCLUDE_BASE	0x984
+
 /*
  * AMD64 MSRs. Not complete. See the architecture manual for a more
  * complete list.
diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h
index 2c5f12ae7d04..28387ae7277b 100644
--- a/arch/x86/include/asm/processor.h
+++ b/arch/x86/include/asm/processor.h
@@ -863,4 +863,18 @@  bool arch_is_platform_page(u64 paddr);
 #define arch_is_platform_page arch_is_platform_page
 #endif
 
+/* Helpers to access TME_ACTIVATE MSR */
+#define TME_ACTIVATE_LOCKED(x)		((x) & 0x1)
+#define TME_ACTIVATE_ENABLED(x)		((x) & 0x2)
+
+#define TME_ACTIVATE_POLICY(x)		(((x) >> 4) & 0xf)        /* Bits 7:4 */
+#define TME_ACTIVATE_POLICY_AES_XTS_128	0
+
+#define TME_ACTIVATE_KEYID_BITS(x)	(((x) >> 32) & 0xf)     /* Bits 35:32 */
+
+#define TME_ACTIVATE_CRYPTO_ALGS(x)	(((x) >> 48) & 0xffff)    /* Bits 63:48 */
+#define TME_ACTIVATE_CRYPTO_AES_XTS_128	1
+
+#define TME_EXCLUSION_ENABLED(x)	((x) & 0x800) /* Bit 11 */
+
 #endif /* _ASM_X86_PROCESSOR_H */
diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c
index 8321c43554a1..46ad006089a3 100644
--- a/arch/x86/kernel/cpu/intel.c
+++ b/arch/x86/kernel/cpu/intel.c
@@ -14,6 +14,7 @@ 
 
 #include <asm/cpufeature.h>
 #include <asm/msr.h>
+#include <asm/processor.h>
 #include <asm/bugs.h>
 #include <asm/cpu.h>
 #include <asm/intel-family.h>
@@ -492,20 +493,6 @@  static void srat_detect_node(struct cpuinfo_x86 *c)
 #endif
 }
 
-#define MSR_IA32_TME_ACTIVATE		0x982
-
-/* Helpers to access TME_ACTIVATE MSR */
-#define TME_ACTIVATE_LOCKED(x)		(x & 0x1)
-#define TME_ACTIVATE_ENABLED(x)		(x & 0x2)
-
-#define TME_ACTIVATE_POLICY(x)		((x >> 4) & 0xf)	/* Bits 7:4 */
-#define TME_ACTIVATE_POLICY_AES_XTS_128	0
-
-#define TME_ACTIVATE_KEYID_BITS(x)	((x >> 32) & 0xf)	/* Bits 35:32 */
-
-#define TME_ACTIVATE_CRYPTO_ALGS(x)	((x >> 48) & 0xffff)	/* Bits 63:48 */
-#define TME_ACTIVATE_CRYPTO_AES_XTS_128	1
-
 /* Values for mktme_status (SW only construct) */
 #define MKTME_ENABLED			0
 #define MKTME_DISABLED			1
diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c
index 28be02adc669..c5a18527f099 100644
--- a/arch/x86/kvm/cpuid.c
+++ b/arch/x86/kvm/cpuid.c
@@ -84,6 +84,22 @@  static inline struct kvm_cpuid_entry2 *cpuid_entry2_find(
 	return NULL;
 }
 
+static bool kvm_tme_supported(void)
+{
+	u64 tme_activation, tme_exclusion;
+
+	if (!feature_bit(TME))
+		return false;
+
+	if (rdmsrl_safe(MSR_IA32_TME_EXCLUDE_MASK, &tme_exclusion))
+		return false;
+	if (rdmsrl_safe(MSR_IA32_TME_ACTIVATE, &tme_activation))
+		return false;
+
+	return TME_ACTIVATE_LOCKED(tme_activation) &&
+		!TME_EXCLUSION_ENABLED(tme_exclusion);
+}
+
 static int kvm_check_cpuid(struct kvm_vcpu *vcpu,
 			   struct kvm_cpuid_entry2 *entries,
 			   int nent)
@@ -508,6 +524,7 @@  static __always_inline void kvm_cpu_cap_mask(enum cpuid_leafs leaf, u32 mask)
 
 void kvm_set_cpu_caps(void)
 {
+	unsigned int f_tme = kvm_tme_supported() ? F(TME) : 0;
 #ifdef CONFIG_X86_64
 	unsigned int f_gbpages = F(GBPAGES);
 	unsigned int f_lm = F(LM);
@@ -565,7 +582,7 @@  void kvm_set_cpu_caps(void)
 		F(AVX512VBMI) | F(LA57) | F(PKU) | 0 /*OSPKE*/ | F(RDPID) |
 		F(AVX512_VPOPCNTDQ) | F(UMIP) | F(AVX512_VBMI2) | F(GFNI) |
 		F(VAES) | F(VPCLMULQDQ) | F(AVX512_VNNI) | F(AVX512_BITALG) |
-		F(CLDEMOTE) | F(MOVDIRI) | F(MOVDIR64B) | 0 /*WAITPKG*/ |
+		f_tme | F(CLDEMOTE) | F(MOVDIRI) | F(MOVDIR64B) | 0 /*WAITPKG*/ |
 		F(SGX_LC) | F(BUS_LOCK_DETECT)
 	);
 	/* Set LA57 based on hardware capability. */
diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
index aca3ae2a02f3..f8cbf935cfe0 100644
--- a/arch/x86/kvm/vmx/vmx.c
+++ b/arch/x86/kvm/vmx/vmx.c
@@ -1913,6 +1913,26 @@  static int vmx_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
 	case MSR_IA32_DEBUGCTLMSR:
 		msr_info->data = vmcs_read64(GUEST_IA32_DEBUGCTL);
 		break;
+	case MSR_IA32_TME_CAPABILITY:
+		if (!guest_cpuid_has(vcpu, X86_FEATURE_TME))
+			return 1;
+		if (rdmsrl_safe(MSR_IA32_TME_CAPABILITY, &msr_info->data))
+			return 1;
+		msr_info->data &= 0x80000005; /* Bit 0, 2, 31 */
+		break;
+	case MSR_IA32_TME_ACTIVATE:
+		if (!guest_cpuid_has(vcpu, X86_FEATURE_TME))
+			return 1;
+		if (rdmsrl_safe(MSR_IA32_TME_ACTIVATE, &msr_info->data))
+			return 1;
+		msr_info->data &= 0x800000FF; /* Bits [0-7] and Bit 31 */
+		break;
+	case MSR_IA32_TME_EXCLUDE_MASK:
+	case MSR_IA32_TME_EXCLUDE_BASE:
+		if (!guest_cpuid_has(vcpu, X86_FEATURE_TME))
+			return 1;
+		msr_info->data = 0x0;
+		break;
 	default:
 	find_uret_msr:
 		msr = vmx_find_uret_msr(vmx, msr_info->index);