* [PATCH v2 1/2] KVM: selftests: SEV: Verify unsupported VM types are rejected at creation
2026-07-09 17:49 ` [PATCH v2 0/2] KVM: selftests: SEV: address two TODOs in the SEV tests Hemanth Selam
@ 2026-07-09 17:49 ` Hemanth Selam
2026-07-09 20:21 ` Sean Christopherson
2026-07-10 5:06 ` Hemanth Selam
2026-07-09 17:49 ` [PATCH v2 2/2] KVM: selftests: SEV: Sanity check the launch measurement Hemanth Selam
2026-07-10 5:04 ` [PATCH v3] KVM: selftests: Add a test for KVM_CREATE_VM VM type enforcement Hemanth Selam
2 siblings, 2 replies; 9+ messages in thread
From: Hemanth Selam @ 2026-07-09 17:49 UTC (permalink / raw)
To: seanjc, pbonzini, shuah; +Cc: kvm, linux-kselftest, linux-kernel, Hemanth Selam
test_vm_types() only exercised creation of the SEV/SEV-ES/SEV-SNP VM
types that the platform actually supports, leaving the previously noted
TODO ("check that unsupported types cannot be created") unaddressed.
Add test_create_invalid_type() which issues a raw KVM_CREATE_VM for a
given type and asserts it fails with -EINVAL, and invoke it for
KVM_X86_SEV_ES_VM / KVM_X86_SNP_VM whenever the corresponding capability
is not advertised. Because vm_create_barebones_type() asserts that
KVM_CREATE_VM succeeds, the check is issued directly against the KVM fd
so the negative path can be observed.
TEST_ASSERT() aborts the program when its condition fails, so the helper
releases the fd and latches errno before asserting: if KVM_CREATE_VM
ever wrongly succeeds, the VM fd is closed rather than leaked, and errno
is captured before close() can clobber it.
While here, stop shadowing the file-scope kvm_fd with a local in main()
so the new helper can use it.
Signed-off-by: Hemanth Selam <hemanth.selam@gmail.com>
---
.../selftests/kvm/x86/sev_init2_tests.c | 27 +++++++++++++++----
1 file changed, 22 insertions(+), 5 deletions(-)
diff --git a/tools/testing/selftests/kvm/x86/sev_init2_tests.c b/tools/testing/selftests/kvm/x86/sev_init2_tests.c
index 8db88c355f16..7663418b3fa8 100644
--- a/tools/testing/selftests/kvm/x86/sev_init2_tests.c
+++ b/tools/testing/selftests/kvm/x86/sev_init2_tests.c
@@ -6,6 +6,7 @@
#include <stdlib.h>
#include <errno.h>
#include <pthread.h>
+#include <unistd.h>
#include "test_util.h"
#include "kvm_util.h"
@@ -73,19 +74,34 @@ static void test_init2_invalid(unsigned long vm_type, struct kvm_sev_init *init,
kvm_vm_free(vm);
}
+static void test_create_invalid_type(unsigned long vm_type, const char *msg)
+{
+ int fd = __kvm_ioctl(kvm_fd, KVM_CREATE_VM, (void *)vm_type);
+ int err = errno;
+
+ /* Clean up before asserting; TEST_ASSERT() aborts on failure. */
+ if (fd >= 0)
+ close(fd);
+
+ TEST_ASSERT(fd < 0 && err == EINVAL,
+ "KVM_CREATE_VM should reject unsupported type (%s), got fd=%d errno=%d",
+ msg, fd, err);
+}
+
void test_vm_types(void)
{
test_init2(KVM_X86_SEV_VM, &(struct kvm_sev_init){});
- /*
- * TODO: check that unsupported types cannot be created. Probably
- * a separate selftest.
- */
+ /* Unsupported types must be rejected by KVM_CREATE_VM itself. */
if (have_sev_es)
test_init2(KVM_X86_SEV_ES_VM, &(struct kvm_sev_init){});
+ else
+ test_create_invalid_type(KVM_X86_SEV_ES_VM, "SEV-ES is unsupported");
if (have_snp)
test_init2(KVM_X86_SNP_VM, &(struct kvm_sev_init){});
+ else
+ test_create_invalid_type(KVM_X86_SNP_VM, "SEV-SNP is unsupported");
test_init2_invalid(0, &(struct kvm_sev_init){},
"VM type is KVM_X86_DEFAULT_VM");
@@ -121,9 +137,10 @@ void test_features(u32 vm_type, u64 supported_features)
int main(int argc, char *argv[])
{
- int kvm_fd = open_kvm_dev_path_or_exit();
bool have_sev;
+ kvm_fd = open_kvm_dev_path_or_exit();
+
TEST_REQUIRE(__kvm_has_device_attr(kvm_fd, KVM_X86_GRP_SEV,
KVM_X86_SEV_VMSA_FEATURES) == 0);
kvm_device_attr_get(kvm_fd, KVM_X86_GRP_SEV,
--
2.43.7
^ permalink raw reply related [flat|nested] 9+ messages in thread* Re: [PATCH v2 1/2] KVM: selftests: SEV: Verify unsupported VM types are rejected at creation
2026-07-09 17:49 ` [PATCH v2 1/2] KVM: selftests: SEV: Verify unsupported VM types are rejected at creation Hemanth Selam
@ 2026-07-09 20:21 ` Sean Christopherson
2026-07-10 5:06 ` Hemanth Selam
1 sibling, 0 replies; 9+ messages in thread
From: Sean Christopherson @ 2026-07-09 20:21 UTC (permalink / raw)
To: Hemanth Selam; +Cc: pbonzini, shuah, kvm, linux-kselftest, linux-kernel
On Thu, Jul 09, 2026, Hemanth Selam wrote:
> @@ -73,19 +74,34 @@ static void test_init2_invalid(unsigned long vm_type, struct kvm_sev_init *init,
> kvm_vm_free(vm);
> }
>
> +static void test_create_invalid_type(unsigned long vm_type, const char *msg)
> +{
> + int fd = __kvm_ioctl(kvm_fd, KVM_CREATE_VM, (void *)vm_type);
> + int err = errno;
> +
> + /* Clean up before asserting; TEST_ASSERT() aborts on failure. */
Literally every test relies on the kernel to clean up fds on an early exit. I
see no reason for this to behave differently.
Also, Sashiko was wrong. If KVM_CREATE_VM fails with something other than EINVAL,
the assert will NOT fire, but fd will be < 0.
> + if (fd >= 0)
> + close(fd);
> +
> + TEST_ASSERT(fd < 0 && err == EINVAL,
> + "KVM_CREATE_VM should reject unsupported type (%s), got fd=%d errno=%d",
> + msg, fd, err);
test_assert logs the errno, no need to spit it out here as well.
> +}
> +
> void test_vm_types(void)
> {
> test_init2(KVM_X86_SEV_VM, &(struct kvm_sev_init){});
>
> - /*
> - * TODO: check that unsupported types cannot be created. Probably
> - * a separate selftest.
Heh, I agree with the comment: put this in a separate selftest. This doesn't
have anything to do with KVM_SEV_INIT2, and in fact doesn't even have anyting to
do with SEV+ or even x86. E.g. add a kvm_vm_types_test that attempts to create
all possible VM types, and asserts success/failure based on the output from
kvm_check_cap(KVM_CAP_VM_TYPES).
^ permalink raw reply [flat|nested] 9+ messages in thread* Re: [PATCH v2 1/2] KVM: selftests: SEV: Verify unsupported VM types are rejected at creation
2026-07-09 17:49 ` [PATCH v2 1/2] KVM: selftests: SEV: Verify unsupported VM types are rejected at creation Hemanth Selam
2026-07-09 20:21 ` Sean Christopherson
@ 2026-07-10 5:06 ` Hemanth Selam
1 sibling, 0 replies; 9+ messages in thread
From: Hemanth Selam @ 2026-07-10 5:06 UTC (permalink / raw)
To: seanjc; +Cc: pbonzini, shuah, kvm, linux-kselftest, linux-kernel,
Hemanth Selam
On Thu, Jul 09, 2026, Sean Christopherson wrote:
> Literally every test relies on the kernel to clean up fds on an early
> exit. I see no reason for this to behave differently.
>
> Also, Sashiko was wrong. If KVM_CREATE_VM fails with something other
> than EINVAL, the assert will NOT fire, but fd will be < 0.
Agreed on both; dropped the manual close() and the errno latching.
> test_assert logs the errno, no need to spit it out here as well.
Removed.
> Heh, I agree with the comment: put this in a separate selftest. This
> doesn't have anything to do with KVM_SEV_INIT2, and in fact doesn't
> even have anyting to do with SEV+ or even x86. E.g. add a
> kvm_vm_types_test that attempts to create all possible VM types, and
> asserts success/failure based on the output from
> kvm_check_cap(KVM_CAP_VM_TYPES).
Done. v3 drops the sev_init2_tests changes and adds a standalone,
arch-generic test that walks all type values (including out-of-range
ones) and asserts KVM_CREATE_VM success/failure against
KVM_CAP_VM_TYPES:
https://lore.kernel.org/all/20260710050442.826777-1-hemanth.selam@gmail.com/
I also dropped the "SEV: Sanity check the launch measurement" patch for
now; v3 is just the VM-types test.
Thanks for the review!
Hemanth
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v2 2/2] KVM: selftests: SEV: Sanity check the launch measurement
2026-07-09 17:49 ` [PATCH v2 0/2] KVM: selftests: SEV: address two TODOs in the SEV tests Hemanth Selam
2026-07-09 17:49 ` [PATCH v2 1/2] KVM: selftests: SEV: Verify unsupported VM types are rejected at creation Hemanth Selam
@ 2026-07-09 17:49 ` Hemanth Selam
2026-07-10 5:04 ` [PATCH v3] KVM: selftests: Add a test for KVM_CREATE_VM VM type enforcement Hemanth Selam
2 siblings, 0 replies; 9+ messages in thread
From: Hemanth Selam @ 2026-07-09 17:49 UTC (permalink / raw)
To: seanjc, pbonzini, shuah; +Cc: kvm, linux-kselftest, linux-kernel, Hemanth Selam
test_sev() launched the guest while discarding the launch measurement
and left a TODO to validate it. A full attestation-style validation is
not possible from the selftest because userspace does not possess the
transport keys the PSP uses to derive the measurement, so recomputing
the expected value cannot be done here.
Capture the measurement returned by KVM_SEV_LAUNCH_MEASURE for SEV and
SEV-ES guests and assert that it is not all zeros, which catches a PSP
or plumbing failure that silently leaves the buffer untouched. SNP does
not return a measurement through this path, so it is skipped.
Signed-off-by: Hemanth Selam <hemanth.selam@gmail.com>
---
.../selftests/kvm/x86/sev_smoke_test.c | 23 +++++++++++++++++--
1 file changed, 21 insertions(+), 2 deletions(-)
diff --git a/tools/testing/selftests/kvm/x86/sev_smoke_test.c b/tools/testing/selftests/kvm/x86/sev_smoke_test.c
index 6b2cbe2a90b7..9ce465b4a770 100644
--- a/tools/testing/selftests/kvm/x86/sev_smoke_test.c
+++ b/tools/testing/selftests/kvm/x86/sev_smoke_test.c
@@ -150,16 +150,35 @@ static void test_sync_vmsa(u32 type, u64 policy)
kvm_vm_free(vm);
}
+static bool is_measurement_nonzero(const u8 *measurement, size_t len)
+{
+ size_t i;
+
+ for (i = 0; i < len; i++)
+ if (measurement[i])
+ return true;
+
+ return false;
+}
+
static void test_sev(void *guest_code, u32 type, u64 policy)
{
+ u8 measurement[256];
struct kvm_vcpu *vcpu;
struct kvm_vm *vm;
struct ucall uc;
vm = vm_sev_create_with_one_vcpu(type, guest_code, &vcpu);
- /* TODO: Validate the measurement is as expected. */
- vm_sev_launch(vm, policy, NULL);
+ /* Sanity check the measurement; SNP has no measurement here. */
+ if (is_sev_snp_vm(vm)) {
+ vm_sev_launch(vm, policy, NULL);
+ } else {
+ memset(measurement, 0, sizeof(measurement));
+ vm_sev_launch(vm, policy, measurement);
+ TEST_ASSERT(is_measurement_nonzero(measurement, sizeof(measurement)),
+ "SEV launch measurement is unexpectedly all zeros");
+ }
for (;;) {
vcpu_run(vcpu);
--
2.43.7
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH v3] KVM: selftests: Add a test for KVM_CREATE_VM VM type enforcement
2026-07-09 17:49 ` [PATCH v2 0/2] KVM: selftests: SEV: address two TODOs in the SEV tests Hemanth Selam
2026-07-09 17:49 ` [PATCH v2 1/2] KVM: selftests: SEV: Verify unsupported VM types are rejected at creation Hemanth Selam
2026-07-09 17:49 ` [PATCH v2 2/2] KVM: selftests: SEV: Sanity check the launch measurement Hemanth Selam
@ 2026-07-10 5:04 ` Hemanth Selam
2 siblings, 0 replies; 9+ messages in thread
From: Hemanth Selam @ 2026-07-10 5:04 UTC (permalink / raw)
To: seanjc, pbonzini, shuah; +Cc: kvm, linux-kselftest, linux-kernel, Hemanth Selam
KVM_CAP_VM_TYPES advertises the bitmap of VM types that KVM_CREATE_VM
accepts, but nothing verified that the ioctl actually enforces it: that
every advertised type can be created and every non-advertised type is
rejected. sev_init2_tests carried a TODO for this ("check that
unsupported types cannot be created. Probably a separate selftest"),
but the check is not specific to SEV or KVM_SEV_INIT2, and not even to
x86.
Add a standalone test that walks the type space and, for each value,
asserts that KVM_CREATE_VM succeeds iff the corresponding bit is set in
KVM_CAP_VM_TYPES, and otherwise fails with -EINVAL. The walk extends
past bit 31 so that out-of-range type values, which can never be
advertised in the u32 bitmap, are also confirmed to be rejected. The
test only depends on KVM_CAP_VM_TYPES, so it lives in the common set and
is skipped on architectures that don't advertise the capability.
Drop the now-addressed TODO from sev_init2_tests.c.
Tested on an AMD SEV-SNP capable host. With KVM_CAP_VM_TYPES=0x15
(DEFAULT/SEV/SNP), only the advertised types are created and everything
else is rejected:
$ strace -e trace=ioctl ./vm_types_test 2>&1 | grep KVM_CREATE_VM
ioctl(3, KVM_CREATE_VM, 0) = 4 # DEFAULT
ioctl(3, KVM_CREATE_VM, 0x1) = -1 EINVAL # SW_PROTECTED
ioctl(3, KVM_CREATE_VM, 0x2) = 4 # SEV
ioctl(3, KVM_CREATE_VM, 0x3) = -1 EINVAL # SEV-ES
ioctl(3, KVM_CREATE_VM, 0x4) = 4 # SNP
ioctl(3, KVM_CREATE_VM, 0x5) = -1 EINVAL # TDX
... 0x6..0x3f all -1 EINVAL ...
Reloading kvm_amd with sev_snp=0 drops the bitmap to 0x5 and only types
0 and 2 are then created, confirming the test tracks the advertised set
rather than hard-coded types.
Signed-off-by: Hemanth Selam <hemanth.selam@gmail.com>
---
Changes in v3:
- Reworked into a separate, generic test that checks all VM types
against KVM_CAP_VM_TYPES (per review), instead of adding negative
checks to sev_init2_tests; also cover out-of-range types. Dropped the
manual fd cleanup and the redundant errno in the assert message, and
removed the addressed TODO from sev_init2_tests.c.
- Dropped the separate "SEV: Sanity check the launch measurement" patch
that accompanied v1/v2; this revision is a single patch.
v2: https://lore.kernel.org/all/20260709174955.628913-1-hemanth.selam@gmail.com/
v1: https://lore.kernel.org/all/20260709164751.621326-1-hemanth.selam@gmail.com/
tools/testing/selftests/kvm/Makefile.kvm | 1 +
tools/testing/selftests/kvm/vm_types_test.c | 50 +++++++++++++++++++
.../selftests/kvm/x86/sev_init2_tests.c | 4 --
3 files changed, 51 insertions(+), 4 deletions(-)
create mode 100644 tools/testing/selftests/kvm/vm_types_test.c
diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selftests/kvm/Makefile.kvm
index d28a057fa6c2..ad74d0b98694 100644
--- a/tools/testing/selftests/kvm/Makefile.kvm
+++ b/tools/testing/selftests/kvm/Makefile.kvm
@@ -66,6 +66,7 @@ TEST_GEN_PROGS_COMMON += kvm_page_table_test
TEST_GEN_PROGS_COMMON += set_memory_region_test
TEST_GEN_PROGS_COMMON += memslot_modification_stress_test
TEST_GEN_PROGS_COMMON += memslot_perf_test
+TEST_GEN_PROGS_COMMON += vm_types_test
# Compiled test targets
TEST_GEN_PROGS_x86 = $(TEST_GEN_PROGS_COMMON)
diff --git a/tools/testing/selftests/kvm/vm_types_test.c b/tools/testing/selftests/kvm/vm_types_test.c
new file mode 100644
index 000000000000..e8ef3b018f6c
--- /dev/null
+++ b/tools/testing/selftests/kvm/vm_types_test.c
@@ -0,0 +1,50 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Verify that KVM_CREATE_VM accepts exactly the VM types enumerated by
+ * KVM_CAP_VM_TYPES, and rejects every other type with -EINVAL.
+ */
+#include <errno.h>
+#include <stdbool.h>
+#include <unistd.h>
+
+#include <linux/kvm.h>
+
+#include "kvm_util.h"
+#include "test_util.h"
+
+int main(void)
+{
+ unsigned int supported_types;
+ unsigned long type;
+ int kvm_fd, fd;
+
+ TEST_REQUIRE(kvm_has_cap(KVM_CAP_VM_TYPES));
+
+ kvm_fd = open_kvm_dev_path_or_exit();
+ supported_types = kvm_check_cap(KVM_CAP_VM_TYPES);
+ pr_info("KVM_CAP_VM_TYPES: 0x%x\n", supported_types);
+
+ /*
+ * KVM_CAP_VM_TYPES is a u32 bitmap, so only types 0..31 can ever be
+ * advertised. Walk past that range as well to confirm that any
+ * out-of-range type is rejected rather than silently accepted.
+ */
+ for (type = 0; type < 64; type++) {
+ bool supported = type < 32 && (supported_types & (1U << type));
+
+ fd = __kvm_ioctl(kvm_fd, KVM_CREATE_VM, (void *)type);
+
+ if (supported) {
+ TEST_ASSERT(fd >= 0,
+ "KVM_CREATE_VM(%lu) should succeed, KVM_CAP_VM_TYPES=0x%x",
+ type, supported_types);
+ close(fd);
+ } else {
+ TEST_ASSERT(fd < 0 && errno == EINVAL,
+ "KVM_CREATE_VM(%lu) should fail with EINVAL, KVM_CAP_VM_TYPES=0x%x",
+ type, supported_types);
+ }
+ }
+
+ return 0;
+}
diff --git a/tools/testing/selftests/kvm/x86/sev_init2_tests.c b/tools/testing/selftests/kvm/x86/sev_init2_tests.c
index 8db88c355f16..d4227dc922ab 100644
--- a/tools/testing/selftests/kvm/x86/sev_init2_tests.c
+++ b/tools/testing/selftests/kvm/x86/sev_init2_tests.c
@@ -77,10 +77,6 @@ void test_vm_types(void)
{
test_init2(KVM_X86_SEV_VM, &(struct kvm_sev_init){});
- /*
- * TODO: check that unsupported types cannot be created. Probably
- * a separate selftest.
- */
if (have_sev_es)
test_init2(KVM_X86_SEV_ES_VM, &(struct kvm_sev_init){});
--
2.43.7
^ permalink raw reply related [flat|nested] 9+ messages in thread