Page MenuHomeFreeBSD

D5603.id21262.diff
No OneTemporary

D5603.id21262.diff

Index: sys/amd64/amd64/elf_machdep.c
===================================================================
--- sys/amd64/amd64/elf_machdep.c
+++ sys/amd64/amd64/elf_machdep.c
@@ -72,7 +72,8 @@
.sv_setregs = exec_setregs,
.sv_fixlimit = NULL,
.sv_maxssiz = NULL,
- .sv_flags = SV_ABI_FREEBSD | SV_LP64 | SV_SHP | SV_TIMEKEEP,
+ .sv_flags = SV_ABI_FREEBSD | SV_LP64 | SV_SHP | SV_TIMEKEEP |
+ SV_ASLR,
.sv_set_syscall_retval = cpu_set_syscall_retval,
.sv_fetch_syscall_args = cpu_fetch_syscall_args,
.sv_syscallnames = syscallnames,
Index: sys/arm/arm/elf_machdep.c
===================================================================
--- sys/arm/arm/elf_machdep.c
+++ sys/arm/arm/elf_machdep.c
@@ -75,7 +75,7 @@
.sv_maxssiz = NULL,
.sv_flags =
#if __ARM_ARCH >= 6
- SV_SHP | SV_TIMEKEEP |
+ SV_SHP | SV_TIMEKEEP | SV_ASLR |
#endif
SV_ABI_FREEBSD | SV_ILP32,
.sv_set_syscall_retval = cpu_set_syscall_retval,
Index: sys/compat/freebsd32/freebsd32_misc.c
===================================================================
--- sys/compat/freebsd32/freebsd32_misc.c
+++ sys/compat/freebsd32/freebsd32_misc.c
@@ -3049,6 +3049,7 @@
case PROC_SPROTECT:
case PROC_TRACE_CTL:
case PROC_TRAPCAP_CTL:
+ case PROC_ASLR_CTL:
error = copyin(PTRIN(uap->data), &flags, sizeof(flags));
if (error != 0)
return (error);
@@ -3079,6 +3080,7 @@
break;
case PROC_TRACE_STATUS:
case PROC_TRAPCAP_STATUS:
+ case PROC_ASLR_STATUS:
data = &flags;
break;
default:
@@ -3098,6 +3100,7 @@
break;
case PROC_TRACE_STATUS:
case PROC_TRAPCAP_STATUS:
+ case PROC_ASLR_STATUS:
if (error == 0)
error = copyout(&flags, uap->data, sizeof(flags));
break;
Index: sys/compat/ia32/ia32_sysvec.c
===================================================================
--- sys/compat/ia32/ia32_sysvec.c
+++ sys/compat/ia32/ia32_sysvec.c
@@ -120,11 +120,9 @@
.sv_setregs = ia32_setregs,
.sv_fixlimit = ia32_fixlimit,
.sv_maxssiz = &ia32_maxssiz,
- .sv_flags = SV_ABI_FREEBSD | SV_IA32 | SV_ILP32 |
+ .sv_flags = SV_ABI_FREEBSD | SV_IA32 | SV_ILP32
#ifdef __amd64__
- SV_SHP | SV_TIMEKEEP
-#else
- 0
+ | SV_SHP | SV_TIMEKEEP | SV_ASLR
#endif
,
.sv_set_syscall_retval = ia32_set_syscall_retval,
Index: sys/i386/i386/elf_machdep.c
===================================================================
--- sys/i386/i386/elf_machdep.c
+++ sys/i386/i386/elf_machdep.c
@@ -79,7 +79,7 @@
.sv_fixlimit = NULL,
.sv_maxssiz = NULL,
.sv_flags = SV_ABI_FREEBSD | SV_IA32 | SV_ILP32 | SV_SHP |
- SV_TIMEKEEP,
+ SV_TIMEKEEP | SV_ASLR,
.sv_set_syscall_retval = cpu_set_syscall_retval,
.sv_fetch_syscall_args = cpu_fetch_syscall_args,
.sv_syscallnames = syscallnames,
Index: sys/kern/imgact_elf.c
===================================================================
--- sys/kern/imgact_elf.c
+++ sys/kern/imgact_elf.c
@@ -135,6 +135,23 @@
#endif
#endif
+static int __elfN(aslr_enabled) = 1;
+SYSCTL_INT(__CONCAT(_kern_elf, __ELF_WORD_SIZE), OID_AUTO,
+ aslr_enabled, CTLFLAG_RWTUN, &__elfN(aslr_enabled), 0,
+ __XSTRING(__CONCAT(ELF, __ELF_WORD_SIZE))
+ ": enable address map randomization");
+
+static int __elfN(pie_aslr_enabled) = 1;
+SYSCTL_INT(__CONCAT(_kern_elf, __ELF_WORD_SIZE), OID_AUTO,
+ pie_aslr_enabled, CTLFLAG_RWTUN, &__elfN(pie_aslr_enabled), 0,
+ __XSTRING(__CONCAT(ELF, __ELF_WORD_SIZE))
+ ": enable address map randomization for PIE binaries");
+
+static int __elfN(aslr_honor_sbrk) = 0;
+SYSCTL_INT(__CONCAT(_kern_elf, __ELF_WORD_SIZE), OID_AUTO,
+ aslr_honor_sbrk, CTLFLAG_RW, &__elfN(aslr_honor_sbrk), 0,
+ __XSTRING(__CONCAT(ELF, __ELF_WORD_SIZE)) ": assume sbrk is used");
+
static Elf_Brandinfo *elf_brand_list[MAX_BRANDS];
#define trunc_page_ps(va, ps) rounddown2(va, ps)
@@ -422,13 +439,14 @@
}
static int
-__elfN(map_insert)(vm_map_t map, vm_object_t object, vm_ooffset_t offset,
- vm_offset_t start, vm_offset_t end, vm_prot_t prot, int cow)
+__elfN(map_insert)(struct image_params *imgp, vm_map_t map, vm_object_t object,
+ vm_ooffset_t offset, vm_offset_t start, vm_offset_t end, vm_prot_t prot,
+ int cow)
{
struct sf_buf *sf;
vm_offset_t off;
vm_size_t sz;
- int error, rv;
+ int error, locked, rv;
if (start != trunc_page(start)) {
rv = __elfN(map_partial)(map, object, offset, start,
@@ -451,9 +469,10 @@
* The mapping is not page aligned. This means we have
* to copy the data. Sigh.
*/
- rv = vm_map_find(map, NULL, 0, &start, end - start, 0,
- VMFS_NO_SPACE, prot | VM_PROT_WRITE, VM_PROT_ALL,
- 0);
+ vm_map_lock(map);
+ rv = vm_map_insert(map, NULL, 0, start, end,
+ prot | VM_PROT_WRITE, VM_PROT_ALL, 0);
+ vm_map_unlock(map);
if (rv != KERN_SUCCESS)
return (rv);
if (object == NULL)
@@ -480,8 +499,12 @@
rv = vm_map_insert(map, object, offset, start, end,
prot, VM_PROT_ALL, cow);
vm_map_unlock(map);
- if (rv != KERN_SUCCESS)
+ if (rv != KERN_SUCCESS) {
+ locked = VOP_ISLOCKED(imgp->vp);
+ VOP_UNLOCK(imgp->vp, 0);
vm_object_deallocate(object);
+ vn_lock(imgp->vp, locked | LK_RETRY);
+ }
}
return (rv);
} else {
@@ -538,7 +561,7 @@
cow = MAP_COPY_ON_WRITE | MAP_PREFAULT |
(prot & VM_PROT_WRITE ? 0 : MAP_DISABLE_COREDUMP);
- rv = __elfN(map_insert)(map,
+ rv = __elfN(map_insert)(imgp, map,
object,
file_addr, /* file offset */
map_addr, /* virtual start */
@@ -568,8 +591,8 @@
/* This had damn well better be true! */
if (map_len != 0) {
- rv = __elfN(map_insert)(map, NULL, 0, map_addr, map_addr +
- map_len, VM_PROT_ALL, 0);
+ rv = __elfN(map_insert)(imgp, map, NULL, 0, map_addr,
+ map_addr + map_len, VM_PROT_ALL, 0);
if (rv != KERN_SUCCESS) {
return (EINVAL);
}
@@ -744,6 +767,30 @@
return (error);
}
+static u_long
+__CONCAT(rnd_, __elfN(base))(u_long base, u_long minv, u_long maxv,
+ u_int align)
+{
+ u_long rbase, res;
+
+ arc4rand(&rbase, sizeof(rbase), 0);
+ res = base + rbase % (maxv - minv);
+ res &= ~((u_long)align - 1);
+ KASSERT(res >= base,
+ ("res %#lx < base %#lx, minv %#lx maxv %#lx rbase %#lx",
+ res, base, minv, maxv, rbase));
+ KASSERT(res < maxv,
+ ("res %#lx > maxv %#lx, minv %#lx base %#lx rbase %#lx",
+ res, maxv, minv, base, rbase));
+ return (res);
+}
+
+/*
+ * Impossible et_dyn_addr initial value indicating that the real base
+ * must be calculated later with some randomization applied.
+ */
+#define ET_DYN_ADDR_RAND 1
+
static int
__CONCAT(exec_, __elfN(imgact))(struct image_params *imgp)
{
@@ -752,6 +799,7 @@
const Elf_Phdr *phdr;
Elf_Auxargs *elf_auxargs;
struct vmspace *vmspace;
+ vm_map_t map;
const char *err_str, *newinterp;
char *interp, *interp_buf, *path;
Elf_Brandinfo *brand_info;
@@ -759,6 +807,7 @@
vm_prot_t prot;
u_long text_size, data_size, total_size, text_addr, data_addr;
u_long seg_size, seg_addr, addr, baddr, et_dyn_addr, entry, proghdr;
+ u_long maxalign, mapsz, maxv;
int32_t osrel;
int error, i, n, interp_name_len, have_interp;
@@ -800,12 +849,17 @@
err_str = newinterp = NULL;
interp = interp_buf = NULL;
td = curthread;
+ maxalign = PAGE_SIZE;
+ mapsz = 0;
for (i = 0; i < hdr->e_phnum; i++) {
switch (phdr[i].p_type) {
case PT_LOAD:
if (n == 0)
baddr = phdr[i].p_vaddr;
+ if (phdr[i].p_align > maxalign)
+ maxalign = phdr[i].p_align;
+ mapsz += phdr[i].p_memsz;
n++;
break;
case PT_INTERP:
@@ -859,6 +913,8 @@
error = ENOEXEC;
goto ret;
}
+ sv = brand_info->sysvec;
+ et_dyn_addr = 0;
if (hdr->e_type == ET_DYN) {
if ((brand_info->flags & BI_CAN_EXEC_DYN) == 0) {
uprintf("Cannot execute shared object\n");
@@ -869,13 +925,17 @@
* Honour the base load address from the dso if it is
* non-zero for some reason.
*/
- if (baddr == 0)
- et_dyn_addr = ET_DYN_LOAD_ADDR;
- else
- et_dyn_addr = 0;
- } else
- et_dyn_addr = 0;
- sv = brand_info->sysvec;
+ if (baddr == 0) {
+ if ((sv->sv_flags & SV_ASLR) == 0)
+ et_dyn_addr = ET_DYN_LOAD_ADDR;
+ else if ((__elfN(pie_aslr_enabled) &&
+ (imgp->proc->p_flag2 & P2_ASLR_DISABLE) == 0) ||
+ (imgp->proc->p_flag2 & P2_ASLR_ENABLE) != 0)
+ et_dyn_addr = ET_DYN_ADDR_RAND;
+ else
+ et_dyn_addr = ET_DYN_LOAD_ADDR;
+ }
+ }
if (interp != NULL && brand_info->interp_newpath != NULL)
newinterp = brand_info->interp_newpath;
@@ -894,6 +954,50 @@
error = exec_new_vmspace(imgp, sv);
imgp->proc->p_sysent = sv;
+ vmspace = imgp->proc->p_vmspace;
+ map = &vmspace->vm_map;
+
+ /*
+ * Decide to enable randomization of user mappings. First,
+ * reset user preferences for the setid binaries. Then,
+ * account for the support of the randomization by the ABI, by
+ * user preferences, and make special treatment for PIE
+ * binaries.
+ */
+ if (imgp->credential_setid) {
+ PROC_LOCK(imgp->proc);
+ imgp->proc->p_flag2 &= ~(P2_ASLR_ENABLE | P2_ASLR_DISABLE);
+ PROC_UNLOCK(imgp->proc);
+ }
+ if ((sv->sv_flags & SV_ASLR) == 0 ||
+ (imgp->proc->p_flag2 & P2_ASLR_DISABLE) != 0) {
+ KASSERT(et_dyn_addr != ET_DYN_ADDR_RAND,
+ ("et_dyn_addr == RAND and !ASLR"));
+ } else if ((imgp->proc->p_flag2 & P2_ASLR_ENABLE) != 0 ||
+ (__elfN(aslr_enabled) && hdr->e_type == ET_EXEC) ||
+ et_dyn_addr == ET_DYN_ADDR_RAND) {
+ vm_map_lock(map);
+ map->flags |= MAP_ASLR;
+ /*
+ * If user does not care about sbrk, utilize the bss
+ * grow region for mappings as well. We can select
+ * the base for the image anywere and still not suffer
+ * from the fragmentation.
+ */
+ if (!__elfN(aslr_honor_sbrk) ||
+ (imgp->proc->p_flag2 & P2_ASLR_IGNSTART) != 0)
+ map->flags |= MAP_ASLR_IGNSTART;
+ vm_map_unlock(map);
+ }
+ maxv = vm_map_max(map) - lim_max(td, RLIMIT_STACK);
+ if (et_dyn_addr == ET_DYN_ADDR_RAND) {
+ KASSERT((map->flags & MAP_ASLR) != 0,
+ ("ET_DYN_ADDR_RAND but !MAP_ASLR"));
+ et_dyn_addr = __CONCAT(rnd_, __elfN(base))(vm_map_min(map),
+ vm_map_min(map) + mapsz + lim_max(td, RLIMIT_DATA),
+ /* reserve half of the address space to interpreter */
+ maxv / 2, 1UL << flsl(maxalign));
+ }
vn_lock(imgp->vp, LK_EXCLUSIVE | LK_RETRY);
if (error != 0)
@@ -986,7 +1090,6 @@
goto ret;
}
- vmspace = imgp->proc->p_vmspace;
vmspace->vm_tsize = text_size >> PAGE_SHIFT;
vmspace->vm_taddr = (caddr_t)(uintptr_t)text_addr;
vmspace->vm_dsize = data_size >> PAGE_SHIFT;
@@ -1007,6 +1110,11 @@
if (interp != NULL) {
have_interp = FALSE;
VOP_UNLOCK(imgp->vp, 0);
+ if ((map->flags & MAP_ASLR) != 0) {
+ addr = __CONCAT(rnd_, __elfN(base))(addr, addr,
+ /* Assume that interpeter fits into 1/4 of AS */
+ (maxv + addr) / 2, PAGE_SIZE);
+ }
if (brand_info->emul_path != NULL &&
brand_info->emul_path[0] != '\0') {
path = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
Index: sys/kern/kern_exec.c
===================================================================
--- sys/kern/kern_exec.c
+++ sys/kern/kern_exec.c
@@ -1094,6 +1094,7 @@
shmexit(vmspace);
pmap_remove_pages(vmspace_pmap(vmspace));
vm_map_remove(map, vm_map_min(map), vm_map_max(map));
+ map->flags &= ~(MAP_ASLR | MAP_ASLR_IGNSTART);
} else {
error = vmspace_exec(p, sv_minuser, sv->sv_maxuser);
if (error)
Index: sys/kern/kern_fork.c
===================================================================
--- sys/kern/kern_fork.c
+++ sys/kern/kern_fork.c
@@ -497,7 +497,8 @@
* Increase reference counts on shared objects.
*/
p2->p_flag = P_INMEM;
- p2->p_flag2 = p1->p_flag2 & (P2_NOTRACE | P2_NOTRACE_EXEC | P2_TRAPCAP);
+ p2->p_flag2 = p1->p_flag2 & (P2_NOTRACE | P2_NOTRACE_EXEC | P2_TRAPCAP |
+ P2_ASLR_ENABLE | P2_ASLR_DISABLE | P2_ASLR_IGNSTART);
p2->p_swtick = ticks;
if (p1->p_flag & P_PROFIL)
startprofclock(p2);
Index: sys/kern/kern_procctl.c
===================================================================
--- sys/kern/kern_procctl.c
+++ sys/kern/kern_procctl.c
@@ -43,6 +43,11 @@
#include <sys/sysproto.h>
#include <sys/wait.h>
+#include <vm/vm.h>
+#include <vm/pmap.h>
+#include <vm/vm_map.h>
+#include <vm/vm_extern.h>
+
static int
protect_setchild(struct thread *td, struct proc *p, int flags)
{
@@ -364,6 +369,62 @@
return (0);
}
+static int
+aslr_ctl(struct thread *td, struct proc *p, int state)
+{
+
+ PROC_LOCK_ASSERT(p, MA_OWNED);
+
+ switch (state) {
+ case PROC_ASLR_FORCE_ENABLE:
+ p->p_flag2 &= ~P2_ASLR_DISABLE;
+ p->p_flag2 |= P2_ASLR_ENABLE;
+ break;
+ case PROC_ASLR_FORCE_DISABLE:
+ p->p_flag2 |= P2_ASLR_DISABLE;
+ p->p_flag2 &= ~P2_ASLR_ENABLE;
+ break;
+ case PROC_ASLR_NOFORCE:
+ p->p_flag2 &= ~(P2_ASLR_ENABLE | P2_ASLR_DISABLE);
+ break;
+ default:
+ return (EINVAL);
+ }
+ return (0);
+}
+
+static int
+aslr_status(struct thread *td, struct proc *p, int *data)
+{
+ struct vmspace *vm;
+ int d;
+
+ switch (p->p_flag2 & (P2_ASLR_ENABLE | P2_ASLR_DISABLE)) {
+ case 0:
+ d = PROC_ASLR_NOFORCE;
+ break;
+ case P2_ASLR_ENABLE:
+ d = PROC_ASLR_FORCE_ENABLE;
+ break;
+ case P2_ASLR_DISABLE:
+ d = PROC_ASLR_FORCE_DISABLE;
+ break;
+ }
+ if ((p->p_flag & P_WEXIT) == 0) {
+ _PHOLD(p);
+ PROC_UNLOCK(p);
+ vm = vmspace_acquire_ref(p);
+ if (vm != NULL && (vm->vm_map.flags & MAP_ASLR) != 0) {
+ d |= PROC_ASLR_ACTIVE;
+ vmspace_free(vm);
+ }
+ PROC_LOCK(p);
+ _PRELE(p);
+ }
+ *data = d;
+ return (0);
+}
+
#ifndef _SYS_SYSPROTO_H_
struct procctl_args {
idtype_t idtype;
@@ -388,6 +449,7 @@
case PROC_SPROTECT:
case PROC_TRACE_CTL:
case PROC_TRAPCAP_CTL:
+ case PROC_ASLR_CTL:
error = copyin(uap->data, &flags, sizeof(flags));
if (error != 0)
return (error);
@@ -416,6 +478,7 @@
break;
case PROC_TRACE_STATUS:
case PROC_TRAPCAP_STATUS:
+ case PROC_ASLR_STATUS:
data = &flags;
break;
default:
@@ -434,6 +497,7 @@
break;
case PROC_TRACE_STATUS:
case PROC_TRAPCAP_STATUS:
+ case PROC_ASLR_STATUS:
if (error == 0)
error = copyout(&flags, uap->data, sizeof(flags));
break;
@@ -467,6 +531,10 @@
return (trapcap_ctl(td, p, *(int *)data));
case PROC_TRAPCAP_STATUS:
return (trapcap_status(td, p, data));
+ case PROC_ASLR_CTL:
+ return (aslr_ctl(td, p, *(int *)data));
+ case PROC_ASLR_STATUS:
+ return (aslr_status(td, p, data));
default:
return (EINVAL);
}
@@ -488,6 +556,8 @@
case PROC_REAP_KILL:
case PROC_TRACE_STATUS:
case PROC_TRAPCAP_STATUS:
+ case PROC_ASLR_CTL:
+ case PROC_ASLR_STATUS:
if (idtype != P_PID)
return (EINVAL);
}
@@ -509,6 +579,8 @@
break;
case PROC_TRACE_STATUS:
case PROC_TRAPCAP_STATUS:
+ case PROC_ASLR_CTL:
+ case PROC_ASLR_STATUS:
tree_locked = false;
break;
default:
Index: sys/sys/proc.h
===================================================================
--- sys/sys/proc.h
+++ sys/sys/proc.h
@@ -717,6 +717,9 @@
#define P2_AST_SU 0x00000008 /* Handles SU ast for kthreads. */
#define P2_PTRACE_FSTP 0x00000010 /* SIGSTOP from PT_ATTACH not yet handled. */
#define P2_TRAPCAP 0x00000020 /* SIGTRAP on ENOTCAPABLE */
+#define P2_ASLR_ENABLE 0x00000040 /* Force enable ASLR. */
+#define P2_ASLR_DISABLE 0x00000080 /* Force disable ASLR. */
+#define P2_ASLR_IGNSTART 0x00000100 /* Enable ASLR to consume sbrk area. */
/* Flags protected by proctree_lock, kept in p_treeflags. */
#define P_TREE_ORPHANED 0x00000001 /* Reparented, on orphan list */
Index: sys/sys/procctl.h
===================================================================
--- sys/sys/procctl.h
+++ sys/sys/procctl.h
@@ -49,6 +49,8 @@
#define PROC_TRACE_STATUS 8 /* query tracing status */
#define PROC_TRAPCAP_CTL 9 /* trap capability errors */
#define PROC_TRAPCAP_STATUS 10 /* query trap capability status */
+#define PROC_ASLR_CTL 11 /* en/dis ASLR */
+#define PROC_ASLR_STATUS 12 /* query ASLR status */
/* Operations for PROC_SPROTECT (passed in integer arg). */
#define PPROT_OP(x) ((x) & 0xf)
@@ -111,6 +113,11 @@
#define PROC_TRAPCAP_CTL_ENABLE 1
#define PROC_TRAPCAP_CTL_DISABLE 2
+#define PROC_ASLR_FORCE_ENABLE 1
+#define PROC_ASLR_FORCE_DISABLE 2
+#define PROC_ASLR_NOFORCE 3
+#define PROC_ASLR_ACTIVE 0x80000000
+
#ifndef _KERNEL
__BEGIN_DECLS
int procctl(idtype_t, id_t, int, void *);
Index: sys/sys/sysent.h
===================================================================
--- sys/sys/sysent.h
+++ sys/sys/sysent.h
@@ -138,7 +138,8 @@
#define SV_AOUT 0x008000 /* a.out executable. */
#define SV_SHP 0x010000 /* Shared page. */
#define SV_CAPSICUM 0x020000 /* Force cap_enter() on startup. */
-#define SV_TIMEKEEP 0x040000
+#define SV_TIMEKEEP 0x040000 /* Shared page timehands. */
+#define SV_ASLR 0x080000 /* ASLR allowed. */
#define SV_ABI_MASK 0xff
#define SV_ABI_ERRNO(p, e) ((p)->p_sysent->sv_errsize <= 0 ? e : \
Index: sys/vm/vm_map.h
===================================================================
--- sys/vm/vm_map.h
+++ sys/vm/vm_map.h
@@ -190,6 +190,7 @@
pmap_t pmap; /* (c) Physical map */
#define min_offset header.start /* (c) */
#define max_offset header.end /* (c) */
+ vm_offset_t anon_loc;
int busy;
};
@@ -198,6 +199,8 @@
*/
#define MAP_WIREFUTURE 0x01 /* wire all future pages */
#define MAP_BUSY_WAKEUP 0x02
+#define MAP_ASLR 0x04 /* enabled ASLR */
+#define MAP_ASLR_IGNSTART 0x08
#ifdef _KERNEL
static __inline vm_offset_t
Index: sys/vm/vm_map.c
===================================================================
--- sys/vm/vm_map.c
+++ sys/vm/vm_map.c
@@ -1470,6 +1470,20 @@
return (result);
}
+static const int aslr_pages_rnd_64[2] = {0x1000, 0x10};
+static const int aslr_pages_rnd_32[2] = {0x100, 0x4};
+
+static int aslr_sloppiness = 5;
+SYSCTL_INT(_vm, OID_AUTO, aslr_sloppiness, CTLFLAG_RW, &aslr_sloppiness, 0,
+ "");
+
+static int aslr_collapse_anon = 1;
+SYSCTL_INT(_vm, OID_AUTO, aslr_collapse_anon, CTLFLAG_RW,
+ &aslr_collapse_anon, 0,
+ "");
+
+#define MAP_32BIT_MAX_ADDR ((vm_offset_t)1 << 31)
+
/*
* vm_map_find finds an unallocated region in the target address
* map with the given length. The search is defined to be
@@ -1485,8 +1499,11 @@
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;
+ vm_map_entry_t prev_entry;
+ vm_offset_t alignment, addr_save, start, start1, rand_max, re;
+ const int *aslr_pages_rnd;
+ int result, do_aslr, pidx;
+ bool en_aslr, anon;
KASSERT((cow & (MAP_STACK_GROWS_DOWN | MAP_STACK_GROWS_UP)) == 0 ||
object == NULL,
@@ -1499,21 +1516,86 @@
alignment = (vm_offset_t)1 << (find_space >> 8);
} else
alignment = 0;
- initial_addr = *addr;
+ do_aslr = (map->flags & MAP_ASLR) != 0 ? aslr_sloppiness : 0;
+ en_aslr = do_aslr != 0;
+ anon = object == NULL && (cow & (MAP_INHERIT_SHARE |
+ MAP_STACK_GROWS_UP | MAP_STACK_GROWS_DOWN)) == 0 &&
+ prot != PROT_NONE && aslr_collapse_anon;
+ addr_save = *addr;
+ if (en_aslr) {
+ if (vm_map_max(map) > MAP_32BIT_MAX_ADDR &&
+ (max_addr == 0 || max_addr > MAP_32BIT_MAX_ADDR))
+ aslr_pages_rnd = aslr_pages_rnd_64;
+ else
+ aslr_pages_rnd = aslr_pages_rnd_32;
+ if (find_space != VMFS_NO_SPACE && (map->flags &
+ MAP_ASLR_IGNSTART) != 0) {
+ start = anon ? map->anon_loc : vm_map_min(map);
+ } else {
+ start = anon && *addr == 0 ? map->anon_loc : addr_save;
+ }
+ } else {
+ start = addr_save;
+ }
+ start1 = start; /* for again_any_space restart */
again:
- start = initial_addr;
+ if (en_aslr && (do_aslr == 0 || (anon &&
+ do_aslr == aslr_sloppiness - 1))) {
+ /*
+ * We are either at the last aslr iteration, or anon
+ * coalescing failed on the first try. Retry with
+ * free run.
+ */
+ if ((map->flags & MAP_ASLR_IGNSTART) != 0)
+ start = vm_map_min(map);
+ else
+ start = addr_save;
+ }
+again_any_space:
vm_map_lock(map);
do {
if (find_space != VMFS_NO_SPACE) {
if (vm_map_findspace(map, start, length, addr) ||
(max_addr != 0 && *addr + length > max_addr)) {
vm_map_unlock(map);
+ if (do_aslr > 0) {
+ do_aslr--;
+ goto again;
+ }
if (find_space == VMFS_OPTIMAL_SPACE) {
find_space = VMFS_ANY_SPACE;
- goto again;
+ start = start1;
+ goto again_any_space;
}
return (KERN_NO_SPACE);
}
+ /*
+ * The R step for ASLR. But skip it if we are
+ * trying to coalesce anon memory request.
+ */
+ if (do_aslr > 0 &&
+ !(anon && do_aslr == aslr_sloppiness)) {
+ vm_map_lookup_entry(map, *addr, &prev_entry);
+ if (MAXPAGESIZES > 1 && pagesizes[1] != 0 &&
+ (find_space == VMFS_SUPER_SPACE ||
+ find_space == VMFS_OPTIMAL_SPACE))
+ pidx = 1;
+ else
+ pidx = 0;
+ re = prev_entry->next == &map->header ?
+ map->max_offset : prev_entry->next->start;
+ rand_max = ((max_addr != 0 && re > max_addr) ?
+ max_addr : re) - *addr - length;
+ rand_max /= pagesizes[pidx];
+ if (rand_max < aslr_pages_rnd[pidx]) {
+ vm_map_unlock(map);
+ start = re;
+ do_aslr--;
+ goto again;
+ }
+ *addr += (arc4random() % rand_max) *
+ pagesizes[pidx];
+ }
switch (find_space) {
case VMFS_SUPER_SPACE:
case VMFS_OPTIMAL_SPACE:
@@ -1529,7 +1611,6 @@
}
break;
}
-
start = *addr;
}
if ((cow & (MAP_STACK_GROWS_DOWN | MAP_STACK_GROWS_UP)) != 0) {
@@ -1539,8 +1620,15 @@
result = vm_map_insert(map, object, offset, start,
start + length, prot, max, cow);
}
+ if (result != KERN_SUCCESS && do_aslr > 0) {
+ vm_map_unlock(map);
+ do_aslr--;
+ goto again;
+ }
} while (result == KERN_NO_SPACE && find_space != VMFS_NO_SPACE &&
find_space != VMFS_ANY_SPACE);
+ if (result == KERN_SUCCESS && anon)
+ map->anon_loc = *addr + length;
vm_map_unlock(map);
return (result);
}
@@ -3049,6 +3137,9 @@
pmap_remove(map->pmap, entry->start, entry->end);
+ if (entry->end == map->anon_loc)
+ map->anon_loc = entry->prev->end;
+
/*
* Delete the entry only after removing all pmap
* entries pointing to its pages. (Otherwise, its
Index: usr.bin/proccontrol/proccontrol.c
===================================================================
--- usr.bin/proccontrol/proccontrol.c
+++ usr.bin/proccontrol/proccontrol.c
@@ -42,6 +42,7 @@
MODE_INVALID,
MODE_TRACE,
MODE_TRAPCAP,
+ MODE_ASLR,
};
static pid_t
@@ -62,7 +63,7 @@
usage(void)
{
- fprintf(stderr, "Usage: proccontrol -m (trace|trapcap) [-q] "
+ fprintf(stderr, "Usage: proccontrol -m (trace|trapcap|aslr) [-q] "
"[-s (enable|disable)] [-p pid | command]\n");
exit(1);
}
@@ -85,6 +86,8 @@
mode = MODE_TRACE;
else if (strcmp(optarg, "trapcap") == 0)
mode = MODE_TRAPCAP;
+ else if (strcmp(optarg, "aslr") == 0)
+ mode = MODE_ASLR;
else
usage();
break;
@@ -127,6 +130,9 @@
case MODE_TRAPCAP:
error = procctl(P_PID, pid, PROC_TRAPCAP_STATUS, &arg);
break;
+ case MODE_ASLR:
+ error = procctl(P_PID, pid, PROC_ASLR_STATUS, &arg);
+ break;
default:
usage();
break;
@@ -152,6 +158,23 @@
break;
}
break;
+ case MODE_ASLR:
+ switch (arg & ~PROC_ASLR_ACTIVE) {
+ case PROC_ASLR_FORCE_ENABLE:
+ printf("force enabled");
+ break;
+ case PROC_ASLR_FORCE_DISABLE:
+ printf("force disabled");
+ break;
+ case PROC_ASLR_NOFORCE:
+ printf("not forced");
+ break;
+ }
+ if ((arg & PROC_ASLR_ACTIVE) != 0)
+ printf(", active\n");
+ else
+ printf(", not active\n");
+ break;
}
} else {
switch (mode) {
@@ -165,6 +188,11 @@
PROC_TRAPCAP_CTL_DISABLE;
error = procctl(P_PID, pid, PROC_TRAPCAP_CTL, &arg);
break;
+ case MODE_ASLR:
+ arg = enable ? PROC_ASLR_FORCE_ENABLE :
+ PROC_ASLR_FORCE_DISABLE;
+ error = procctl(P_PID, pid, PROC_ASLR_CTL, &arg);
+ break;
default:
usage();
break;

File Metadata

Mime Type
text/plain
Expires
Mon, Dec 16, 2:50 AM (20 h, 50 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
9092290
Default Alt Text
D5603.id21262.diff (23 KB)

Event Timeline