diff --git a/lib/libc/sys/mprotect.2 b/lib/libc/sys/mprotect.2 index 3be81c6582a..ca4d6307c44 100644 --- a/lib/libc/sys/mprotect.2 +++ b/lib/libc/sys/mprotect.2 @@ -28,7 +28,7 @@ .\" @(#)mprotect.2 8.1 (Berkeley) 6/9/93 .\" $FreeBSD$ .\" -.Dd August 3, 2016 +.Dd June 24, 2017 .Dt MPROTECT 2 .Os .Sh NAME @@ -80,10 +80,24 @@ and arguments is not valid. .It Bq Er EACCES The calling process was not allowed to change -the protection to the value specified by -the +the protection to the value specified by the .Fa prot argument. +.It Bq Er ENOMEM +The virtual address range specified by the +.Fa addr +and +.Fa len +arguments specify one or more pages which are not mapped. +.It Bq Er ENOMEM +The +.Fa prot +argument specifies +.Dv PROT_WRITE +on a +.Dv MAP_PRIVATE +mapping, and it would require more swap space than the system is able to +supply for the private pages. .El .Sh SEE ALSO .Xr madvise 2 , diff --git a/sys/vm/vm_map.c b/sys/vm/vm_map.c index 39cf303eaa0..b311b54d0f0 100644 --- a/sys/vm/vm_map.c +++ b/sys/vm/vm_map.c @@ -1490,11 +1490,11 @@ vm_map_fixed(vm_map_t map, vm_object_t object, vm_ooffset_t offset, * If object is non-NULL, ref count must be bumped by caller * prior to making call to account for the new entry. */ -int -vm_map_find(vm_map_t map, vm_object_t object, vm_ooffset_t offset, - vm_offset_t *addr, /* IN/OUT */ - vm_size_t length, vm_offset_t max_addr, int find_space, - vm_prot_t prot, vm_prot_t max, int cow) +static int +vm_map_find1(vm_map_t map, vm_object_t object, vm_ooffset_t offset, + vm_offset_t *addr, /* IN/OUT */ + vm_size_t length, vm_offset_t max_addr, int find_space, vm_prot_t prot, + vm_prot_t max, int cow) { vm_offset_t alignment, initial_addr, start; int result; @@ -1556,6 +1556,26 @@ again: return (result); } +int +vm_map_find(vm_map_t map, vm_object_t object, vm_ooffset_t offset, + vm_offset_t *addr, /* IN/OUT */ + vm_size_t length, vm_offset_t max_addr, int find_space, vm_prot_t prot, + vm_prot_t max, int cow) +{ + int rv; + bool hinted; + + hinted = *addr != 0; + for (;;) { + rv = vm_map_find1(map, object, offset, addr, length, max_addr, + find_space, prot, max, cow); + if (rv != KERN_NO_SPACE || !hinted) + return (rv); + *addr = 0; + hinted = false; + } +} + /* * vm_map_simplify_entry: * @@ -1970,7 +1990,7 @@ vm_map_pmap_enter(vm_map_t map, vm_offset_t addr, vm_prot_t prot, */ int vm_map_protect(vm_map_t map, vm_offset_t start, vm_offset_t end, - vm_prot_t new_prot, boolean_t set_max) + vm_prot_t new_prot, boolean_t set_max) { vm_map_entry_t current, entry; vm_object_t obj; @@ -1995,7 +2015,8 @@ vm_map_protect(vm_map_t map, vm_offset_t start, vm_offset_t end, if (vm_map_lookup_entry(map, start, &entry)) { vm_map_clip_start(map, entry, start); } else { - entry = entry->next; + vm_map_unlock(map); + return (KERN_INVALID_ADDRESS); } /* @@ -2003,6 +2024,8 @@ vm_map_protect(vm_map_t map, vm_offset_t start, vm_offset_t end, */ for (current = entry; current != &map->header && current->start < end; current = current->next) { + if ((current->eflags & MAP_ENTRY_GUARD) != 0) + continue; if (current->eflags & MAP_ENTRY_IS_SUB_MAP) { vm_map_unlock(map); return (KERN_INVALID_ARGUMENT); @@ -2011,6 +2034,11 @@ vm_map_protect(vm_map_t map, vm_offset_t start, vm_offset_t end, vm_map_unlock(map); return (KERN_PROTECTION_FAILURE); } + if (current->end < end && (current->next == &map->header || + current->next->start > current->end)) { + vm_map_unlock(map); + return (KERN_INVALID_ADDRESS); + } } /* @@ -2712,9 +2740,9 @@ vm_map_wire(vm_map_t map, vm_offset_t start, vm_offset_t end, * If VM_MAP_WIRE_HOLESOK was specified, skip this check. */ next_entry: - if (((flags & VM_MAP_WIRE_HOLESOK) == 0) && - (entry->end < end && (entry->next == &map->header || - entry->next->start > entry->end))) { + if ((flags & VM_MAP_WIRE_HOLESOK) == 0 && + entry->end < end && (entry->next == &map->header || + entry->next->start > entry->end)) { end = entry->end; rv = KERN_INVALID_ADDRESS; goto done; diff --git a/sys/vm/vm_mmap.c b/sys/vm/vm_mmap.c index 4d8f6ad9ed7..09912250d52 100644 --- a/sys/vm/vm_mmap.c +++ b/sys/vm/vm_mmap.c @@ -607,6 +607,7 @@ kern_mprotect(struct thread *td, uintptr_t addr0, size_t size, int prot) case KERN_PROTECTION_FAILURE: return (EACCES); case KERN_RESOURCE_SHORTAGE: + case KERN_INVALID_ADDRESS: return (ENOMEM); } return (EINVAL);