Skip to content

Commit d1c371b

Browse files
chao-psean-jc
authored andcommitted
KVM: selftests: Expand set_memory_region_test to validate guest_memfd()
Expand set_memory_region_test to exercise various positive and negative testcases for private memory. - Non-guest_memfd() file descriptor for private memory - guest_memfd() from different VM - Overlapping bindings - Unaligned bindings Signed-off-by: Chao Peng <chao.p.peng@linux.intel.com> Co-developed-by: Ackerley Tng <ackerleytng@google.com> Signed-off-by: Ackerley Tng <ackerleytng@google.com> [sean: trim the testcases to remove duplicate coverage] Signed-off-by: Sean Christopherson <seanjc@google.com>
1 parent 2e896cd commit d1c371b

2 files changed

Lines changed: 110 additions & 0 deletions

File tree

tools/testing/selftests/kvm/include/kvm_util_base.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -819,6 +819,16 @@ static inline struct kvm_vm *vm_create_barebones(void)
819819
return ____vm_create(VM_SHAPE_DEFAULT);
820820
}
821821

822+
static inline struct kvm_vm *vm_create_barebones_protected_vm(void)
823+
{
824+
const struct vm_shape shape = {
825+
.mode = VM_MODE_DEFAULT,
826+
.type = KVM_X86_SW_PROTECTED_VM,
827+
};
828+
829+
return ____vm_create(shape);
830+
}
831+
822832
static inline struct kvm_vm *vm_create(uint32_t nr_runnable_vcpus)
823833
{
824834
return __vm_create(VM_SHAPE_DEFAULT, nr_runnable_vcpus, 0);

tools/testing/selftests/kvm/set_memory_region_test.c

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -385,6 +385,98 @@ static void test_add_max_memory_regions(void)
385385
kvm_vm_free(vm);
386386
}
387387

388+
389+
static void test_invalid_guest_memfd(struct kvm_vm *vm, int memfd,
390+
size_t offset, const char *msg)
391+
{
392+
int r = __vm_set_user_memory_region2(vm, MEM_REGION_SLOT, KVM_MEM_PRIVATE,
393+
MEM_REGION_GPA, MEM_REGION_SIZE,
394+
0, memfd, offset);
395+
TEST_ASSERT(r == -1 && errno == EINVAL, "%s", msg);
396+
}
397+
398+
static void test_add_private_memory_region(void)
399+
{
400+
struct kvm_vm *vm, *vm2;
401+
int memfd, i;
402+
403+
pr_info("Testing ADD of KVM_MEM_PRIVATE memory regions\n");
404+
405+
vm = vm_create_barebones_protected_vm();
406+
407+
test_invalid_guest_memfd(vm, vm->kvm_fd, 0, "KVM fd should fail");
408+
test_invalid_guest_memfd(vm, vm->fd, 0, "VM's fd should fail");
409+
410+
memfd = kvm_memfd_alloc(MEM_REGION_SIZE, false);
411+
test_invalid_guest_memfd(vm, memfd, 0, "Regular memfd() should fail");
412+
close(memfd);
413+
414+
vm2 = vm_create_barebones_protected_vm();
415+
memfd = vm_create_guest_memfd(vm2, MEM_REGION_SIZE, 0);
416+
test_invalid_guest_memfd(vm, memfd, 0, "Other VM's guest_memfd() should fail");
417+
418+
vm_set_user_memory_region2(vm2, MEM_REGION_SLOT, KVM_MEM_PRIVATE,
419+
MEM_REGION_GPA, MEM_REGION_SIZE, 0, memfd, 0);
420+
close(memfd);
421+
kvm_vm_free(vm2);
422+
423+
memfd = vm_create_guest_memfd(vm, MEM_REGION_SIZE, 0);
424+
for (i = 1; i < PAGE_SIZE; i++)
425+
test_invalid_guest_memfd(vm, memfd, i, "Unaligned offset should fail");
426+
427+
vm_set_user_memory_region2(vm, MEM_REGION_SLOT, KVM_MEM_PRIVATE,
428+
MEM_REGION_GPA, MEM_REGION_SIZE, 0, memfd, 0);
429+
close(memfd);
430+
431+
kvm_vm_free(vm);
432+
}
433+
434+
static void test_add_overlapping_private_memory_regions(void)
435+
{
436+
struct kvm_vm *vm;
437+
int memfd;
438+
int r;
439+
440+
pr_info("Testing ADD of overlapping KVM_MEM_PRIVATE memory regions\n");
441+
442+
vm = vm_create_barebones_protected_vm();
443+
444+
memfd = vm_create_guest_memfd(vm, MEM_REGION_SIZE * 4, 0);
445+
446+
vm_set_user_memory_region2(vm, MEM_REGION_SLOT, KVM_MEM_PRIVATE,
447+
MEM_REGION_GPA, MEM_REGION_SIZE * 2, 0, memfd, 0);
448+
449+
vm_set_user_memory_region2(vm, MEM_REGION_SLOT + 1, KVM_MEM_PRIVATE,
450+
MEM_REGION_GPA * 2, MEM_REGION_SIZE * 2,
451+
0, memfd, MEM_REGION_SIZE * 2);
452+
453+
/*
454+
* Delete the first memslot, and then attempt to recreate it except
455+
* with a "bad" offset that results in overlap in the guest_memfd().
456+
*/
457+
vm_set_user_memory_region2(vm, MEM_REGION_SLOT, KVM_MEM_PRIVATE,
458+
MEM_REGION_GPA, 0, NULL, -1, 0);
459+
460+
/* Overlap the front half of the other slot. */
461+
r = __vm_set_user_memory_region2(vm, MEM_REGION_SLOT, KVM_MEM_PRIVATE,
462+
MEM_REGION_GPA * 2 - MEM_REGION_SIZE,
463+
MEM_REGION_SIZE * 2,
464+
0, memfd, 0);
465+
TEST_ASSERT(r == -1 && errno == EEXIST, "%s",
466+
"Overlapping guest_memfd() bindings should fail with EEXIST");
467+
468+
/* And now the back half of the other slot. */
469+
r = __vm_set_user_memory_region2(vm, MEM_REGION_SLOT, KVM_MEM_PRIVATE,
470+
MEM_REGION_GPA * 2 + MEM_REGION_SIZE,
471+
MEM_REGION_SIZE * 2,
472+
0, memfd, 0);
473+
TEST_ASSERT(r == -1 && errno == EEXIST, "%s",
474+
"Overlapping guest_memfd() bindings should fail with EEXIST");
475+
476+
close(memfd);
477+
kvm_vm_free(vm);
478+
}
479+
388480
int main(int argc, char *argv[])
389481
{
390482
#ifdef __x86_64__
@@ -401,6 +493,14 @@ int main(int argc, char *argv[])
401493

402494
test_add_max_memory_regions();
403495

496+
if (kvm_has_cap(KVM_CAP_GUEST_MEMFD) &&
497+
(kvm_check_cap(KVM_CAP_VM_TYPES) & BIT(KVM_X86_SW_PROTECTED_VM))) {
498+
test_add_private_memory_region();
499+
test_add_overlapping_private_memory_regions();
500+
} else {
501+
pr_info("Skipping tests for KVM_MEM_PRIVATE memory regions\n");
502+
}
503+
404504
#ifdef __x86_64__
405505
if (argc > 1)
406506
loops = atoi_positive("Number of iterations", argv[1]);

0 commit comments

Comments
 (0)