git: d8e6f4946cec - main - vm: Fix anonymous memory clustering under ASLR
Date: Tue, 27 Jun 2023 04:43:50 UTC
The branch main has been updated by alc: URL: https://cgit.FreeBSD.org/src/commit/?id=d8e6f4946cec0b84a6997d62e791b8cf993741b2 commit d8e6f4946cec0b84a6997d62e791b8cf993741b2 Author: Alan Cox <alc@FreeBSD.org> AuthorDate: 2023-06-23 17:00:32 +0000 Commit: Alan Cox <alc@FreeBSD.org> CommitDate: 2023-06-27 04:42:48 +0000 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 --- sys/vm/vm_map.c | 10 +++++++--- sys/vm/vm_map.h | 1 + sys/vm/vm_mmap.c | 8 +++++--- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/sys/vm/vm_map.c b/sys/vm/vm_map.c index f5863a9b9939..a02107b5e64d 100644 --- a/sys/vm/vm_map.c +++ b/sys/vm/vm_map.c @@ -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"); static bool -clustering_anon_allowed(vm_offset_t addr) +clustering_anon_allowed(vm_offset_t addr, int cow) { switch (cluster_anon) { case 0: return (false); case 1: - return (addr == 0); + return (addr == 0 || (cow & MAP_NO_HINT) != 0); case 2: default: return (true); @@ -2111,7 +2111,7 @@ vm_map_find(vm_map_t map, vm_object_t object, vm_ooffset_t offset, } else alignment = 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 && find_space != VMFS_NO_SPACE && object == NULL && (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; hint = *addr; + if (hint == 0) + cow |= MAP_NO_HINT; + if (hint < min_addr) + *addr = hint = min_addr; for (;;) { rv = vm_map_find(map, object, offset, addr, length, max_addr, find_space, prot, max, cow); diff --git a/sys/vm/vm_map.h b/sys/vm/vm_map.h index 2ac54a39a57b..fd8b606e8ddc 100644 --- a/sys/vm/vm_map.h +++ b/sys/vm/vm_map.h @@ -383,6 +383,7 @@ long vmspace_resident_count(struct vmspace *vmspace); #define MAP_CREATE_STACK_GAP_DN 0x00020000 #define MAP_VN_EXEC 0x00040000 #define MAP_SPLIT_BOUNDARY_MASK 0x00180000 +#define MAP_NO_HINT 0x00200000 #define MAP_SPLIT_BOUNDARY_SHIFT 19 diff --git a/sys/vm/vm_mmap.c b/sys/vm/vm_mmap.c index 56345fcaf560..408e077476dd 100644 --- a/sys/vm/vm_mmap.c +++ b/sys/vm/vm_mmap.c @@ -353,10 +353,12 @@ kern_mmap(struct thread *td, const struct mmap_req *mrp) * the hint would fall in the potential heap space, * place it after the end of the largest possible heap. * - * There should really be a pmap call to determine a reasonable - * location. + * For anonymous mappings within the address space of the + * 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_daddr + lim_max(td, RLIMIT_DATA))))