diff --git a/sys/vm/vm_map.h b/sys/vm/vm_map.h --- a/sys/vm/vm_map.h +++ b/sys/vm/vm_map.h @@ -148,6 +148,7 @@ #define MAP_ENTRY_STACK_GAP_DN 0x00020000 #define MAP_ENTRY_STACK_GAP_UP 0x00040000 #define MAP_ENTRY_HEADER 0x00080000 +#define MAP_ENTRY_ANON_LOC_UPD 0x00400000 #define MAP_ENTRY_SPLIT_BOUNDARY_MASK 0x00300000 diff --git a/sys/vm/vm_map.c b/sys/vm/vm_map.c --- a/sys/vm/vm_map.c +++ b/sys/vm/vm_map.c @@ -159,6 +159,12 @@ #define PROC_VMSPACE_LOCK(p) do { } while (0) #define PROC_VMSPACE_UNLOCK(p) do { } while (0) +static int cluster_anon = 1; +SYSCTL_INT(_vm, OID_AUTO, cluster_anon, CTLFLAG_RW, + &cluster_anon, 0, + "Cluster anonymous mappings: " + "0 = no, 1 = yes if no hint, 2 = always, 3 = keep anon_loc const"); + /* * VM_MAP_RANGE_CHECK: [ internal use only ] * @@ -1700,6 +1706,12 @@ return (KERN_INVALID_ARGUMENT); protoeflags |= bidx << MAP_ENTRY_SPLIT_BOUNDARY_SHIFT; } + if (cluster_anon == 1 || cluster_anon == 2) { + if ((object == NULL || (cow & (MAP_INHERIT_SHARE | + MAP_STACK_GROWS_UP | MAP_STACK_GROWS_DOWN | + MAP_ENTRY_GUARD)) == 0) && max != PROT_NONE) + protoeflags |= MAP_ENTRY_ANON_LOC_UPD; + } cred = NULL; if ((cow & (MAP_ACC_NO_CHARGE | MAP_NOFAULT | MAP_CREATE_GUARD)) != 0) @@ -1975,26 +1987,27 @@ static const int aslr_pages_rnd_64[2] = {0x1000, 0x10}; static const int aslr_pages_rnd_32[2] = {0x100, 0x4}; -static int cluster_anon = 1; -SYSCTL_INT(_vm, OID_AUTO, cluster_anon, CTLFLAG_RW, - &cluster_anon, 0, - "Cluster anonymous mappings: 0 = no, 1 = yes if no hint, 2 = always"); - static bool -clustering_anon_allowed(vm_offset_t addr) +clustering_anon_allowed(vm_offset_t addr, vm_offset_t anon_loc) { switch (cluster_anon) { case 0: return (false); case 1: - return (addr == 0); + return (addr == 0 || addr <= anon_loc); case 2: default: return (true); } } +static bool +clustering_anon_loc_const(void) +{ + return (cluster_anon == 3); +} + static long aslr_restarts; SYSCTL_LONG(_vm, OID_AUTO, aslr_restarts, CTLFLAG_RD, &aslr_restarts, 0, @@ -2111,7 +2124,7 @@ } else alignment = 0; en_aslr = (map->flags & MAP_ASLR) != 0; - update_anon = cluster = clustering_anon_allowed(*addr) && + update_anon = cluster = clustering_anon_allowed(*addr, map->anon_loc) && (map->flags & MAP_IS_SUB_MAP) == 0 && max_addr == 0 && find_space != VMFS_NO_SPACE && object == NULL && (cow & (MAP_INHERIT_SHARE | MAP_STACK_GROWS_UP | @@ -2226,7 +2239,7 @@ rv = vm_map_insert(map, object, offset, *addr, *addr + length, prot, max, cow); } - if (rv == KERN_SUCCESS && update_anon) + if (rv == KERN_SUCCESS && update_anon && !clustering_anon_loc_const()) map->anon_loc = *addr + length; done: vm_map_unlock(map); @@ -3966,8 +3979,9 @@ entry->object.vm_object != NULL) pmap_map_delete(map->pmap, entry->start, entry->end); - if (entry->end == map->anon_loc) - map->anon_loc = entry->start; + if (entry->end == map->anon_loc && + (entry->eflags & MAP_ENTRY_ANON_LOC_UPD) != 0) + map->anon_loc = vm_map_entry_pred(entry)->end; /* * Delete the entry only after removing all pmap