diff mbox series

[RFC,6/8] KVM: SVM: KVM_SEV_SNP_LAUNCH_RESET_VECTOR

Message ID 20230127025237.269680-7-jarkko@profian.com (mailing list archive)
State New, archived
Headers show
Series [RFC,1/8] KVM: SVM: fix: calculate end instead of passing size | expand

Commit Message

Jarkko Sakkinen Jan. 27, 2023, 2:52 a.m. UTC
The attestation of the workload includes the CPU state information.

When the workload that was running in the VM exits, the system stores
the state in the special area (VMSA).  When the workload is started again,
it loads the state back.  This is a well-defined process and works.

However, the *initial state* needs to be better defined.  Currently, it is
defined by kernel without userspace knowledge or ability to influence.  As
a result, Enarx does not know the initial state and has to make a guess
whenever there is need to offline digest calculation.  After all, the core
idea of confidential computing that everything can be validated and
verified in order to reach trust.

The variation could come mainly from either sev_features and vintr_ctrl.

Allow to user space to define them when the new KVM_SEV_SNP_RESET_VECTOR
init flag is set but at the same time verify that they are set only to
those values that kernel is aware of.

Link: https://enarx.dev/
Signed-off-by: Jarkko Sakkinen <jarkko@profian.com>
---
 arch/x86/include/asm/svm.h | 15 ++++++----
 arch/x86/kvm/svm/sev.c     | 57 +++++++++++++++++++++++++++++++-------
 arch/x86/kvm/svm/svm.h     |  1 +
 include/uapi/linux/kvm.h   |  5 ++++
 4 files changed, 63 insertions(+), 15 deletions(-)
diff mbox series

Patch

diff --git a/arch/x86/include/asm/svm.h b/arch/x86/include/asm/svm.h
index e76ad26ba64f..b3b7131a1ce7 100644
--- a/arch/x86/include/asm/svm.h
+++ b/arch/x86/include/asm/svm.h
@@ -278,12 +278,17 @@  enum avic_ipi_failure_cause {
 #define AVIC_HPA_MASK	~((0xFFFULL << 52) | 0xFFF)
 #define VMCB_AVIC_APIC_BAR_MASK		0xFFFFFFFFFF000ULL
 
-#define SVM_SEV_FEAT_SNP_ACTIVE			BIT(0)
-#define SVM_SEV_FEAT_RESTRICTED_INJECTION	BIT(3)
-#define SVM_SEV_FEAT_ALTERNATE_INJECTION	BIT(4)
-#define SVM_SEV_FEAT_INT_INJ_MODES		\
-	(SVM_SEV_FEAT_RESTRICTED_INJECTION |	\
+
+#define SVM_SEV_FEAT_SNP_ACTIVE			BIT_ULL(0)
+#define SVM_SEV_FEAT_RESTRICTED_INJECTION	BIT_ULL(3)
+#define SVM_SEV_FEAT_ALTERNATE_INJECTION	BIT_ULL(4)
+#define SVM_SEV_FEAT_INT_INJ_MODES \
+	(SVM_SEV_FEAT_RESTRICTED_INJECTION |\
 	 SVM_SEV_FEAT_ALTERNATE_INJECTION)
+#define SVM_SEV_FEAT_UNSUPPORTED_MASK \
+	~(SVM_SEV_FEAT_SNP_ACTIVE |\
+	  SVM_SEV_FEAT_RESTRICTED_INJECTION |\
+	  SVM_SEV_FEAT_ALTERNATE_INJECTION)
 
 struct vmcb_seg {
 	u16 selector;
diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c
index 899c78d03c35..5e4666b79689 100644
--- a/arch/x86/kvm/svm/sev.c
+++ b/arch/x86/kvm/svm/sev.c
@@ -303,6 +303,11 @@  static int verify_snp_init_flags(struct kvm *kvm, struct kvm_sev_cmd *argp)
 	/* Save the supplied flags value */
 	sev->snp_init_flags = params.flags;
 
+	if (params.flags & KVM_SEV_SNP_RESET_VECTOR) {
+		sev->sev_features = params.sev_features;
+		sev->vintr_ctrl = params.vintr_ctrl;
+	}
+
 	/* Return the supported flags value */
 	params.flags = SEV_SNP_SUPPORTED_FLAGS;
 
@@ -785,6 +790,33 @@  static int sev_es_sync_vmsa(struct vcpu_svm *svm)
 	if (svm->vcpu.guest_debug || (svm->vmcb->save.dr7 & ~DR7_FIXED_1))
 		return -EINVAL;
 
+	/* Validate that the user defined reset vector meets the expectations: */
+	if (sev->snp_init_flags & KVM_SEV_SNP_RESET_VECTOR) {
+		u64 unsupported = sev->sev_features & SVM_SEV_FEAT_UNSUPPORTED_MASK;
+
+		if (sev->sev_features & unsupported) {
+			pr_debug("sev_features: unsupported flags: 0x%016llx\n", unsupported);
+			return -EINVAL;
+		}
+
+		if (!(sev_snp_guest(svm->vcpu.kvm) &&
+		    (sev->sev_features & SVM_SEV_FEAT_SNP_ACTIVE))) {
+			pr_debug("sev_features: SNP_ACTIVE is not set\n");
+			return -EINVAL;
+		}
+
+		if (!((sev->snp_init_flags & KVM_SEV_SNP_RESTRICTED_INJET) &&
+		    (sev->sev_features & SVM_SEV_FEAT_RESTRICTED_INJECTION))) {
+			pr_debug("sev_features: SNP_SEV_FEAT_RESTRICTED_INJECTION is not set\n");
+			return -EINVAL;
+		}
+
+		if (sev->vintr_ctrl) {
+			pr_debug("vintr_ctrl: unsupported flags: 0x%016llx\n", sev->vintr_ctrl);
+			return -EINVAL;
+		}
+	}
+
 	/*
 	 * SEV-ES will use a VMSA that is pointed to by the VMCB, not
 	 * the traditional VMSA that is part of the VMCB. Copy the
@@ -820,18 +852,23 @@  static int sev_es_sync_vmsa(struct vcpu_svm *svm)
 	save->xss  = svm->vcpu.arch.ia32_xss;
 	save->dr6  = svm->vcpu.arch.dr6;
 
-	/* Enable the SEV-SNP feature */
-	if (sev_snp_guest(svm->vcpu.kvm))
-		save->sev_features |= SVM_SEV_FEAT_SNP_ACTIVE;
+	if (sev->snp_init_flags & KVM_SEV_SNP_RESET_VECTOR) {
+		save->sev_features = sev->sev_features;
+		save->vintr_ctrl = sev->vintr_ctrl;
+	} else {
+		/* Enable the SEV-SNP feature */
+		if (sev_snp_guest(svm->vcpu.kvm))
+			save->sev_features |= SVM_SEV_FEAT_SNP_ACTIVE;
 
-	if (sev->snp_init_flags & KVM_SEV_SNP_RESTRICTED_INJET)
-		save->sev_features |= SVM_SEV_FEAT_RESTRICTED_INJECTION;
+		if (sev->snp_init_flags & KVM_SEV_SNP_RESTRICTED_INJET)
+			save->sev_features |= SVM_SEV_FEAT_RESTRICTED_INJECTION;
 
-	/*
-	 * Save the VMSA synced SEV features. For now, they are the same for
-	 * all vCPUs, so just save each time.
-	 */
-	sev->sev_features = save->sev_features;
+		/*
+		 * Save the VMSA synced SEV features. For now, they are the same for
+		 * all vCPUs, so just save each time.
+		 */
+		sev->sev_features = save->sev_features;
+	}
 
 	pr_debug("Virtual Machine Save Area (VMSA):\n");
 	print_hex_dump_debug("", DUMP_PREFIX_NONE, 16, 1, save, sizeof(*save), false);
diff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h
index 4dab13084363..5dce17eefd5d 100644
--- a/arch/x86/kvm/svm/svm.h
+++ b/arch/x86/kvm/svm/svm.h
@@ -106,6 +106,7 @@  struct kvm_sev_info {
 	struct mutex guest_req_lock;
 
 	u64 sev_features;	/* Features set at VMSA creation */
+	u64 vintr_ctrl;
 };
 
 struct kvm_svm {
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index 48bcc59cf86b..e176d0ec6c54 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -2054,8 +2054,13 @@  struct kvm_sev_receive_update_data {
 /* enable the restricted injection timer */
 #define KVM_SEV_SNP_RESTRICTED_TIMER_INJET   (1 << 1)
 
+/* use the given reset vector for sev_features and vintr_ctrl */
+#define KVM_SEV_SNP_RESET_VECTOR   (1 << 2)
+
 struct kvm_snp_init {
 	__u64 flags;
+	__u64 sev_features;
+	__u64 vintr_ctrl;
 };
 
 struct kvm_sev_snp_launch_start {