summaryrefslogtreecommitdiff
path: root/tools/testing
diff options
context:
space:
mode:
authorPaolo Bonzini <pbonzini@redhat.com>2026-06-12 10:08:52 +0200
committerPaolo Bonzini <pbonzini@redhat.com>2026-06-12 10:08:52 +0200
commit06ba195f136a34f0a6e41f252002368d57875db9 (patch)
tree053ffcdfbc1d9430fdc19be88132a27b907a260b /tools/testing
parent4d37da77e657edc44eba33d57701b9b6ba058252 (diff)
parent48dbe473219832788c3940c84faa7f1df4375d5d (diff)
Merge tag 'kvm-x86-gmem-7.2' of https://github.com/kvm-x86/linux into HEAD
KVM guest_memfd changes for 7.2 - Return -EEXIST instead of -EINVAL if userspace attempts to bind a gmem range to multiple memslots, and fix the test that was supposed to ensure KVM returns -EEXIST. - Treat memslot binding offsets and sizes as unsigned values to fix a bug where KVM interprets a large "offset + size" as a negative value and allows a nonsensical offset. - Use the inode number instead of the page offset for the NUMA interleaving index to fix a bug where the effective index would jump by two for consecutive pages (the caller also adds in the page offset).
Diffstat (limited to 'tools/testing')
-rw-r--r--tools/testing/selftests/kvm/guest_memfd_test.c24
-rw-r--r--tools/testing/selftests/kvm/set_memory_region_test.c31
2 files changed, 49 insertions, 6 deletions
diff --git a/tools/testing/selftests/kvm/guest_memfd_test.c b/tools/testing/selftests/kvm/guest_memfd_test.c
index 832ef4dfb99f..2233d871a38f 100644
--- a/tools/testing/selftests/kvm/guest_memfd_test.c
+++ b/tools/testing/selftests/kvm/guest_memfd_test.c
@@ -345,6 +345,16 @@ static void test_invalid_punch_hole(int fd, size_t total_size)
}
}
+static void test_invalid_binding(struct kvm_vm *vm, int fd, size_t size)
+{
+ int r;
+
+ r = __vm_set_user_memory_region2(vm, 0, KVM_MEM_GUEST_MEMFD, 0, size, 0,
+ fd, ALIGN_DOWN(INT64_MAX, page_size));
+ TEST_ASSERT(r && errno == EINVAL,
+ "Memslot with out-of-range offset+size should fail");
+}
+
static void test_create_guest_memfd_invalid_sizes(struct kvm_vm *vm,
u64 guest_memfd_flags)
{
@@ -408,17 +418,26 @@ static void test_guest_memfd_flags(struct kvm_vm *vm)
}
}
-#define __gmem_test(__test, __vm, __flags, __gmem_size) \
+#define ____gmem_test(__test, __vm, __flags, __gmem_size, args...) \
do { \
int fd = vm_create_guest_memfd(__vm, __gmem_size, __flags); \
\
- test_##__test(fd, __gmem_size); \
+ test_##__test(args); \
close(fd); \
} while (0)
+#define __gmem_test(__test, __vm, __flags, __gmem_size) \
+ ____gmem_test(__test, __vm, __flags, __gmem_size, fd, __gmem_size)
+
#define gmem_test(__test, __vm, __flags) \
__gmem_test(__test, __vm, __flags, page_size * 4)
+#define __gmem_test_vm(__test, __vm, __flags, __gmem_size) \
+ ____gmem_test(__test, __vm, __flags, __gmem_size, __vm, fd, __gmem_size)
+
+#define gmem_test_vm(__test, __vm, __flags) \
+ __gmem_test_vm(__test, __vm, __flags, page_size * 4)
+
static void __test_guest_memfd(struct kvm_vm *vm, u64 flags)
{
test_create_guest_memfd_multiple(vm);
@@ -447,6 +466,7 @@ static void __test_guest_memfd(struct kvm_vm *vm, u64 flags)
gmem_test(file_size, vm, flags);
gmem_test(fallocate, vm, flags);
gmem_test(invalid_punch_hole, vm, flags);
+ gmem_test_vm(invalid_binding, vm, flags);
}
static void test_guest_memfd(unsigned long vm_type)
diff --git a/tools/testing/selftests/kvm/set_memory_region_test.c b/tools/testing/selftests/kvm/set_memory_region_test.c
index e639a9db51ee..a152ab65c657 100644
--- a/tools/testing/selftests/kvm/set_memory_region_test.c
+++ b/tools/testing/selftests/kvm/set_memory_region_test.c
@@ -510,7 +510,7 @@ static void test_add_overlapping_private_memory_regions(void)
vm = vm_create_barebones_type(KVM_X86_SW_PROTECTED_VM);
- memfd = vm_create_guest_memfd(vm, MEM_REGION_SIZE * 4, 0);
+ memfd = vm_create_guest_memfd(vm, MEM_REGION_SIZE * 5, 0);
vm_set_user_memory_region2(vm, MEM_REGION_SLOT, KVM_MEM_GUEST_MEMFD,
MEM_REGION_GPA, MEM_REGION_SIZE * 2, 0, memfd, 0);
@@ -526,12 +526,35 @@ static void test_add_overlapping_private_memory_regions(void)
vm_set_user_memory_region2(vm, MEM_REGION_SLOT, KVM_MEM_GUEST_MEMFD,
MEM_REGION_GPA, 0, NULL, -1, 0);
- /* Overlap the front half of the other slot. */
+ /*
+ * Verify that overlap in the guest_memfd bindings (i.e. in guest_memfd
+ * file offsets), but _not_ in the GPA space, fails with -EEXIST.
+ */
+ r = __vm_set_user_memory_region2(vm, MEM_REGION_SLOT, KVM_MEM_GUEST_MEMFD,
+ MEM_REGION_GPA,
+ MEM_REGION_SIZE * 2,
+ 0, memfd, MEM_REGION_SIZE);
+ TEST_ASSERT(r == -1 && errno == EEXIST,
+ "Overlapping guest_memfd() bindings should fail with EEXIST");
+
+ /* And now the back half of the other slot's guest_memfd binding. */
+ r = __vm_set_user_memory_region2(vm, MEM_REGION_SLOT, KVM_MEM_GUEST_MEMFD,
+ MEM_REGION_GPA,
+ MEM_REGION_SIZE * 2,
+ 0, memfd, MEM_REGION_SIZE * 3);
+ TEST_ASSERT(r == -1 && errno == EEXIST,
+ "Overlapping guest_memfd() bindings should fail with EEXIST");
+
+ /*
+ * Repeat the overlap tests, but this time with overlap in the memslots
+ * GPA space. Regardless of where there is overlap, KVM should return
+ * -EEXIST.
+ */
r = __vm_set_user_memory_region2(vm, MEM_REGION_SLOT, KVM_MEM_GUEST_MEMFD,
MEM_REGION_GPA * 2 - MEM_REGION_SIZE,
MEM_REGION_SIZE * 2,
0, memfd, 0);
- TEST_ASSERT(r == -1 && errno == EEXIST, "%s",
+ TEST_ASSERT(r == -1 && errno == EEXIST,
"Overlapping guest_memfd() bindings should fail with EEXIST");
/* And now the back half of the other slot. */
@@ -539,7 +562,7 @@ static void test_add_overlapping_private_memory_regions(void)
MEM_REGION_GPA * 2 + MEM_REGION_SIZE,
MEM_REGION_SIZE * 2,
0, memfd, 0);
- TEST_ASSERT(r == -1 && errno == EEXIST, "%s",
+ TEST_ASSERT(r == -1 && errno == EEXIST,
"Overlapping guest_memfd() bindings should fail with EEXIST");
close(memfd);