Applied, thanks! [email protected], le dim. 21 sept. 2025 21:23:42 +0100, a ecrit: > From: Diego Nieto Cid <[email protected]> > > * 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 > --- > doc/mach.texi | 29 ++++++++ > include/mach/gnumach.defs | 34 +++++++++ > kern/task.c | 5 ++ > tests/test-vm.c | 96 +++++++++++++++++++++++++ > vm/vm_kern.c | 22 +++--- > vm/vm_map.c | 148 +++++++++++++++++++++++++++++++++++--- > vm/vm_map.h | 15 +++- > vm/vm_user.c | 69 ++++++++++++++++++ > xen/grant.c | 3 +- > 9 files changed, 400 insertions(+), 21 deletions(-) > > diff --git a/doc/mach.texi b/doc/mach.texi > index e2328c1b..1f28cea3 100644 > --- a/doc/mach.texi > +++ b/doc/mach.texi > @@ -203,6 +203,7 @@ Virtual Memory Interface > * Data Transfer:: Reading, writing and copying memory. > * Memory Attributes:: Tweaking memory regions. > * Mapping Memory Objects:: How to map memory objects. > +* Memory Limitations:: Tweaking virtual memory space limts. > * Memory Statistics:: How to get statistics about memory usage. > > External Memory Management > @@ -3029,6 +3030,7 @@ the kernel. > * Data Transfer:: Reading, writing and copying memory. > * Memory Attributes:: Tweaking memory regions. > * Mapping Memory Objects:: How to map memory objects. > +* Memory Limitations:: Tweaking virtual memory limits. > * Memory Statistics:: How to get statistics about memory usage. > * Memory physical addresses:: How to get physical addresses of memory. > @end menu > @@ -3476,6 +3478,33 @@ found, and @code{KERN_INVALID_ARGUMENT} if an invalid > argument was provided. > @end deftypefun > > > +@node Memory Limitations > +@section Memory Limitations > + > +@deftypefun kern_reutrn_t vm_get_size_limit (@w{vm_task_t @var{map}}, > @w{vm_size_t *@var{current_limit}}, @w{vm_size_t *@var{max_limit}}) > +This function will return the current limit and the maximum limit of the > +virtual memory address space of the task indicated by the @var{map} argument > +in the parameters @var{current_limit} and @var{max_limit}, respectively. > +@end deftypefun > + > +@deftypefun kern_return_t vm_set_size_limit (@w{mach_port_t > @var{host_port}}, @w{vm_task_t @var{map}}, @w{vm_size_t @var{current_limit}}, > @w{vm_size_t @var{max_limit}}) > +This function shall be used to update the virtual address space limits > +of the task given by the @var{map} argument. > + > +If the value of the argument @var{current_limit} is greater than > @var{max_limit}, > +the function returns @code{KERN_INVALID_ARGUMENT}. The privileged host port > +must be provided in the @var{host_port} argument when the function is used > +to increase the current max limit of the address space. Otherwise the > function > +returns @code{KERN_NO_ACCESS}. > + > +The function returns @code{KERN_INVALID_TASK} or @code{KERN_INVALID_HOST} > when > +the arguments @var{map} and @var{host_port} are not a vlaid task or host, > respectively. > + > +@code{KERN_SUCCESS} is returned when the map limits could be updated > +successfuly. > +@end deftypefun > + > + > @node Memory Statistics > @section Memory Statistics > > diff --git a/include/mach/gnumach.defs b/include/mach/gnumach.defs > index f13e866b..f5b2f7f2 100644 > --- a/include/mach/gnumach.defs > +++ b/include/mach/gnumach.defs > @@ -223,3 +223,37 @@ simpleroutine thread_set_name( > routine thread_get_name( > thread : thread_t; > out name : kernel_debug_name_t); > + > +/* > + * Set a task virtual memory limit parameters > + * > + * HOST_PORT must be the privileged host control port > + * if the caller desires to increase the current max limit. > + * > + * On the other hand, if the max limit is being decreased, the > + * unprivileged host control port (as returned by mach_host_self()) > + * can be provided. > + * > + * Returns: > + * - KERN_SUCCESS > + * - KERN_INVALID_TASK > + * - KERN_INVALID_HOST > + * - KERN_INVALID_ARGUMENT > + * * when current_limit > max_limit > + * - KERN_NO_ACCESS > + * * attempt to increase max limit without providing > + * the privileged host control port. > + */ > +routine vm_set_size_limit( > + host_port : mach_port_t; > + map : vm_task_t; > + current_limit : vm_size_t; > + max_limit : vm_size_t); > + > +/* > + * Get a task virtual memory limit parameters > + */ > +routine vm_get_size_limit( > + map : vm_task_t; > + out current_limit : vm_size_t; > + out max_limit : vm_size_t); > diff --git a/kern/task.c b/kern/task.c > index bd57ca2a..e78e856f 100644 > --- a/kern/task.c > +++ b/kern/task.c > @@ -126,6 +126,11 @@ task_create_kernel( > trunc_page(VM_MAX_USER_ADDRESS)); > if (new_task->map == VM_MAP_NULL) > pmap_destroy(new_pmap); > + else if (parent_task != TASK_NULL) { > + vm_map_lock_read(parent_task->map); > + vm_map_copy_limits(new_task->map, > parent_task->map); > + vm_map_unlock_read(parent_task->map); > + } > } > } > if (new_task->map == VM_MAP_NULL) { > 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; > } > diff --git a/vm/vm_kern.c b/vm/vm_kern.c > index 51223d98..37185687 100644 > --- a/vm/vm_kern.c > +++ b/vm/vm_kern.c > @@ -108,7 +108,8 @@ projected_buffer_allocate( > > vm_map_lock(kernel_map); > kr = vm_map_find_entry(kernel_map, &addr, size, (vm_offset_t) 0, > - VM_OBJECT_NULL, &k_entry); > + VM_OBJECT_NULL, &k_entry, > + VM_PROT_DEFAULT, VM_PROT_ALL); > if (kr != KERN_SUCCESS) { > vm_map_unlock(kernel_map); > vm_object_deallocate(object); > @@ -125,7 +126,8 @@ projected_buffer_allocate( > > vm_map_lock(map); > kr = vm_map_find_entry(map, &addr, size, (vm_offset_t) 0, > - VM_OBJECT_NULL, &u_entry); > + VM_OBJECT_NULL, &u_entry, > + protection, protection); > if (kr != KERN_SUCCESS) { > vm_map_unlock(map); > vm_map_lock(kernel_map); > @@ -141,8 +143,6 @@ projected_buffer_allocate( > /*Creates coupling with kernel mapping of the buffer, and > also guarantees that user cannot directly manipulate > buffer VM entry*/ > - u_entry->protection = protection; > - u_entry->max_protection = protection; > u_entry->inheritance = inheritance; > vm_map_unlock(map); > *user_p = addr; > @@ -209,7 +209,8 @@ projected_buffer_map( > > vm_map_lock(map); > kr = vm_map_find_entry(map, &user_addr, size, (vm_offset_t) 0, > - VM_OBJECT_NULL, &u_entry); > + VM_OBJECT_NULL, &u_entry, > + protection, protection); > if (kr != KERN_SUCCESS) { > vm_map_unlock(map); > return kr; > @@ -222,8 +223,6 @@ projected_buffer_map( > /*Creates coupling with kernel mapping of the buffer, and > also guarantees that user cannot directly manipulate > buffer VM entry*/ > - u_entry->protection = protection; > - u_entry->max_protection = protection; > u_entry->inheritance = inheritance; > u_entry->wired_count = k_entry->wired_count; > vm_map_unlock(map); > @@ -393,7 +392,8 @@ kmem_alloc( > retry: > vm_map_lock(map); > kr = vm_map_find_entry(map, &addr, size, (vm_offset_t) 0, > - VM_OBJECT_NULL, &entry); > + VM_OBJECT_NULL, &entry, > + VM_PROT_DEFAULT, VM_PROT_ALL); > if (kr != KERN_SUCCESS) { > vm_map_unlock(map); > > @@ -465,7 +465,8 @@ kmem_valloc( > retry: > vm_map_lock(map); > kr = vm_map_find_entry(map, &addr, size, (vm_offset_t) 0, > - kernel_object, &entry); > + kernel_object, &entry, > + VM_PROT_DEFAULT, VM_PROT_ALL); > if (kr != KERN_SUCCESS) { > vm_map_unlock(map); > > @@ -585,7 +586,8 @@ kmem_alloc_aligned( > retry: > vm_map_lock(map); > kr = vm_map_find_entry(map, &addr, size, size - 1, > - kernel_object, &entry); > + kernel_object, &entry, > + VM_PROT_DEFAULT, VM_PROT_ALL); > if (kr != KERN_SUCCESS) { > vm_map_unlock(map); > > diff --git a/vm/vm_map.c b/vm/vm_map.c > index e1f8af9e..ff466d35 100644 > --- a/vm/vm_map.c > +++ b/vm/vm_map.c > @@ -189,6 +189,7 @@ void vm_map_setup( > > map->size = 0; > map->size_wired = 0; > + map->size_none = 0; > map->ref_count = 1; > map->pmap = pmap; > map->min_offset = min; > @@ -198,6 +199,14 @@ void vm_map_setup( > map->first_free = vm_map_to_entry(map); > map->hint = vm_map_to_entry(map); > map->name = NULL; > + /* TODO add to default limit the swap size */ > + if (pmap != kernel_pmap) { > + map->size_cur_limit = vm_page_mem_size() / 2; > + map->size_max_limit = vm_page_mem_size() / 2; > + } else { > + map->size_cur_limit = (~0UL); > + map->size_max_limit = (~0UL); > + } > vm_map_lock_init(map); > simple_lock_init(&map->ref_lock); > simple_lock_init(&map->hint_lock); > @@ -268,6 +277,46 @@ void vm_map_unlock(struct vm_map *map) > lock_write_done(&map->lock); > } > > +/* > + * Enforces the VM limit of a target map. > + */ > +static kern_return_t > +vm_map_enforce_limit( > + vm_map_t map, > + vm_size_t size, > + const char *fn_name) > +{ > + /* Limit is ignored for the kernel map */ > + if (vm_map_pmap(map) == kernel_pmap) { > + return KERN_SUCCESS; > + } > + > + /* Avoid taking into account the total VM_PROT_NONE virtual memory */ > + vm_size_t really_allocated_size = map->size - map->size_none; > + vm_size_t new_size = really_allocated_size + size; > + /* Check for integer overflow */ > + if (new_size < size) { > + return KERN_INVALID_ARGUMENT; > + } > + > + if (new_size > map->size_cur_limit) { > + return KERN_NO_SPACE; > + } > + > + return KERN_SUCCESS; > +} > + > +/* > + * Copies the limits from source to destination map. > + * Called by task_create_kernel with the src_map locked. > + */ > +void > +vm_map_copy_limits(vm_map_t dst_map, vm_map_t src_map) > +{ > + dst_map->size_cur_limit = src_map->size_cur_limit; > + dst_map->size_max_limit = src_map->size_max_limit; > +} > + > /* > * vm_map_entry_create: [ internal use only ] > * > @@ -779,6 +828,21 @@ error: > * If an entry is allocated, the object/offset fields > * are initialized to zero. If an object is supplied, > * then an existing entry may be extended. > + * > + * Before allocating a new virtual address map the VM > + * space limits are checked. The protection and max_protection > + * arguments are essential for properly enforcing the limits > + * at the point where the entry is allocated (i.e. skipping the > + * checks when max_protextion is VM_PROT_NONE). > + * > + * Having the max_protection argument allows the size of > + * the requested entry to be accounted as used virtual memory > + * or unused virtual memory (VM_PROT_NONE), in which case the > + * size_none field of the map is incremented by the requested > + * size. > + * > + * As a result, the allocated entry will have its protection > + * and max_protection fields set before return. > */ > kern_return_t vm_map_find_entry( > vm_map_t map, > @@ -786,11 +850,19 @@ kern_return_t vm_map_find_entry( > vm_size_t size, > vm_offset_t mask, > vm_object_t object, > - vm_map_entry_t *o_entry) /* OUT */ > + vm_map_entry_t *o_entry, /* OUT */ > + vm_prot_t protection, > + vm_prot_t max_protection) > { > vm_map_entry_t entry, new_entry; > vm_offset_t start; > vm_offset_t end; > + kern_return_t err; > + > + > + if (max_protection != VM_PROT_NONE) > + if ((err = vm_map_enforce_limit(map, size, > "vm_map_find_entry")) != KERN_SUCCESS) > + return err; > > entry = vm_map_find_entry_anywhere(map, size, mask, TRUE, &start); > > @@ -827,8 +899,8 @@ kern_return_t vm_map_find_entry( > (entry->object.vm_object == object) && > (entry->needs_copy == FALSE) && > (entry->inheritance == VM_INHERIT_DEFAULT) && > - (entry->protection == VM_PROT_DEFAULT) && > - (entry->max_protection == VM_PROT_ALL) && > + (entry->protection == protection) && > + (entry->max_protection == max_protection) && > (entry->wired_count != 0) && > (entry->projected_on == 0)) { > /* > @@ -853,8 +925,8 @@ kern_return_t vm_map_find_entry( > new_entry->needs_copy = FALSE; > > new_entry->inheritance = VM_INHERIT_DEFAULT; > - new_entry->protection = VM_PROT_DEFAULT; > - new_entry->max_protection = VM_PROT_ALL; > + new_entry->protection = protection; > + new_entry->max_protection = max_protection; > new_entry->wired_count = 1; > new_entry->wired_access = VM_PROT_DEFAULT; > > @@ -870,6 +942,8 @@ kern_return_t vm_map_find_entry( > } > > map->size += size; > + if (max_protection == VM_PROT_NONE) > + map->size_none += size; > > /* > * Update the free space hint and the lookup hint > @@ -1042,6 +1116,16 @@ MACRO_END > RETURN(KERN_NO_SPACE); > } > > + /* > + * If the allocation has protection equal to VM_PROT_NONE, > + * don't check for limits as the map's size_none field is > + * not yet incremented. > + */ > + if (max_protection != VM_PROT_NONE) { > + if ((result = vm_map_enforce_limit(map, size, "vm_map_enter")) > != KERN_SUCCESS) > + RETURN(result); > + } > + > /* > * At this point, > * "start" and "end" should define the endpoints of the > @@ -1082,6 +1166,8 @@ MACRO_END > * new range. > */ > map->size += size; > + if (max_protection == VM_PROT_NONE) > + map->size_none += size; > entry->vme_end = end; > vm_map_gap_update(&map->hdr, entry); > /* > @@ -1118,6 +1204,8 @@ MACRO_END > * new range. > */ > map->size += size; > + if (max_protection == VM_PROT_NONE) > + map->size_none += size; > next_entry->vme_start = start; > vm_map_gap_update(&map->hdr, entry); > /* > @@ -1165,6 +1253,8 @@ MACRO_END > > vm_map_entry_link(map, entry, new_entry); > map->size += size; > + if (max_protection == VM_PROT_NONE) > + map->size_none += size; > > /* > * Update the free space hint and the lookup hint > @@ -1684,11 +1774,14 @@ kern_return_t vm_map_protect( > vm_map_clip_end(map, current, end); > > old_prot = current->protection; > - if (set_max) > + if (set_max) { > + if (current->max_protection != new_prot && new_prot == > VM_PROT_NONE) > + map->size_none += current->vme_end - > current->vme_start; > + > current->protection = > (current->max_protection = new_prot) & > old_prot; > - else > + } else > current->protection = new_prot; > > /* > @@ -2047,6 +2140,8 @@ void vm_map_entry_delete( > > vm_map_entry_unlink(map, entry); > map->size -= size; > + if (entry->max_protection == VM_PROT_NONE) > + map->size_none -= size; > > vm_map_entry_dispose(map, entry); > } > @@ -2887,6 +2982,11 @@ kern_return_t vm_map_copyout( > return KERN_NO_SPACE; > } > > + if ((kr = vm_map_enforce_limit(dst_map, size, "vm_map_copyout")) != > KERN_SUCCESS) { > + vm_map_unlock(dst_map); > + return kr; > + } > + > /* > * Adjust the addresses in the copy chain, and > * reset the region attributes. > @@ -2990,6 +3090,10 @@ kern_return_t vm_map_copyout( > SAVE_HINT(dst_map, vm_map_copy_last_entry(copy)); > > dst_map->size += size; > + /* > + * dst_map->size_none need no updating because the protection > + * of all entries is VM_PROT_DEFAULT / VM_PROT_ALL > + */ > > /* > * Link in the copy > @@ -3067,6 +3171,11 @@ kern_return_t vm_map_copyout_page_list( > return KERN_NO_SPACE; > } > > + if ((result = vm_map_enforce_limit(dst_map, size, > "vm_map_copyout_page_lists")) != KERN_SUCCESS) { > + vm_map_unlock(dst_map); > + return result; > + } > + > end = start + size; > > must_wire = dst_map->wiring_required; > @@ -3155,6 +3264,11 @@ kern_return_t vm_map_copyout_page_list( > * new range. > */ > dst_map->size += size; > + /* > + * dst_map->size_none need no updating because the protection > + * of `last` entry is VM_PROT_DEFAULT / VM_PROT_ALL (otherwise > + * the flow would have jumped to create_object). > + */ > last->vme_end = end; > vm_map_gap_update(&dst_map->hdr, last); > > @@ -3211,6 +3325,10 @@ create_object: > } > SAVE_HINT(dst_map, entry); > dst_map->size += size; > + /* > + * dst_map->size_none need no updating because the protection > + * of `entry` is VM_PROT_DEFAULT / VM_PROT_ALL > + */ > > /* > * Link in the entry > @@ -4395,6 +4513,7 @@ vm_map_t vm_map_fork(vm_map_t old_map) > vm_map_entry_t new_entry; > pmap_t new_pmap = pmap_create((vm_size_t) 0); > vm_size_t new_size = 0; > + vm_size_t new_size_none = 0; > vm_size_t entry_size; > vm_object_t object; > > @@ -4529,6 +4648,8 @@ vm_map_t vm_map_fork(vm_map_t old_map) > old_entry->vme_start); > > new_size += entry_size; > + if (old_entry->max_protection == VM_PROT_NONE) > + new_size_none += entry_size; > break; > > case VM_INHERIT_COPY: > @@ -4577,6 +4698,8 @@ vm_map_t vm_map_fork(vm_map_t old_map) > > > new_size += entry_size; > + if (old_entry->max_protection == > VM_PROT_NONE) > + new_size_none += entry_size; > break; > } > > @@ -4614,6 +4737,8 @@ vm_map_t vm_map_fork(vm_map_t old_map) > > vm_map_copy_insert(new_map, last, copy); > new_size += entry_size; > + if (old_entry->max_protection == VM_PROT_NONE) > + new_size_none += entry_size; > > /* > * Pick up the traversal at the end of > @@ -4635,6 +4760,8 @@ vm_map_t vm_map_fork(vm_map_t old_map) > } > > new_map->size = new_size; > + new_map->size_none = new_size_none; > + vm_map_copy_limits(new_map, old_map); > vm_map_unlock(old_map); > > return(new_map); > @@ -5166,8 +5293,11 @@ void vm_map_print(db_expr_t addr, boolean_t have_addr, > db_expr_t count, const ch > iprintf("Map 0x%X: name=\"%s\", pmap=0x%X,", > (vm_offset_t) map, map->name, (vm_offset_t) (map->pmap)); > printf("ref=%d,nentries=%d\n", map->ref_count, map->hdr.nentries); > - printf("size=%lu,resident:%lu,wired=%lu\n", map->size, > - pmap_resident_count(map->pmap) * PAGE_SIZE, map->size_wired); > + printf("size=%lu,resident:%lu,wired=%lu,none=%lu\n", map->size, > + pmap_resident_count(map->pmap) * PAGE_SIZE, map->size_wired, > + map->size_none); > + printf("max_limit=%lu,cur_limit=%lu\n", > + map->size_max_limit, map->size_cur_limit); > printf("version=%d\n", map->timestamp); > indent += 1; > for (entry = vm_map_first_entry(map); > diff --git a/vm/vm_map.h b/vm/vm_map.h > index 900f1218..1b66dda4 100644 > --- a/vm/vm_map.h > +++ b/vm/vm_map.h > @@ -184,6 +184,7 @@ struct vm_map { > pmap_t pmap; /* Physical map */ > vm_size_t size; /* virtual size */ > vm_size_t size_wired; /* wired size */ > + vm_size_t size_none; /* none protection size */ > int ref_count; /* Reference count */ > decl_simple_lock_data(, ref_lock) /* Lock for ref_count field */ > vm_map_entry_t hint; /* hint for quick lookups */ > @@ -198,6 +199,10 @@ struct vm_map { > unsigned int timestamp; /* Version number */ > > const char *name; /* Associated name */ > + > + vm_size_t size_cur_limit; /* current limit on virtual > memory size */ > + vm_size_t size_max_limit; /* maximum size an unprivileged > user can > + change current limit to */ > }; > > #define vm_map_to_entry(map) ((struct vm_map_entry *) &(map)->hdr.links) > @@ -401,7 +406,7 @@ extern kern_return_t vm_map_enter(vm_map_t, > vm_offset_t *, vm_size_t, > /* Enter a mapping primitive */ > extern kern_return_t vm_map_find_entry(vm_map_t, vm_offset_t *, vm_size_t, > vm_offset_t, vm_object_t, > - vm_map_entry_t *); > + vm_map_entry_t *, vm_prot_t, > vm_prot_t); > /* Deallocate a region */ > extern kern_return_t vm_map_remove(vm_map_t, vm_offset_t, vm_offset_t); > /* Change protection */ > @@ -582,4 +587,12 @@ void _vm_map_clip_end( > vm_offset_t end, > boolean_t link_gap); > > +/* > + * This function is called to inherit the virtual memory limits > + * from one vm_map_t to another. > + */ > +void vm_map_copy_limits( > + vm_map_t dst, > + vm_map_t src); > + > #endif /* _VM_VM_MAP_H_ */ > diff --git a/vm/vm_user.c b/vm/vm_user.c > index c6dbda68..ef2c39d7 100644 > --- a/vm/vm_user.c > +++ b/vm/vm_user.c > @@ -813,3 +813,72 @@ kern_return_t vm_pages_phys( > > return KERN_SUCCESS; > } > + > +/* > + * vm_set_size_limit > + * > + * Sets the current/maximum virtual adress space limits > + * of the `target_task`. > + * > + * The host privileged port must be provided to increase > + * the max limit. > + */ > +kern_return_t > +vm_set_size_limit( > + const ipc_port_t host_port, > + vm_map_t map, > + vm_size_t current_limit, > + vm_size_t max_limit) > +{ > + ipc_kobject_type_t ikot_host = IKOT_NONE; > + > + if (current_limit > max_limit) > + return KERN_INVALID_ARGUMENT; > + if (map == VM_MAP_NULL) > + return KERN_INVALID_TASK; > + > + if (!IP_VALID(host_port)) > + return KERN_INVALID_HOST; > + ip_lock(host_port); > + if (ip_active(host_port)) > + ikot_host = ip_kotype(host_port); > + ip_unlock(host_port); > + > + if (ikot_host != IKOT_HOST && ikot_host != IKOT_HOST_PRIV) > + return KERN_INVALID_HOST; > + > + vm_map_lock(map); > + if (max_limit > map->size_max_limit && ikot_host != IKOT_HOST_PRIV) { > + vm_map_unlock(map); > + return KERN_NO_ACCESS; > + } > + > + map->size_cur_limit = current_limit; > + map->size_max_limit = max_limit; > + vm_map_unlock(map); > + > + return KERN_SUCCESS; > +} > + > +/* > + * vm_get_size_limit > + * > + * Gets the current/maximum virtual adress space limits > + * of the provided `map`. > + */ > +kern_return_t > +vm_get_size_limit( > + vm_map_t map, > + vm_size_t *current_limit, > + vm_size_t *max_limit) > +{ > + if (map == VM_MAP_NULL) > + return KERN_INVALID_TASK; > + > + vm_map_lock_read(map); > + *current_limit = map->size_cur_limit; > + *max_limit = map->size_max_limit; > + vm_map_unlock_read(map); > + > + return KERN_SUCCESS; > +} > diff --git a/xen/grant.c b/xen/grant.c > index 84758cfc..dd2fabf7 100644 > --- a/xen/grant.c > +++ b/xen/grant.c > @@ -135,7 +135,8 @@ void hyp_grant_init(void) { > > simple_lock_init(&lock); > vm_map_find_entry(kernel_map, &addr, NR_GRANT_PAGES * PAGE_SIZE, > - (vm_offset_t) 0, kernel_object, &grants_map_entry); > + (vm_offset_t) 0, kernel_object, &grants_map_entry, > + VM_PROT_DEFAULT, VM_PROT_ALL); > grants = (void*) addr; > > for (i = 0; i < NR_GRANT_PAGES; i++) > -- > 2.51.0 > >
-- Samuel Accroche-toi au terminal, j'enlève le shell... -+- nojhan -+-
