vm: Fix anonymous memory clustering under ASLR
By default, our ASLR implementation is supposed to cluster anonymous memory allocations, unless the application's mmap(..., MAP_ANON, ...) call included a non-zero address hint. Unfortunately, clustering never occurred because kern_mmap() always replaced the given address hint when it was zero. So, the ASLR implementation always believed that a non-zero hint had been provided and randomized the mapping's location in the address space. To fix this problem, I'm pushing down the point at which we convert a hint of zero to the minimum allocatable address from kern_mmap() to vm_map_find_min(). Reviewed by: kib MFC after: 2 weeks Differential Revision: https://reviews.freebsd.org/D40743
This commit is contained in:
parent
af296130ea
commit
d8e6f4946c
@ -1981,14 +1981,14 @@ SYSCTL_INT(_vm, OID_AUTO, cluster_anon, CTLFLAG_RW,
|
|||||||
"Cluster anonymous mappings: 0 = no, 1 = yes if no hint, 2 = always");
|
"Cluster anonymous mappings: 0 = no, 1 = yes if no hint, 2 = always");
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
clustering_anon_allowed(vm_offset_t addr)
|
clustering_anon_allowed(vm_offset_t addr, int cow)
|
||||||
{
|
{
|
||||||
|
|
||||||
switch (cluster_anon) {
|
switch (cluster_anon) {
|
||||||
case 0:
|
case 0:
|
||||||
return (false);
|
return (false);
|
||||||
case 1:
|
case 1:
|
||||||
return (addr == 0);
|
return (addr == 0 || (cow & MAP_NO_HINT) != 0);
|
||||||
case 2:
|
case 2:
|
||||||
default:
|
default:
|
||||||
return (true);
|
return (true);
|
||||||
@ -2111,7 +2111,7 @@ vm_map_find(vm_map_t map, vm_object_t object, vm_ooffset_t offset,
|
|||||||
} else
|
} else
|
||||||
alignment = 0;
|
alignment = 0;
|
||||||
en_aslr = (map->flags & MAP_ASLR) != 0;
|
en_aslr = (map->flags & MAP_ASLR) != 0;
|
||||||
update_anon = cluster = clustering_anon_allowed(*addr) &&
|
update_anon = cluster = clustering_anon_allowed(*addr, cow) &&
|
||||||
(map->flags & MAP_IS_SUB_MAP) == 0 && max_addr == 0 &&
|
(map->flags & MAP_IS_SUB_MAP) == 0 && max_addr == 0 &&
|
||||||
find_space != VMFS_NO_SPACE && object == NULL &&
|
find_space != VMFS_NO_SPACE && object == NULL &&
|
||||||
(cow & (MAP_INHERIT_SHARE | MAP_STACK_GROWS_UP |
|
(cow & (MAP_INHERIT_SHARE | MAP_STACK_GROWS_UP |
|
||||||
@ -2255,6 +2255,10 @@ vm_map_find_min(vm_map_t map, vm_object_t object, vm_ooffset_t offset,
|
|||||||
int rv;
|
int rv;
|
||||||
|
|
||||||
hint = *addr;
|
hint = *addr;
|
||||||
|
if (hint == 0)
|
||||||
|
cow |= MAP_NO_HINT;
|
||||||
|
if (hint < min_addr)
|
||||||
|
*addr = hint = min_addr;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
rv = vm_map_find(map, object, offset, addr, length, max_addr,
|
rv = vm_map_find(map, object, offset, addr, length, max_addr,
|
||||||
find_space, prot, max, cow);
|
find_space, prot, max, cow);
|
||||||
|
@ -383,6 +383,7 @@ long vmspace_resident_count(struct vmspace *vmspace);
|
|||||||
#define MAP_CREATE_STACK_GAP_DN 0x00020000
|
#define MAP_CREATE_STACK_GAP_DN 0x00020000
|
||||||
#define MAP_VN_EXEC 0x00040000
|
#define MAP_VN_EXEC 0x00040000
|
||||||
#define MAP_SPLIT_BOUNDARY_MASK 0x00180000
|
#define MAP_SPLIT_BOUNDARY_MASK 0x00180000
|
||||||
|
#define MAP_NO_HINT 0x00200000
|
||||||
|
|
||||||
#define MAP_SPLIT_BOUNDARY_SHIFT 19
|
#define MAP_SPLIT_BOUNDARY_SHIFT 19
|
||||||
|
|
||||||
|
@ -353,10 +353,12 @@ kern_mmap(struct thread *td, const struct mmap_req *mrp)
|
|||||||
* the hint would fall in the potential heap space,
|
* the hint would fall in the potential heap space,
|
||||||
* place it after the end of the largest possible heap.
|
* place it after the end of the largest possible heap.
|
||||||
*
|
*
|
||||||
* There should really be a pmap call to determine a reasonable
|
* For anonymous mappings within the address space of the
|
||||||
* location.
|
* calling process, the absence of a hint is handled at a
|
||||||
|
* lower level in order to implement different clustering
|
||||||
|
* strategies for ASLR.
|
||||||
*/
|
*/
|
||||||
if (addr == 0 ||
|
if (((flags & MAP_ANON) == 0 && addr == 0) ||
|
||||||
(addr >= round_page((vm_offset_t)vms->vm_taddr) &&
|
(addr >= round_page((vm_offset_t)vms->vm_taddr) &&
|
||||||
addr < round_page((vm_offset_t)vms->vm_daddr +
|
addr < round_page((vm_offset_t)vms->vm_daddr +
|
||||||
lim_max(td, RLIMIT_DATA))))
|
lim_max(td, RLIMIT_DATA))))
|
||||||
|
Loading…
Reference in New Issue
Block a user