@@ -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+
388480int 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