Date: Tue, 12 Mar 2019 16:33:45 +0000 (UTC) From: Konstantin Belousov <kib@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-12@freebsd.org Subject: svn commit: r345067 - in stable/12: lib/libc/sys sys/amd64/amd64 sys/arm/arm sys/arm64/arm64 sys/compat/freebsd32 sys/compat/ia32 sys/i386/i386 sys/kern sys/mips/mips sys/powerpc/powerpc sys/riscv/... Message-ID: <201903121633.x2CGXjll043779@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: kib Date: Tue Mar 12 16:33:44 2019 New Revision: 345067 URL: https://svnweb.freebsd.org/changeset/base/345067 Log: MFC r343964, r344121, r344128, r344593, r344594: ASLR. Added: stable/12/usr.bin/proccontrol/proccontrol.1 - copied unchanged from r344594, head/usr.bin/proccontrol/proccontrol.1 Modified: stable/12/lib/libc/sys/procctl.2 stable/12/sys/amd64/amd64/elf_machdep.c stable/12/sys/arm/arm/elf_machdep.c stable/12/sys/arm64/arm64/elf_machdep.c stable/12/sys/compat/freebsd32/freebsd32_misc.c stable/12/sys/compat/ia32/ia32_sysvec.c stable/12/sys/i386/i386/elf_machdep.c stable/12/sys/kern/imgact_elf.c stable/12/sys/kern/kern_exec.c stable/12/sys/kern/kern_fork.c stable/12/sys/kern/kern_procctl.c stable/12/sys/mips/mips/elf_machdep.c stable/12/sys/powerpc/powerpc/elf32_machdep.c stable/12/sys/powerpc/powerpc/elf64_machdep.c stable/12/sys/riscv/riscv/elf_machdep.c stable/12/sys/sparc64/sparc64/elf_machdep.c stable/12/sys/sys/imgact.h stable/12/sys/sys/proc.h stable/12/sys/sys/procctl.h stable/12/sys/sys/sysent.h stable/12/sys/vm/vm_map.c stable/12/sys/vm/vm_map.h stable/12/usr.bin/proccontrol/Makefile stable/12/usr.bin/proccontrol/proccontrol.c Directory Properties: stable/12/ (props changed) Modified: stable/12/lib/libc/sys/procctl.2 ============================================================================== --- stable/12/lib/libc/sys/procctl.2 Tue Mar 12 16:21:39 2019 (r345066) +++ stable/12/lib/libc/sys/procctl.2 Tue Mar 12 16:33:44 2019 (r345067) @@ -72,6 +72,46 @@ The control request to perform is specified by the argument. The following commands are supported: .Bl -tag -width PROC_TRAPCAP_STATUS +.It Dv PROC_ASLR_CTL +Controls the Address Space Layout Randomization (ASLR) in the program +images created +by +.Xr execve 2 +in the specified process or its descendants that did not changed +the control nor modified it by other means. +The +.Va arg +parameter must point to the integer variable holding one of the following +values: +.Bl -tag -width PROC_ASLR_FORCE_DISABLE +.It Dv PROC_ASLR_FORCE_ENABLE +Request that ASLR is enabled after execution, even if it is disabled +system-wide. +The image flag and set-uid might prevent ASLR enablement still. +.It Dv PROC_ASLR_FORCE_DISABLE +Request that ASLR is disabled after execution. +Same notes as for +.Dv PROC_ASKR_FORCE_ENABLE +apply. +.It Dv PROC_ASLR_NOFORCE +Use system-wide configured policy for ASLR. +.El +.It Dv PROC_ASLR_STATUS +Returns the current status of ASLR enablement for the target process. +The +.Va arg +parameter must point to the integer variable, where one of the +following values is written: +.Bl -tag -width PROC_ASLR_FORCE_DISABLE +.It Dv PROC_ASLR_FORCE_ENABLE +.It Dv PROC_ASLR_FORCE_DISABLE +.It Dv PROC_ASLR_NOFORCE +.El +.Pp +If the currently executed image in the process itself has ASLR enabled, +the +.Dv PROC_ASLR_ACTIVE +flag is or-ed with the value listed above. .It Dv PROC_SPROTECT Set process protection state. This is used to mark a process as protected from being killed if the system @@ -543,11 +583,16 @@ The .Fn procctl function appeared in .Fx 10.0 . +.Pp The reaper facility is based on a similar feature of Linux and DragonflyBSD, and first appeared in .Fx 10.2 . +.Pp The .Dv PROC_PDEATHSIG_CTL facility is based on the prctl(PR_SET_PDEATHSIG, ...) feature of Linux, and first appeared in .Fx 11.2 . +.Pp +The ASLR support was added to system for the checklists compliance in +.Fx 13.0 . Modified: stable/12/sys/amd64/amd64/elf_machdep.c ============================================================================== --- stable/12/sys/amd64/amd64/elf_machdep.c Tue Mar 12 16:21:39 2019 (r345066) +++ stable/12/sys/amd64/amd64/elf_machdep.c Tue Mar 12 16:33:44 2019 (r345067) @@ -74,7 +74,8 @@ struct sysentvec elf64_freebsd_sysvec = { .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_ASLR | SV_LP64 | SV_SHP | + SV_TIMEKEEP, .sv_set_syscall_retval = cpu_set_syscall_retval, .sv_fetch_syscall_args = cpu_fetch_syscall_args, .sv_syscallnames = syscallnames, Modified: stable/12/sys/arm/arm/elf_machdep.c ============================================================================== --- stable/12/sys/arm/arm/elf_machdep.c Tue Mar 12 16:21:39 2019 (r345066) +++ stable/12/sys/arm/arm/elf_machdep.c Tue Mar 12 16:33:44 2019 (r345067) @@ -83,9 +83,9 @@ struct sysentvec elf32_freebsd_sysvec = { .sv_maxssiz = NULL, .sv_flags = #if __ARM_ARCH >= 6 - SV_SHP | SV_TIMEKEEP | + SV_ASLR | SV_SHP | SV_TIMEKEEP | #endif - SV_ABI_FREEBSD | SV_ILP32, + SV_ABI_FREEBSD | SV_ILP32 | SV_ASLR, .sv_set_syscall_retval = cpu_set_syscall_retval, .sv_fetch_syscall_args = cpu_fetch_syscall_args, .sv_syscallnames = syscallnames, Modified: stable/12/sys/arm64/arm64/elf_machdep.c ============================================================================== --- stable/12/sys/arm64/arm64/elf_machdep.c Tue Mar 12 16:21:39 2019 (r345066) +++ stable/12/sys/arm64/arm64/elf_machdep.c Tue Mar 12 16:33:44 2019 (r345067) @@ -80,7 +80,8 @@ static struct sysentvec elf64_freebsd_sysvec = { .sv_setregs = exec_setregs, .sv_fixlimit = NULL, .sv_maxssiz = NULL, - .sv_flags = SV_SHP | SV_TIMEKEEP | SV_ABI_FREEBSD | SV_LP64, + .sv_flags = SV_SHP | SV_TIMEKEEP | SV_ABI_FREEBSD | SV_LP64 | + SV_ASLR, .sv_set_syscall_retval = cpu_set_syscall_retval, .sv_fetch_syscall_args = cpu_fetch_syscall_args, .sv_syscallnames = syscallnames, Modified: stable/12/sys/compat/freebsd32/freebsd32_misc.c ============================================================================== --- stable/12/sys/compat/freebsd32/freebsd32_misc.c Tue Mar 12 16:21:39 2019 (r345066) +++ stable/12/sys/compat/freebsd32/freebsd32_misc.c Tue Mar 12 16:33:44 2019 (r345067) @@ -3351,6 +3351,7 @@ freebsd32_procctl(struct thread *td, struct freebsd32_ int error, error1, flags, signum; switch (uap->com) { + case PROC_ASLR_CTL: case PROC_SPROTECT: case PROC_TRACE_CTL: case PROC_TRAPCAP_CTL: @@ -3382,6 +3383,7 @@ freebsd32_procctl(struct thread *td, struct freebsd32_ return (error); data = &x.rk; break; + case PROC_ASLR_STATUS: case PROC_TRACE_STATUS: case PROC_TRAPCAP_STATUS: data = &flags; @@ -3410,6 +3412,7 @@ freebsd32_procctl(struct thread *td, struct freebsd32_ if (error == 0) error = error1; break; + case PROC_ASLR_STATUS: case PROC_TRACE_STATUS: case PROC_TRAPCAP_STATUS: if (error == 0) Modified: stable/12/sys/compat/ia32/ia32_sysvec.c ============================================================================== --- stable/12/sys/compat/ia32/ia32_sysvec.c Tue Mar 12 16:21:39 2019 (r345066) +++ stable/12/sys/compat/ia32/ia32_sysvec.c Tue Mar 12 16:33:44 2019 (r345067) @@ -120,7 +120,7 @@ struct sysentvec ia32_freebsd_sysvec = { .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_ASLR | SV_IA32 | SV_ILP32 | SV_SHP | SV_TIMEKEEP, .sv_set_syscall_retval = ia32_set_syscall_retval, .sv_fetch_syscall_args = ia32_fetch_syscall_args, Modified: stable/12/sys/i386/i386/elf_machdep.c ============================================================================== --- stable/12/sys/i386/i386/elf_machdep.c Tue Mar 12 16:21:39 2019 (r345066) +++ stable/12/sys/i386/i386/elf_machdep.c Tue Mar 12 16:33:44 2019 (r345067) @@ -76,8 +76,8 @@ struct sysentvec elf32_freebsd_sysvec = { .sv_setregs = exec_setregs, .sv_fixlimit = NULL, .sv_maxssiz = NULL, - .sv_flags = SV_ABI_FREEBSD | SV_IA32 | SV_ILP32 | SV_SHP | - SV_TIMEKEEP, + .sv_flags = SV_ABI_FREEBSD | SV_ASLR | SV_IA32 | SV_ILP32 | + SV_SHP | SV_TIMEKEEP, .sv_set_syscall_retval = cpu_set_syscall_retval, .sv_fetch_syscall_args = cpu_fetch_syscall_args, .sv_syscallnames = syscallnames, Modified: stable/12/sys/kern/imgact_elf.c ============================================================================== --- stable/12/sys/kern/imgact_elf.c Tue Mar 12 16:21:39 2019 (r345066) +++ stable/12/sys/kern/imgact_elf.c Tue Mar 12 16:33:44 2019 (r345067) @@ -137,6 +137,27 @@ SYSCTL_INT(_kern_elf32, OID_AUTO, read_exec, CTLFLAG_R #endif #endif +SYSCTL_NODE(__CONCAT(_kern_elf, __ELF_WORD_SIZE), OID_AUTO, aslr, CTLFLAG_RW, 0, + ""); +#define ASLR_NODE_OID __CONCAT(__CONCAT(_kern_elf, __ELF_WORD_SIZE), _aslr) + +static int __elfN(aslr_enabled) = 0; +SYSCTL_INT(ASLR_NODE_OID, OID_AUTO, enable, CTLFLAG_RWTUN, + &__elfN(aslr_enabled), 0, + __XSTRING(__CONCAT(ELF, __ELF_WORD_SIZE)) + ": enable address map randomization"); + +static int __elfN(pie_aslr_enabled) = 0; +SYSCTL_INT(ASLR_NODE_OID, OID_AUTO, pie_enable, 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) = 1; +SYSCTL_INT(ASLR_NODE_OID, OID_AUTO, 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) @@ -774,6 +795,36 @@ fail: return (error); } +static u_long +__CONCAT(rnd_, __elfN(base))(vm_map_t map __unused, u_long minv, u_long maxv, + u_int align) +{ + u_long rbase, res; + + MPASS(vm_map_min(map) <= minv); + MPASS(maxv <= vm_map_max(map)); + MPASS(minv < maxv); + MPASS(minv + align < maxv); + arc4rand(&rbase, sizeof(rbase), 0); + res = roundup(minv, (u_long)align) + rbase % (maxv - minv); + res &= ~((u_long)align - 1); + if (res >= maxv) + res -= align; + KASSERT(res >= minv, + ("res %#lx < minv %#lx, maxv %#lx rbase %#lx", + res, minv, maxv, rbase)); + KASSERT(res < maxv, + ("res %#lx > maxv %#lx, minv %#lx rbase %#lx", + res, maxv, minv, 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) { @@ -782,6 +833,7 @@ __CONCAT(exec_, __elfN(imgact))(struct image_params *i 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; @@ -789,6 +841,7 @@ __CONCAT(exec_, __elfN(imgact))(struct image_params *i 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, maxv1; uint32_t fctl0; int32_t osrel; int error, i, n, interp_name_len, have_interp; @@ -832,12 +885,17 @@ __CONCAT(exec_, __elfN(imgact))(struct image_params *i 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: @@ -898,6 +956,7 @@ __CONCAT(exec_, __elfN(imgact))(struct image_params *i 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) { @@ -909,10 +968,18 @@ __CONCAT(exec_, __elfN(imgact))(struct image_params *i * 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; + if (baddr == 0) { + if ((sv->sv_flags & SV_ASLR) == 0 || + (fctl0 & NT_FREEBSD_FCTL_ASLR_DISABLE) != 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; + } } - sv = brand_info->sysvec; if (interp != NULL && brand_info->interp_newpath != NULL) newinterp = brand_info->interp_newpath; @@ -929,9 +996,54 @@ __CONCAT(exec_, __elfN(imgact))(struct image_params *i */ VOP_UNLOCK(imgp->vp, 0); + /* + * Decide whether 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 || + (fctl0 & NT_FREEBSD_FCTL_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) { + imgp->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) + imgp->map_flags |= MAP_ASLR_IGNSTART; + } + error = exec_new_vmspace(imgp, sv); + vmspace = imgp->proc->p_vmspace; + map = &vmspace->vm_map; + imgp->proc->p_sysent = sv; + 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))(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) goto ret; @@ -1023,7 +1135,6 @@ __CONCAT(exec_, __elfN(imgact))(struct image_params *i 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; @@ -1037,6 +1148,14 @@ __CONCAT(exec_, __elfN(imgact))(struct image_params *i */ addr = round_page((vm_offset_t)vmspace->vm_daddr + lim_max(td, RLIMIT_DATA)); + if ((map->flags & MAP_ASLR) != 0) { + maxv1 = maxv / 2 + addr / 2; + MPASS(maxv1 >= addr); /* No overflow */ + map->anon_loc = __CONCAT(rnd_, __elfN(base))(map, addr, maxv1, + MAXPAGESIZES > 1 ? pagesizes[1] : pagesizes[0]); + } else { + map->anon_loc = addr; + } PROC_UNLOCK(imgp->proc); imgp->entry_addr = entry; @@ -1044,6 +1163,13 @@ __CONCAT(exec_, __elfN(imgact))(struct image_params *i if (interp != NULL) { have_interp = FALSE; VOP_UNLOCK(imgp->vp, 0); + if ((map->flags & MAP_ASLR) != 0) { + /* Assume that interpeter fits into 1/4 of AS */ + maxv1 = maxv / 2 + addr / 2; + MPASS(maxv1 >= addr); /* No overflow */ + addr = __CONCAT(rnd_, __elfN(base))(map, addr, + maxv1, PAGE_SIZE); + } if (brand_info->emul_path != NULL && brand_info->emul_path[0] != '\0') { path = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); Modified: stable/12/sys/kern/kern_exec.c ============================================================================== --- stable/12/sys/kern/kern_exec.c Tue Mar 12 16:21:39 2019 (r345066) +++ stable/12/sys/kern/kern_exec.c Tue Mar 12 16:33:44 2019 (r345067) @@ -1104,9 +1104,13 @@ exec_new_vmspace(struct image_params *imgp, struct sys shmexit(vmspace); pmap_remove_pages(vmspace_pmap(vmspace)); vm_map_remove(map, vm_map_min(map), vm_map_max(map)); - /* An exec terminates mlockall(MCL_FUTURE). */ + /* + * An exec terminates mlockall(MCL_FUTURE), ASLR state + * must be re-evaluated. + */ vm_map_lock(map); - vm_map_modflags(map, 0, MAP_WIREFUTURE); + vm_map_modflags(map, 0, MAP_WIREFUTURE | MAP_ASLR | + MAP_ASLR_IGNSTART); vm_map_unlock(map); } else { error = vmspace_exec(p, sv_minuser, sv->sv_maxuser); @@ -1115,6 +1119,7 @@ exec_new_vmspace(struct image_params *imgp, struct sys vmspace = p->p_vmspace; map = &vmspace->vm_map; } + map->flags |= imgp->map_flags; /* Map a shared page */ obj = sv->sv_shared_page_obj; Modified: stable/12/sys/kern/kern_fork.c ============================================================================== --- stable/12/sys/kern/kern_fork.c Tue Mar 12 16:21:39 2019 (r345066) +++ stable/12/sys/kern/kern_fork.c Tue Mar 12 16:33:44 2019 (r345067) @@ -507,7 +507,8 @@ do_fork(struct thread *td, struct fork_req *fr, struct * 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_ASLR_DISABLE | P2_ASLR_ENABLE | + P2_ASLR_IGNSTART | P2_NOTRACE | P2_NOTRACE_EXEC | P2_TRAPCAP); p2->p_swtick = ticks; if (p1->p_flag & P_PROFIL) startprofclock(p2); Modified: stable/12/sys/kern/kern_procctl.c ============================================================================== --- stable/12/sys/kern/kern_procctl.c Tue Mar 12 16:21:39 2019 (r345066) +++ stable/12/sys/kern/kern_procctl.c Tue Mar 12 16:33:44 2019 (r345067) @@ -43,6 +43,11 @@ __FBSDID("$FreeBSD$"); #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) { @@ -413,6 +418,62 @@ trapcap_status(struct thread *td, struct proc *p, int 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; @@ -434,6 +495,7 @@ sys_procctl(struct thread *td, struct procctl_args *ua int error, error1, flags, signum; switch (uap->com) { + case PROC_ASLR_CTL: case PROC_SPROTECT: case PROC_TRACE_CTL: case PROC_TRAPCAP_CTL: @@ -463,6 +525,7 @@ sys_procctl(struct thread *td, struct procctl_args *ua return (error); data = &x.rk; break; + case PROC_ASLR_STATUS: case PROC_TRACE_STATUS: case PROC_TRAPCAP_STATUS: data = &flags; @@ -490,6 +553,7 @@ sys_procctl(struct thread *td, struct procctl_args *ua if (error == 0) error = error1; break; + case PROC_ASLR_STATUS: case PROC_TRACE_STATUS: case PROC_TRAPCAP_STATUS: if (error == 0) @@ -509,6 +573,10 @@ kern_procctl_single(struct thread *td, struct proc *p, PROC_LOCK_ASSERT(p, MA_OWNED); switch (com) { + case PROC_ASLR_CTL: + return (aslr_ctl(td, p, *(int *)data)); + case PROC_ASLR_STATUS: + return (aslr_status(td, p, data)); case PROC_SPROTECT: return (protect_set(td, p, *(int *)data)); case PROC_REAP_ACQUIRE: @@ -544,6 +612,8 @@ kern_procctl(struct thread *td, idtype_t idtype, id_t bool tree_locked; switch (com) { + case PROC_ASLR_CTL: + case PROC_ASLR_STATUS: case PROC_REAP_ACQUIRE: case PROC_REAP_RELEASE: case PROC_REAP_STATUS: @@ -593,6 +663,8 @@ kern_procctl(struct thread *td, idtype_t idtype, id_t sx_xlock(&proctree_lock); tree_locked = true; break; + case PROC_ASLR_CTL: + case PROC_ASLR_STATUS: case PROC_TRACE_STATUS: case PROC_TRAPCAP_STATUS: tree_locked = false; Modified: stable/12/sys/mips/mips/elf_machdep.c ============================================================================== --- stable/12/sys/mips/mips/elf_machdep.c Tue Mar 12 16:21:39 2019 (r345066) +++ stable/12/sys/mips/mips/elf_machdep.c Tue Mar 12 16:33:44 2019 (r345067) @@ -77,7 +77,7 @@ struct sysentvec elf64_freebsd_sysvec = { .sv_setregs = exec_setregs, .sv_fixlimit = NULL, .sv_maxssiz = NULL, - .sv_flags = SV_ABI_FREEBSD | SV_LP64, + .sv_flags = SV_ABI_FREEBSD | SV_LP64 | SV_ASLR, .sv_set_syscall_retval = cpu_set_syscall_retval, .sv_fetch_syscall_args = cpu_fetch_syscall_args, .sv_syscallnames = syscallnames, @@ -133,7 +133,7 @@ struct sysentvec elf32_freebsd_sysvec = { .sv_setregs = exec_setregs, .sv_fixlimit = NULL, .sv_maxssiz = NULL, - .sv_flags = SV_ABI_FREEBSD | SV_ILP32, + .sv_flags = SV_ABI_FREEBSD | SV_ILP32 | SV_ASLR, .sv_set_syscall_retval = cpu_set_syscall_retval, .sv_fetch_syscall_args = cpu_fetch_syscall_args, .sv_syscallnames = syscallnames, Modified: stable/12/sys/powerpc/powerpc/elf32_machdep.c ============================================================================== --- stable/12/sys/powerpc/powerpc/elf32_machdep.c Tue Mar 12 16:21:39 2019 (r345066) +++ stable/12/sys/powerpc/powerpc/elf32_machdep.c Tue Mar 12 16:33:44 2019 (r345067) @@ -116,7 +116,7 @@ struct sysentvec elf32_freebsd_sysvec = { .sv_fixlimit = NULL, #endif .sv_maxssiz = NULL, - .sv_flags = SV_ABI_FREEBSD | SV_ILP32 | SV_SHP, + .sv_flags = SV_ABI_FREEBSD | SV_ILP32 | SV_SHP | SV_ASLR, .sv_set_syscall_retval = cpu_set_syscall_retval, .sv_fetch_syscall_args = cpu_fetch_syscall_args, .sv_shared_page_base = FREEBSD32_SHAREDPAGE, Modified: stable/12/sys/powerpc/powerpc/elf64_machdep.c ============================================================================== --- stable/12/sys/powerpc/powerpc/elf64_machdep.c Tue Mar 12 16:21:39 2019 (r345066) +++ stable/12/sys/powerpc/powerpc/elf64_machdep.c Tue Mar 12 16:33:44 2019 (r345067) @@ -80,7 +80,7 @@ struct sysentvec elf64_freebsd_sysvec_v1 = { .sv_setregs = exec_setregs_funcdesc, .sv_fixlimit = NULL, .sv_maxssiz = NULL, - .sv_flags = SV_ABI_FREEBSD | SV_LP64 | SV_SHP, + .sv_flags = SV_ABI_FREEBSD | SV_LP64 | SV_SHP | SV_ASLR, .sv_set_syscall_retval = cpu_set_syscall_retval, .sv_fetch_syscall_args = cpu_fetch_syscall_args, .sv_syscallnames = syscallnames, Modified: stable/12/sys/riscv/riscv/elf_machdep.c ============================================================================== --- stable/12/sys/riscv/riscv/elf_machdep.c Tue Mar 12 16:21:39 2019 (r345066) +++ stable/12/sys/riscv/riscv/elf_machdep.c Tue Mar 12 16:33:44 2019 (r345067) @@ -83,7 +83,7 @@ struct sysentvec elf64_freebsd_sysvec = { .sv_setregs = exec_setregs, .sv_fixlimit = NULL, .sv_maxssiz = NULL, - .sv_flags = SV_ABI_FREEBSD | SV_LP64, + .sv_flags = SV_ABI_FREEBSD | SV_LP64 | SV_ASLR, .sv_set_syscall_retval = cpu_set_syscall_retval, .sv_fetch_syscall_args = cpu_fetch_syscall_args, .sv_syscallnames = syscallnames, Modified: stable/12/sys/sparc64/sparc64/elf_machdep.c ============================================================================== --- stable/12/sys/sparc64/sparc64/elf_machdep.c Tue Mar 12 16:21:39 2019 (r345066) +++ stable/12/sys/sparc64/sparc64/elf_machdep.c Tue Mar 12 16:33:44 2019 (r345067) @@ -81,7 +81,7 @@ static struct sysentvec elf64_freebsd_sysvec = { .sv_setregs = exec_setregs, .sv_fixlimit = NULL, .sv_maxssiz = NULL, - .sv_flags = SV_ABI_FREEBSD | SV_LP64, + .sv_flags = SV_ABI_FREEBSD | SV_LP64 | SV_ASLR, .sv_set_syscall_retval = cpu_set_syscall_retval, .sv_fetch_syscall_args = cpu_fetch_syscall_args, .sv_syscallnames = syscallnames, Modified: stable/12/sys/sys/imgact.h ============================================================================== --- stable/12/sys/sys/imgact.h Tue Mar 12 16:21:39 2019 (r345066) +++ stable/12/sys/sys/imgact.h Tue Mar 12 16:33:44 2019 (r345067) @@ -88,6 +88,7 @@ struct image_params { u_long stack_sz; struct ucred *newcred; /* new credentials if changing */ bool credential_setid; /* true if becoming setid */ + u_int map_flags; }; #ifdef _KERNEL Modified: stable/12/sys/sys/proc.h ============================================================================== --- stable/12/sys/sys/proc.h Tue Mar 12 16:21:39 2019 (r345066) +++ stable/12/sys/sys/proc.h Tue Mar 12 16:33:44 2019 (r345067) @@ -752,6 +752,9 @@ struct proc { #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 */ Modified: stable/12/sys/sys/procctl.h ============================================================================== --- stable/12/sys/sys/procctl.h Tue Mar 12 16:21:39 2019 (r345066) +++ stable/12/sys/sys/procctl.h Tue Mar 12 16:33:44 2019 (r345067) @@ -53,6 +53,8 @@ #define PROC_TRAPCAP_STATUS 10 /* query trap capability status */ #define PROC_PDEATHSIG_CTL 11 /* set parent death signal */ #define PROC_PDEATHSIG_STATUS 12 /* get parent death signal */ +#define PROC_ASLR_CTL 13 /* en/dis ASLR */ +#define PROC_ASLR_STATUS 14 /* query ASLR status */ /* Operations for PROC_SPROTECT (passed in integer arg). */ #define PPROT_OP(x) ((x) & 0xf) @@ -115,6 +117,11 @@ struct procctl_reaper_kill { #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 Modified: stable/12/sys/sys/sysent.h ============================================================================== --- stable/12/sys/sys/sysent.h Tue Mar 12 16:21:39 2019 (r345066) +++ stable/12/sys/sys/sysent.h Tue Mar 12 16:33:44 2019 (r345067) @@ -145,6 +145,7 @@ struct sysentvec { #define SV_SHP 0x010000 /* Shared page. */ #define SV_CAPSICUM 0x020000 /* Force cap_enter() on startup. */ #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 : \ Modified: stable/12/sys/vm/vm_map.c ============================================================================== --- stable/12/sys/vm/vm_map.c Tue Mar 12 16:21:39 2019 (r345066) +++ stable/12/sys/vm/vm_map.c Tue Mar 12 16:33:44 2019 (r345067) @@ -801,6 +801,7 @@ _vm_map_init(vm_map_t map, pmap_t pmap, vm_offset_t mi map->root = NULL; map->timestamp = 0; map->busy = 0; + map->anon_loc = 0; } void @@ -1480,6 +1481,36 @@ vm_map_fixed(vm_map_t map, vm_object_t object, vm_ooff return (result); } +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) +{ + + switch (cluster_anon) { + case 0: + return (false); + case 1: + return (addr == 0); + case 2: + default: + return (true); + } +} + +static long aslr_restarts; +SYSCTL_LONG(_vm, OID_AUTO, aslr_restarts, CTLFLAG_RD, + &aslr_restarts, 0, + "Number of aslr failures"); + +#define MAP_32BIT_MAX_ADDR ((vm_offset_t)1 << 31) + /* * Searches for the specified amount of free space in the given map with the * specified alignment. Performs an address-ordered, first-fit search from @@ -1559,8 +1590,9 @@ vm_map_find(vm_map_t map, vm_object_t object, vm_ooffs 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, min_addr; - int rv; + vm_offset_t alignment, curr_min_addr, min_addr; + int gap, pidx, rv, try; + bool cluster, en_aslr, update_anon; KASSERT((cow & (MAP_STACK_GROWS_DOWN | MAP_STACK_GROWS_UP)) == 0 || object == NULL, @@ -1575,24 +1607,96 @@ vm_map_find(vm_map_t map, vm_object_t object, vm_ooffs alignment = (vm_offset_t)1 << (find_space >> 8); } else alignment = 0; + en_aslr = (map->flags & MAP_ASLR) != 0; + update_anon = cluster = clustering_anon_allowed(*addr) && + (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 | + MAP_STACK_GROWS_DOWN)) == 0 && prot != PROT_NONE; + curr_min_addr = min_addr = *addr; + if (en_aslr && min_addr == 0 && !cluster && + find_space != VMFS_NO_SPACE && + (map->flags & MAP_ASLR_IGNSTART) != 0) + curr_min_addr = min_addr = vm_map_min(map); + try = 0; vm_map_lock(map); + if (cluster) { + curr_min_addr = map->anon_loc; + if (curr_min_addr == 0) + cluster = false; + } if (find_space != VMFS_NO_SPACE) { KASSERT(find_space == VMFS_ANY_SPACE || find_space == VMFS_OPTIMAL_SPACE || find_space == VMFS_SUPER_SPACE || alignment != 0, ("unexpected VMFS flag")); - min_addr = *addr; again: - if (vm_map_findspace(map, min_addr, length, addr) || + /* + * When creating an anonymous mapping, try clustering + * with an existing anonymous mapping first. + * + * We make up to two attempts to find address space + * for a given find_space value. The first attempt may + * apply randomization or may cluster with an existing + * anonymous mapping. If this first attempt fails, + * perform a first-fit search of the available address + * space. + * + * If all tries failed, and find_space is + * VMFS_OPTIMAL_SPACE, fallback to VMFS_ANY_SPACE. + * Again enable clustering and randomization. + */ + try++; + MPASS(try <= 2); + + if (try == 2) { + /* + * Second try: we failed either to find a + * suitable region for randomizing the + * allocation, or to cluster with an existing + * mapping. Retry with free run. + */ + curr_min_addr = (map->flags & MAP_ASLR_IGNSTART) != 0 ? + vm_map_min(map) : min_addr; + atomic_add_long(&aslr_restarts, 1); + } + + if (try == 1 && en_aslr && !cluster) { + /* + * Find space for allocation, including + * gap needed for later randomization. + */ + pidx = MAXPAGESIZES > 1 && pagesizes[1] != 0 && + (find_space == VMFS_SUPER_SPACE || find_space == + VMFS_OPTIMAL_SPACE) ? 1 : 0; + gap = vm_map_max(map) > MAP_32BIT_MAX_ADDR && + (max_addr == 0 || max_addr > MAP_32BIT_MAX_ADDR) ? + aslr_pages_rnd_64[pidx] : aslr_pages_rnd_32[pidx]; + if (vm_map_findspace(map, curr_min_addr, length + + gap * pagesizes[pidx], addr) || + (max_addr != 0 && *addr + length > max_addr)) + goto again; + /* And randomize the start address. */ + *addr += (arc4random() % gap) * pagesizes[pidx]; + } else if (vm_map_findspace(map, curr_min_addr, length, addr) || (max_addr != 0 && *addr + length > max_addr)) { + if (cluster) { + cluster = false; + MPASS(try == 1); + goto again; + } rv = KERN_NO_SPACE; goto done; } + if (find_space != VMFS_ANY_SPACE && (rv = vm_map_alignspace(map, object, offset, addr, length, max_addr, alignment)) != KERN_SUCCESS) { if (find_space == VMFS_OPTIMAL_SPACE) { find_space = VMFS_ANY_SPACE; + curr_min_addr = min_addr; + cluster = update_anon; + try = 0; goto again; } goto done; @@ -1613,6 +1717,8 @@ again: rv = vm_map_insert(map, object, offset, *addr, *addr + length, prot, max, cow); } + if (rv == KERN_SUCCESS && update_anon) + map->anon_loc = *addr + length; done: vm_map_unlock(map); return (rv); @@ -1922,8 +2028,14 @@ vm_map_submap( vm_map_t submap) { vm_map_entry_t entry; - int result = KERN_INVALID_ARGUMENT; + int result; + result = KERN_INVALID_ARGUMENT; + + vm_map_lock(submap); + submap->flags |= MAP_IS_SUB_MAP; + vm_map_unlock(submap); + vm_map_lock(map); VM_MAP_RANGE_CHECK(map, start, end); @@ -1944,6 +2056,11 @@ vm_map_submap( } vm_map_unlock(map); + if (result != KERN_SUCCESS) { + vm_map_lock(submap); + submap->flags &= ~MAP_IS_SUB_MAP; + vm_map_unlock(submap); + } return (result); } @@ -3170,6 +3287,9 @@ vm_map_delete(vm_map_t map, vm_offset_t start, vm_offs entry->object.vm_object != NULL) pmap_remove(map->pmap, entry->start, entry->end); + if (entry->end == map->anon_loc) + map->anon_loc = entry->start; + /* * Delete the entry only after removing all pmap * entries pointing to its pages. (Otherwise, its @@ -3452,6 +3572,8 @@ vmspace_fork(struct vmspace *vm1, vm_ooffset_t *fork_c vmspace_free(vm2); return (NULL); } + + new_map->anon_loc = old_map->anon_loc; old_entry = old_map->header.next; Modified: stable/12/sys/vm/vm_map.h ============================================================================== --- stable/12/sys/vm/vm_map.h Tue Mar 12 16:21:39 2019 (r345066) +++ stable/12/sys/vm/vm_map.h Tue Mar 12 16:33:44 2019 (r345067) @@ -202,6 +202,7 @@ struct vm_map { vm_flags_t flags; /* flags for this vm_map */ vm_map_entry_t root; /* Root of a binary search tree */ pmap_t pmap; /* (c) Physical map */ + vm_offset_t anon_loc; int busy; }; @@ -210,6 +211,9 @@ struct vm_map { */ #define MAP_WIREFUTURE 0x01 /* wire all future pages */ #define MAP_BUSY_WAKEUP 0x02 +#define MAP_IS_SUB_MAP 0x04 /* has parent */ +#define MAP_ASLR 0x08 /* enabled ASLR */ +#define MAP_ASLR_IGNSTART 0x10 #ifdef _KERNEL #if defined(KLD_MODULE) && !defined(KLD_TIED) Modified: stable/12/usr.bin/proccontrol/Makefile ============================================================================== --- stable/12/usr.bin/proccontrol/Makefile Tue Mar 12 16:21:39 2019 (r345066) +++ stable/12/usr.bin/proccontrol/Makefile Tue Mar 12 16:33:44 2019 (r345067) @@ -2,6 +2,5 @@ PROG= proccontrol WARNS?= 6 -MAN= .include <bsd.prog.mk> Copied: stable/12/usr.bin/proccontrol/proccontrol.1 (from r344594, head/usr.bin/proccontrol/proccontrol.1) ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ stable/12/usr.bin/proccontrol/proccontrol.1 Tue Mar 12 16:33:44 2019 (r345067, copy of r344594, head/usr.bin/proccontrol/proccontrol.1) @@ -0,0 +1,123 @@ +.\" Copyright (c) 2019 The FreeBSD Foundation, Inc. +.\" All rights reserved. +.\" +.\" This documentation was written by +.\" Konstantin Belousov <kib@FreeBSD.org> under sponsorship +.\" from the FreeBSD Foundation. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.\" +.Dd February 22, 2019 +.Dt PROCCONTROL 1 +.Os +.Sh NAME +.Nm proccontrol +.Nd Control some process execution aspects +.Sh SYNOPSIS +.Nm +.Fl m Ar mode +.Op Fl s Ar control +.Op Fl q +.Fl p Ar pid | command +.Sh DESCRIPTION +The +.Nm +command modifies the execution parameter of existing process +specified by the +.Ar pid +argument, or starts execution of the new program +.Ar command +with the execution parameter set for it. +.Pp +Which execution parameter is changed, selected by the mandatory +parameter +.Ar mode . +Possible values for +.Ar mode +are: +.Bl -tag -width trapcap +.It Ar aslr +Control the Address Space Layout Randomization. +Only applicable to the new process spawned. +.It Ar trace +Control the permission for debuggers to attach. +.It Ar trapcap +Controls the signalling of capability mode access violations. +.El +.Pp +The +Ar control +specifies if the selected +.Ar mode +should be enabled or disabled. +Possible values are +.Ar enable +and +.Ar disable , +with the default value being +.Ar enable +if not specified. +See +.Xr procctl 2 +for detailed description of each mode effects and interaction with other +process control facilities. +.Pp +The +.Op Fl q +switch makes the utility query and print the current setting for +the selected mode. +.Sh EXIT STATUS *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201903121633.x2CGXjll043779>