diff options
author | Diego Nieto Cid <dnietoc@gmail.com> | 2025-09-21 21:23:42 +0100 |
---|---|---|
committer | Samuel Thibault <samuel.thibault@ens-lyon.org> | 2025-09-22 00:51:29 +0200 |
commit | 9ae4d99c1d1e7c9c0977cebb4df9b86fa92cca94 (patch) | |
tree | 62e1baaaefde974b943755eb8771ad0a2ca182f4 /tests | |
parent | 1269629d90b28a23ef9742645cfaf657ea3165bb (diff) |
* doc/mach.texi: add a "Memory Limitations" section to document the new interfaces.
* include/mach/gnumach.defs: (vm_set_size_limit) new routine
(vm_get_size_limit) likewise
* kern/task.c: (task_create_kernel) if parent_task is not null copy virtual memory limit
* tests/test-vm.c: (test_vm_limit) add test for the new routines
* vm/vm_map.h: (struct vm_map) new fields size_none, size_cur_limit and size_max_limit
(vm_map_find_entry) add new parameters cur_protection and max_protection
* vm/vm_map.c: (vm_map_setup) initialize new fields
(vm_map_enforce_limit) new function
(vm_map_copy_limits) new function
(vm_map_find_entry) add protection and max_protection parameters.
call limit enforcer function
(vm_map_enter) likewise
(vm_map_copyout) likewise
(vm_map_copyout_page_list) likewise
(vm_map_fork) copy parent limit to the new map and compute and set size_none of the new map
* vm/vm_user.c: (vm_set_size_limit) new function
(vm_get_size_limit) likewise
* xen/grant.c: update call to vm_map_find_entry to pass protection parameters
Message-ID: <0b71f4f89b7cc2b159893a805480d7493d522d60.1758485757.git.dnietoc@gmail.com>
Diffstat (limited to 'tests')
-rw-r--r-- | tests/test-vm.c | 96 |
1 files changed, 96 insertions, 0 deletions
diff --git a/tests/test-vm.c b/tests/test-vm.c index 4ece792e..466dba7e 100644 --- a/tests/test-vm.c +++ b/tests/test-vm.c @@ -75,11 +75,107 @@ static void test_wire() // TODO check that all memory is actually wired or unwired } +void test_vm_limit() +{ + kern_return_t err; + vm_address_t mem, mem2, mem3; + const size_t M_128K = 128l * 1024l; + const size_t M_128M = 128l * 1024l * 1024l; + const size_t M_512M = 512l * 1024l * 1024l; + vm_size_t cur; + vm_size_t max; + + printf("set VM memory limitations\n"); + err = vm_set_size_limit(mach_host_self(), mach_task_self(), M_128M, M_512M); + ASSERT_RET(err, "cannot set VM limits"); + + printf("check limits are actually saved\n"); + err = vm_get_size_limit(mach_task_self(), &cur, &max); + ASSERT_RET(err, "getting the VM limit failed"); + ASSERT(cur == M_128M, "cur limit was not expected"); + ASSERT(max == M_512M, "max limit was not expected"); + + printf("check we can no longer increase the max limit\n"); + err = vm_set_size_limit(mach_host_self(), mach_task_self(), M_128M, M_512M * 2); + ASSERT(err == KERN_NO_ACCESS, "raising VM max limit shall fail with KERN_NO_ACCESS"); + + printf("alloc some memory below the limit\n"); + err = vm_allocate(mach_task_self(), &mem, M_128K, TRUE); + ASSERT_RET(err, "allocating memory below the limit must succeed"); + err = vm_deallocate(mach_task_self(), mem, M_128K); + ASSERT_RET(err, "deallocation failed"); + + printf("alloc a bigger chunk to make it hit the limit\n"); + err = vm_allocate(mach_task_self(), &mem, (M_128M * 2), TRUE); + ASSERT(err == KERN_NO_SPACE, "allocation must fail with KERN_NO_SPACE"); + + printf("check that privileged tasks can increase the hard limit\n"); + err = vm_set_size_limit(host_priv(), mach_task_self(), (M_512M + M_128M), M_512M * 2); + ASSERT_RET(err, "privileged tasks shall be allowed to increase the max limit"); + + printf("check limits are actually saved\n"); + err = vm_get_size_limit(mach_task_self(), &cur, &max); + ASSERT_RET(err, "getting the VM limit failed"); + ASSERT(cur == (M_512M + M_128M), "cur limit was not expected"); + ASSERT(max == (M_512M * 2), "max limit was not expected"); + + printf("allocating the bigger chunk with the new limit shall succeed\n"); + err = vm_allocate(mach_task_self(), &mem, (M_128M * 2), TRUE); + ASSERT_RET(err, "allocation should now succedd"); + err = vm_deallocate(mach_task_self(), mem, (M_128M * 2)); + ASSERT_RET(err, "deallocation failed"); + + printf("check that the limit does not apply to VM_PROT_NONE mappings\n"); + err = vm_map(mach_task_self(), + &mem, (M_512M * 3), 0, 0, MACH_PORT_NULL, 0, 1, + VM_PROT_NONE, VM_PROT_NONE, VM_INHERIT_COPY); + ASSERT_RET(err, "allocation of VM_PROT_NONE areas should not be subject to the limit"); + + printf("check that the VM_PROT_NONE allocation does not reduce the limit\n"); + err = vm_allocate(mach_task_self(), &mem2, M_512M, TRUE); + ASSERT_RET(err, "allocation should succedd in spite of the VM_PROT_NONE map"); + err = vm_deallocate(mach_task_self(), mem2, M_512M); + ASSERT_RET(err, "deallocation failed"); + err = vm_deallocate(mach_task_self(), mem, (M_512M * 3)); + ASSERT_RET(err, "deallocation failed"); + + printf("check that allocations demoted to VM_PROT_NONE no longer counts towards the VM limit\n"); + err = vm_allocate(mach_task_self(), &mem, M_512M, TRUE); + ASSERT_RET(err, "allocating memory below the limit must succeed"); + err = vm_allocate(mach_task_self(), &mem2, M_128M, TRUE); + /* the current limit is M_512M + M_128M, this allocation should hit the limit */ + ASSERT(err == KERN_NO_SPACE, "allocation must fail with KERN_NO_SPACE"); + err = vm_protect(mach_task_self(), mem, M_512M, TRUE, VM_PROT_NONE); + ASSERT_RET(err, "could not drop protection to VM_PROT_NONE"); + /* after dropping the protection there should be enough space again */ + err = vm_allocate(mach_task_self(), &mem2, M_128M, TRUE); + ASSERT_RET(err, "allocating memory below the limit must succeed"); + /* this allocation purpose is showing the failure message to check size_none value */ + err = vm_allocate(mach_task_self(), &mem3, M_512M, TRUE); + ASSERT(err == KERN_NO_SPACE, "going above the limit should still fail"); + err = vm_deallocate(mach_task_self(), mem2, M_128M); + ASSERT_RET(err, "deallocation failed"); + err = vm_deallocate(mach_task_self(), mem, M_512M); + ASSERT_RET(err, "deallocation failed"); + + printf("check that protection cannot be upgraded from VM_PROT_NONE\n"); + err = vm_map(mach_task_self(), + &mem, M_512M, 0, 0, MACH_PORT_NULL, 0, 1, + VM_PROT_NONE, VM_PROT_NONE, VM_INHERIT_COPY); + ASSERT_RET(err, "allocation failed"); + /* attempt to broaden the access to the mapped memory */ + err = vm_protect(mach_task_self(), mem, M_512M, TRUE, VM_PROT_ALL); + ASSERT(err == KERN_PROTECTION_FAILURE, "max protection can only be set to strictier states"); + err = vm_deallocate(mach_task_self(), mem, M_512M); + ASSERT_RET(err, "deallocation failed"); +} + int main(int argc, char *argv[], int envc, char *envp[]) { printf("VM_MIN_ADDRESS=0x%p\n", VM_MIN_ADDRESS); printf("VM_MAX_ADDRESS=0x%p\n", VM_MAX_ADDRESS); test_wire(); test_memobj(); + test_vm_limit(); return 0; } |