[PATCH v4 07/10] KVM: SEV: Disallow setting SNP-only features for non-SNP guests via a single mask

From: Kim Phillips

Date: Tue Aug 04 2026 - 20:03:47 EST


As SNP-only features get added, adding them to the valid_vmsa_features mask
in __sev_guest_init() often gets neglected. Add SVM_SEV_FEAT_SNP_ONLY_MASK
to help group these common features together.

Also establish SNP_ONLY_FEATURES in the sev_init2 selftest as the
corresponding mask for features that must be rejected for non-SNP guests,
populate it with SVM_SEV_FEAT_SECURE_TSC, and exercise the rejection path
by masking those bits out of the features passed for SEV-ES guests. Define
the selftest's SNP_ONLY_FEATURES as ULL so future bits can use BIT_ULL()
there without truncation against the u64 supported_vmsa_features.

Suggested-by: Sean Christopherson <seanjc@xxxxxxxxxx>
Cc: Borislav Petkov (AMD) <bp@xxxxxxxxx>
Link: https://lore.kernel.org/kvm/aaWog_UjW-M3412C@xxxxxxxxxx/
Signed-off-by: Kim Phillips <kim.phillips@xxxxxxx>
Assisted-by: ClaudeCode:claude-opus-4-7
---
arch/x86/include/asm/svm.h | 2 ++
arch/x86/kvm/svm/sev.c | 2 +-
tools/testing/selftests/kvm/x86/sev_init2_tests.c | 12 +++++++-----
3 files changed, 10 insertions(+), 6 deletions(-)

diff --git a/arch/x86/include/asm/svm.h b/arch/x86/include/asm/svm.h
index 52c900bf7e20..a206a0ed2c58 100644
--- a/arch/x86/include/asm/svm.h
+++ b/arch/x86/include/asm/svm.h
@@ -311,6 +311,8 @@ static_assert((X2AVIC_4K_MAX_PHYSICAL_ID & AVIC_PHYSICAL_MAX_INDEX_MASK) == X2AV
#define SVM_SEV_FEAT_DEBUG_SWAP BIT_ULL(5)
#define SVM_SEV_FEAT_SECURE_TSC BIT_ULL(9)

+#define SVM_SEV_FEAT_SNP_ONLY_MASK (SVM_SEV_FEAT_SECURE_TSC)
+
#define VMCB_ALLOWED_SEV_FEATURES_VALID BIT_ULL(63)

struct vmcb_seg {
diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c
index 944aaea6501f..951f0e6be9e5 100644
--- a/arch/x86/kvm/svm/sev.c
+++ b/arch/x86/kvm/svm/sev.c
@@ -504,7 +504,7 @@ static int __sev_guest_init(struct kvm *kvm, struct kvm_sev_cmd *argp,
return -EINVAL;

if (!snp_active)
- valid_vmsa_features &= ~SVM_SEV_FEAT_SECURE_TSC;
+ valid_vmsa_features &= ~SVM_SEV_FEAT_SNP_ONLY_MASK;

if (data->vmsa_features & ~valid_vmsa_features)
return -EINVAL;
diff --git a/tools/testing/selftests/kvm/x86/sev_init2_tests.c b/tools/testing/selftests/kvm/x86/sev_init2_tests.c
index 7b0643bf7ca1..5f4032239f7f 100644
--- a/tools/testing/selftests/kvm/x86/sev_init2_tests.c
+++ b/tools/testing/selftests/kvm/x86/sev_init2_tests.c
@@ -14,16 +14,18 @@
#include "kselftest.h"

#define SVM_SEV_FEAT_DEBUG_SWAP BIT_ULL(5)
+#define SVM_SEV_FEAT_SECURE_TSC BIT_ULL(9)
+
+/* Features valid only for SNP guests, rejected for SEV-ES and below. */
+#define SNP_ONLY_FEATURES (SVM_SEV_FEAT_SECURE_TSC)

/*
* Some features may have hidden dependencies, or may only work
* for certain VM types. Err on the side of safety and don't
* expect that all supported features can be passed one by one
* to KVM_SEV_INIT2.
- *
- * (Well, right now there's only one...)
*/
-#define KNOWN_FEATURES SVM_SEV_FEAT_DEBUG_SWAP
+#define KNOWN_FEATURES (SVM_SEV_FEAT_DEBUG_SWAP | SNP_ONLY_FEATURES)

int kvm_fd;
u64 supported_vmsa_features;
@@ -112,7 +114,7 @@ void test_features(u32 vm_type, u64 supported_features)
if (!(supported_features & BIT_ULL(i)))
test_init2_invalid(vm_type,
&(struct kvm_sev_init){ .vmsa_features = BIT_ULL(i) },
- "unknown feature");
+ "unknown or unsupported feature for VM type");
else if (KNOWN_FEATURES & BIT_ULL(i))
test_init2(vm_type,
&(struct kvm_sev_init){ .vmsa_features = BIT_ULL(i) });
@@ -161,7 +163,7 @@ int main(int argc, char *argv[])

test_features(KVM_X86_SEV_VM, 0);
if (have_sev_es)
- test_features(KVM_X86_SEV_ES_VM, supported_vmsa_features);
+ test_features(KVM_X86_SEV_ES_VM, supported_vmsa_features & ~SNP_ONLY_FEATURES);
if (have_snp)
test_features(KVM_X86_SNP_VM, supported_vmsa_features);

--
2.43.0