Index: sys/amd64/amd64/elf_machdep.c =================================================================== --- sys/amd64/amd64/elf_machdep.c +++ sys/amd64/amd64/elf_machdep.c @@ -26,12 +26,15 @@ #include __FBSDID("$FreeBSD$"); +#include "opt_pax.h" + #include #include #include #include #include #include +#include #include #include #include @@ -81,6 +84,9 @@ .sv_shared_page_base = SHAREDPAGE, .sv_shared_page_len = PAGE_SIZE, .sv_schedtail = NULL, +#ifdef PAX_ASLR + .sv_pax_aslr_init = _pax_aslr_init, +#endif }; INIT_SYSENTVEC(elf64_sysvec, &elf64_freebsd_sysvec); Index: sys/amd64/include/vmparam.h =================================================================== --- sys/amd64/include/vmparam.h +++ sys/amd64/include/vmparam.h @@ -170,7 +170,7 @@ #define VM_MAXUSER_ADDRESS UVADDR(NUPML4E, 0, 0, 0) #define SHAREDPAGE (VM_MAXUSER_ADDRESS - PAGE_SIZE) -#define USRSTACK SHAREDPAGE +#define USRSTACK (SHAREDPAGE - 4*PAGE_SIZE) #define VM_MAX_ADDRESS UPT_MAX_ADDRESS #define VM_MIN_ADDRESS (0) Index: sys/amd64/linux32/linux32_sysvec.c =================================================================== --- sys/amd64/linux32/linux32_sysvec.c +++ sys/amd64/linux32/linux32_sysvec.c @@ -33,6 +33,7 @@ #include __FBSDID("$FreeBSD$"); #include "opt_compat.h" +#include "opt_pax.h" #ifndef COMPAT_FREEBSD32 #error "Unable to compile Linux-emulator due to missing COMPAT_FREEBSD32 option!" @@ -51,6 +52,7 @@ #include #include #include +#include #include #include #include @@ -1037,6 +1039,9 @@ .sv_shared_page_base = LINUX32_SHAREDPAGE, .sv_shared_page_len = PAGE_SIZE, .sv_schedtail = linux_schedtail, +#ifdef PAX_ASLR + .sv_pax_aslr_init = _pax_aslr_init32, +#endif }; INIT_SYSENTVEC(elf_sysvec, &elf_linux_sysvec); Index: sys/arm/arm/elf_machdep.c =================================================================== --- sys/arm/arm/elf_machdep.c +++ sys/arm/arm/elf_machdep.c @@ -26,6 +26,8 @@ #include __FBSDID("$FreeBSD$"); +#include "opt_pax.h" + #include #include #include @@ -34,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -81,6 +84,9 @@ .sv_fetch_syscall_args = cpu_fetch_syscall_args, .sv_syscallnames = syscallnames, .sv_schedtail = NULL, +#ifdef PAX_ASLR + .sv_pax_aslr_init = _pax_aslr_init, +#endif }; static Elf32_Brandinfo freebsd_brand_info = { Index: sys/compat/freebsd32/freebsd32_misc.c =================================================================== --- sys/compat/freebsd32/freebsd32_misc.c +++ sys/compat/freebsd32/freebsd32_misc.c @@ -30,6 +30,7 @@ #include "opt_compat.h" #include "opt_inet.h" #include "opt_inet6.h" +#include "opt_pax.h" #define __ELF_WORD_SIZE 32 @@ -55,6 +56,7 @@ #include #include #include +#include #include #include #include @@ -2766,6 +2768,10 @@ szsigcode = 0; destp = (uintptr_t)arginfo; +#ifdef PAX_ASLR + pax_aslr_stack(curthread, &destp); +#endif + /* * install sigcode */ Index: sys/compat/ia32/ia32_sysvec.c =================================================================== --- sys/compat/ia32/ia32_sysvec.c +++ sys/compat/ia32/ia32_sysvec.c @@ -29,6 +29,7 @@ __FBSDID("$FreeBSD$"); #include "opt_compat.h" +#include "opt_pax.h" #define __ELF_WORD_SIZE 32 @@ -43,6 +44,7 @@ #include #include #include +#include #include #include #include @@ -136,6 +138,9 @@ .sv_shared_page_base = FREEBSD32_SHAREDPAGE, .sv_shared_page_len = PAGE_SIZE, .sv_schedtail = NULL, +#ifdef PAX_ASLR + .sv_pax_aslr_init = _pax_aslr_init32, +#endif }; INIT_SYSENTVEC(elf_ia32_sysvec, &ia32_freebsd_sysvec); Index: sys/conf/NOTES =================================================================== --- sys/conf/NOTES +++ sys/conf/NOTES @@ -2989,3 +2989,7 @@ # Module to enable execution of application via emulators like QEMU options IMAGACT_BINMISC + +# Address Space Layout Randomization (ASLR) +options PAX_ASLR +options PAX_SYSCTLS Index: sys/conf/files =================================================================== --- sys/conf/files +++ sys/conf/files @@ -2959,6 +2959,8 @@ kern/kern_mutex.c standard kern/kern_ntptime.c standard kern/kern_osd.c standard +kern/kern_pax.c optional pax_aslr +kern/kern_pax_aslr.c optional pax_aslr kern/kern_physio.c standard kern/kern_pmc.c standard kern/kern_poll.c optional device_polling Index: sys/conf/options =================================================================== --- sys/conf/options +++ sys/conf/options @@ -923,6 +923,11 @@ # Resource Limits RCTL opt_global.h +# PaX - hardening options +PAX_ASLR opt_pax.h +PAX_ASLR_MAX_SEC opt_pax.h +PAX_SYSCTLS opt_pax.h + # Random number generator(s) RANDOM_YARROW opt_random.h RANDOM_FORTUNA opt_random.h Index: sys/i386/i386/elf_machdep.c =================================================================== --- sys/i386/i386/elf_machdep.c +++ sys/i386/i386/elf_machdep.c @@ -26,12 +26,15 @@ #include __FBSDID("$FreeBSD$"); +#include "opt_pax.h" + #include #include #include #include #include #include +#include #include #include #include @@ -81,6 +84,9 @@ .sv_shared_page_base = SHAREDPAGE, .sv_shared_page_len = PAGE_SIZE, .sv_schedtail = NULL, +#ifdef PAX_ASLR + .sv_pax_aslr_init = _pax_aslr_init, +#endif }; INIT_SYSENTVEC(elf32_sysvec, &elf32_freebsd_sysvec); Index: sys/i386/ibcs2/ibcs2_sysvec.c =================================================================== --- sys/i386/ibcs2/ibcs2_sysvec.c +++ sys/i386/ibcs2/ibcs2_sysvec.c @@ -31,6 +31,8 @@ #include __FBSDID("$FreeBSD$"); +#include "opt_pax.h" + #include #include #include @@ -40,6 +42,7 @@ #include #include #include +#include #include #include @@ -89,6 +92,9 @@ .sv_fetch_syscall_args = cpu_fetch_syscall_args, .sv_syscallnames = NULL, .sv_schedtail = NULL, +#ifdef PAX_ASLR + .sv_pax_aslr_init = _pax_aslr_init, +#endif }; static int Index: sys/i386/linux/linux_sysvec.c =================================================================== --- sys/i386/linux/linux_sysvec.c +++ sys/i386/linux/linux_sysvec.c @@ -29,6 +29,8 @@ #include __FBSDID("$FreeBSD$"); +#include "opt_pax.h" + #include #include #include @@ -41,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -974,6 +977,9 @@ .sv_shared_page_base = LINUX_SHAREDPAGE, .sv_shared_page_len = PAGE_SIZE, .sv_schedtail = linux_schedtail, +#ifdef PAX_ASLR + .sv_pax_aslr_init = _pax_aslr_init, +#endif }; INIT_SYSENTVEC(aout_sysvec, &linux_sysvec); @@ -1012,6 +1018,9 @@ .sv_shared_page_base = LINUX_SHAREDPAGE, .sv_shared_page_len = PAGE_SIZE, .sv_schedtail = linux_schedtail, +#ifdef PAX_ASLR + .sv_pax_aslr_init = _pax_aslr_init, +#endif }; INIT_SYSENTVEC(elf_sysvec, &elf_linux_sysvec); Index: sys/kern/imgact_aout.c =================================================================== --- sys/kern/imgact_aout.c +++ sys/kern/imgact_aout.c @@ -27,6 +27,8 @@ #include __FBSDID("$FreeBSD$"); +#include "opt_pax.h" + #include #include #include @@ -36,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -99,6 +102,9 @@ .sv_fetch_syscall_args = cpu_fetch_syscall_args, .sv_syscallnames = syscallnames, .sv_schedtail = NULL, +#ifdef PAX_ASLR + .sv_pax_aslr_init = _pax_aslr_init, +#endif }; #elif defined(__amd64__) @@ -143,6 +149,9 @@ .sv_set_syscall_retval = ia32_set_syscall_retval, .sv_fetch_syscall_args = ia32_fetch_syscall_args, .sv_syscallnames = freebsd32_syscallnames, +#ifdef PAX_ASLR + .sv_pax_aslr_init = _pax_aslr_init32, +#endif }; #else #error "Port me" Index: sys/kern/imgact_elf.c =================================================================== --- sys/kern/imgact_elf.c +++ sys/kern/imgact_elf.c @@ -34,6 +34,7 @@ #include "opt_capsicum.h" #include "opt_compat.h" #include "opt_core.h" +#include "opt_pax.h" #include #include @@ -48,6 +49,8 @@ #include #include #include +#include +#include #include #include #include @@ -800,16 +803,7 @@ if (hdr->e_type == ET_DYN) { if ((brand_info->flags & BI_CAN_EXEC_DYN) == 0) return (ENOEXEC); - /* - * 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 (interp != NULL && brand_info->interp_newpath != NULL) newinterp = brand_info->interp_newpath; @@ -830,6 +824,21 @@ error = exec_new_vmspace(imgp, sv); imgp->proc->p_sysent = sv; + et_dyn_addr = 0; + if (hdr->e_type == ET_DYN) { + /* + * 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; +#ifdef PAX_ASLR + if (pax_aslr_active(imgp->proc)) + et_dyn_addr += imgp->proc->p_vmspace->vm_aslr_delta_exec; +#endif + } + } + vn_lock(imgp->vp, LK_EXCLUSIVE | LK_RETRY); if (error) return (error); Index: sys/kern/init_main.c =================================================================== --- sys/kern/init_main.c +++ sys/kern/init_main.c @@ -410,6 +410,7 @@ .sv_fetch_syscall_args = null_fetch_syscall_args, .sv_syscallnames = NULL, .sv_schedtail = NULL, + .sv_pax_aslr_init = NULL, }; /* Index: sys/kern/kern_exec.c =================================================================== --- sys/kern/kern_exec.c +++ sys/kern/kern_exec.c @@ -30,6 +30,7 @@ #include "opt_capsicum.h" #include "opt_hwpmc_hooks.h" #include "opt_ktrace.h" +#include "opt_pax.h" #include "opt_vm.h" #include @@ -50,6 +51,7 @@ #include #include #include +#include #include #include #include @@ -402,6 +404,13 @@ imgp->pagesizes = 0; imgp->pagesizeslen = 0; imgp->stack_prot = 0; + imgp->pax_flags = 0; + +#if defined(PAX_ASLR) + error = pax_elf(imgp, 0); + if (error) + goto exec_fail; +#endif #ifdef MAC error = mac_execve_enter(imgp, mac_p); @@ -1066,6 +1075,10 @@ map = &vmspace->vm_map; } +#ifdef PAX_ASLR + pax_aslr_init(imgp); +#endif + /* Map a shared page */ obj = sv->sv_shared_page_obj; if (obj != NULL) { @@ -1100,6 +1113,9 @@ */ vmspace->vm_ssize = sgrowsiz >> PAGE_SHIFT; vmspace->vm_maxsaddr = (char *)sv->sv_usrstack - ssiz; +#ifdef PAX_ASLR + vmspace->vm_maxsaddr -= vmspace->vm_aslr_delta_stack; +#endif return (0); } @@ -1259,6 +1275,9 @@ szsigcode = *(p->p_sysent->sv_szsigcode); } destp = (uintptr_t)arginfo; +#ifdef PAX_ASLR + pax_aslr_stack(curthread, &destp); +#endif /* * install sigcode Index: sys/kern/kern_fork.c =================================================================== --- sys/kern/kern_fork.c +++ sys/kern/kern_fork.c @@ -513,6 +513,11 @@ } /* + * Per-process PaX flags. + */ + p2->p_pax = p1->p_pax; + + /* * p_limit is copy-on-write. Bump its refcount. */ lim_fork(p1, p2); Index: sys/kern/kern_jail.c =================================================================== --- sys/kern/kern_jail.c +++ sys/kern/kern_jail.c @@ -33,6 +33,7 @@ #include "opt_ddb.h" #include "opt_inet.h" #include "opt_inet6.h" +#include "opt_pax.h" #include #include @@ -42,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -117,6 +119,10 @@ }; MTX_SYSINIT(prison0, &prison0.pr_mtx, "jail mutex", MTX_DEF); +#if defined(PAX_ASLR) +SYSINIT(pax, SI_SUB_PAX, SI_ORDER_MIDDLE, pax_init_prison, (void *) &prison0); +#endif + /* allprison, allprison_racct and lastprid are protected by allprison_lock. */ struct sx allprison_lock; SX_SYSINIT(allprison_lock, &allprison_lock, "allprison"); @@ -1307,6 +1313,10 @@ goto done_releroot; } +#if defined(PAX_ASLR) + pax_init_prison(pr); +#endif + mtx_lock(&pr->pr_mtx); /* * New prisons do not yet have a reference, because we do not Index: sys/kern/kern_pax.c =================================================================== --- /dev/null +++ sys/kern/kern_pax.c @@ -0,0 +1,209 @@ +/*- + * Copyright (c) 2006 Elad Efrat + * Copyright (c) 2013-2014, by Oliver Pinter + * Copyright (c) 2014, by Shawn Webb + * All rights reserved. + * + * 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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$ + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_compat.h" +#include "opt_pax.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include + +#include + +#include + +SYSCTL_NODE(_security, OID_AUTO, pax, CTLFLAG_RD, 0, + "PaX (exploit mitigation) features."); + +const char *pax_status_str[] = { + [PAX_FEATURE_DISABLED] = "disabled", + [PAX_FEATURE_OPTIN] = "opt-in", + [PAX_FEATURE_OPTOUT] = "opt-out", + [PAX_FEATURE_FORCE_ENABLED] = "force enabled", + [PAX_FEATURE_UNKNOWN_STATUS] = "UNKNOWN -> changed to \"force enabled\"" +}; + +const char *pax_status_simple_str[] = { + [PAX_FEATURE_SIMPLE_DISABLED] = "disabled", + [PAX_FEATURE_SIMPLE_ENABLED] = "enabled" +}; + +struct prison * +pax_get_prison(struct proc *proc) +{ + if ((proc == NULL) || (proc->p_ucred == NULL)) + return (NULL); + + return (proc->p_ucred->cr_prison); +} + +int +pax_get_flags(struct proc *proc, uint32_t *flags) +{ + *flags = 0; + + if (proc != NULL) + *flags = proc->p_pax; + else + return (1); + + return (0); +} + +int +pax_elf(struct image_params *imgp, uint32_t mode) +{ + u_int flags, flags_aslr; + + flags = 0; + flags_aslr = 0; + + if ((mode & MBI_ALLPAX) != MBI_ALLPAX) { + if (mode & MBI_ASLR_ENABLED) + flags |= PAX_NOTE_ASLR; + if (mode & MBI_ASLR_DISABLED) + flags |= PAX_NOTE_NOASLR; + } + + if ((flags & ~PAX_NOTE_ALL) != 0) { + printf("%s: unknown paxflags: %x\n", __func__, flags); + + return (1); + } + + if (((flags & PAX_NOTE_ALL_ENABLED) & ((flags & PAX_NOTE_ALL_DISABLED) >> 1)) != 0) { + /* + * indicate flags inconsistencies in dmesg and in user terminal + */ + printf("%s: inconsistent paxflags: %x\n", __func__, flags); + + return (1); + } + +#ifdef PAX_ASLR + flags_aslr = pax_aslr_setup_flags(imgp, mode); +#endif + + flags = flags_aslr; + + + CTR3(KTR_PAX, "%s : flags = %x mode = %x", + __func__, flags, mode); + + if (imgp != NULL) { + imgp->pax_flags = flags; + if (imgp->proc != NULL) { + PROC_LOCK(imgp->proc); + imgp->proc->p_pax = flags; + PROC_UNLOCK(imgp->proc); + } + } + + return (0); +} + + +/* + * print out PaX settings on boot time, and validate some of them + */ +static void +pax_sysinit(void) +{ + + printf("PAX: initialize and check PaX and HardeneBSD features.\n"); +} +SYSINIT(pax, SI_SUB_PAX, SI_ORDER_FIRST, pax_sysinit, NULL); + +void +pax_init_prison(struct prison *pr) +{ + + if (pr == NULL) + return; + + if (pr->pr_pax_set) + return; + + prison_lock(pr); + + CTR2(KTR_PAX, "%s: Setting prison %s PaX variables", + __func__, pr->pr_name); + +#ifdef PAX_ASLR + pr->pr_pax_aslr_status = pax_aslr_status; + pr->pr_pax_aslr_debug = pax_aslr_debug; + pr->pr_pax_aslr_mmap_len = pax_aslr_mmap_len; + pr->pr_pax_aslr_stack_len = pax_aslr_stack_len; + pr->pr_pax_aslr_exec_len = pax_aslr_exec_len; + +#ifdef COMPAT_FREEBSD32 + pr->pr_pax_aslr_compat_status = pax_aslr_compat_status; + pr->pr_pax_aslr_compat_mmap_len = pax_aslr_compat_mmap_len; + pr->pr_pax_aslr_compat_stack_len = pax_aslr_compat_stack_len; + pr->pr_pax_aslr_compat_exec_len = pax_aslr_compat_exec_len; +#endif /* COMPAT_FREEBSD32 */ +#endif /* PAX_ASLR */ + + pr->pr_pax_set = 1; + + prison_unlock(pr); +} Index: sys/kern/kern_pax_aslr.c =================================================================== --- /dev/null +++ sys/kern/kern_pax_aslr.c @@ -0,0 +1,768 @@ +/*- + * Copyright (c) 2006 Elad Efrat + * Copyright (c) 2013-2014, by Oliver Pinter + * Copyright (c) 2014, by Shawn Webb + * All rights reserved. + * + * 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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$ + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_compat.h" +#include "opt_pax.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include + +FEATURE(aslr, "Address Space Layout Randomization."); + +int pax_aslr_status = PAX_FEATURE_OPTOUT; +int pax_aslr_debug = PAX_FEATURE_SIMPLE_DISABLED; + +#ifdef PAX_ASLR_MAX_SEC +int pax_aslr_mmap_len = PAX_ASLR_DELTA_MMAP_MAX_LEN; +int pax_aslr_stack_len = PAX_ASLR_DELTA_STACK_MAX_LEN; +int pax_aslr_exec_len = PAX_ASLR_DELTA_EXEC_MAX_LEN; +#else +int pax_aslr_mmap_len = PAX_ASLR_DELTA_MMAP_DEF_LEN; +int pax_aslr_stack_len = PAX_ASLR_DELTA_STACK_DEF_LEN; +int pax_aslr_exec_len = PAX_ASLR_DELTA_EXEC_DEF_LEN; +#endif /* PAX_ASLR_MAX_SEC */ + +#ifdef COMPAT_FREEBSD32 +int pax_aslr_compat_status = PAX_FEATURE_OPTOUT; +#ifdef PAX_ASLR_MAX_SEC +int pax_aslr_compat_mmap_len = PAX_ASLR_COMPAT_DELTA_MMAP_MAX_LEN; +int pax_aslr_compat_stack_len = PAX_ASLR_COMPAT_DELTA_STACK_MAX_LEN; +int pax_aslr_compat_exec_len = PAX_ASLR_COMPAT_DELTA_EXEC_MAX_LEN; +#else +int pax_aslr_compat_mmap_len = PAX_ASLR_COMPAT_DELTA_MMAP_MIN_LEN; +int pax_aslr_compat_stack_len = PAX_ASLR_COMPAT_DELTA_STACK_MIN_LEN; +int pax_aslr_compat_exec_len = PAX_ASLR_COMPAT_DELTA_EXEC_MIN_LEN; +#endif /* PAX_ASLR_MAX_SEC */ +#endif /* COMPAT_FREEBSD32 */ + +TUNABLE_INT("security.pax.aslr.status", &pax_aslr_status); +TUNABLE_INT("security.pax.aslr.mmap_len", &pax_aslr_mmap_len); +TUNABLE_INT("security.pax.aslr.debug", &pax_aslr_debug); +TUNABLE_INT("security.pax.aslr.stack_len", &pax_aslr_stack_len); +TUNABLE_INT("security.pax.aslr.exec_len", &pax_aslr_exec_len); +#ifdef COMPAT_FREEBSD32 +TUNABLE_INT("security.pax.aslr.compat.status", &pax_aslr_compat_status); +TUNABLE_INT("security.pax.aslr.compat.mmap", &pax_aslr_compat_mmap_len); +TUNABLE_INT("security.pax.aslr.compat.stack", &pax_aslr_compat_stack_len); +TUNABLE_INT("security.pax.aslr.compat.stack", &pax_aslr_compat_exec_len); +#endif + +#ifdef PAX_SYSCTLS + +SYSCTL_DECL(_security_pax); + +/* + * sysctls and tunables + */ +static int sysctl_pax_aslr_debug(SYSCTL_HANDLER_ARGS); +static int sysctl_pax_aslr_status(SYSCTL_HANDLER_ARGS); +static int sysctl_pax_aslr_mmap(SYSCTL_HANDLER_ARGS); +static int sysctl_pax_aslr_stack(SYSCTL_HANDLER_ARGS); +static int sysctl_pax_aslr_exec(SYSCTL_HANDLER_ARGS); + + +SYSCTL_NODE(_security_pax, OID_AUTO, aslr, CTLFLAG_RD, 0, + "Address Space Layout Randomization."); + +SYSCTL_PROC(_security_pax_aslr, OID_AUTO, status, + CTLTYPE_INT|CTLFLAG_RWTUN|CTLFLAG_PRISON|CTLFLAG_SECURE, + NULL, 0, sysctl_pax_aslr_status, "I", + "Restrictions status. " + "0 - disabled, " + "1 - opt-in, " + "2 - opt-out, " + "3 - force enabled"); + +SYSCTL_PROC(_security_pax_aslr, OID_AUTO, debug, + CTLTYPE_INT|CTLFLAG_RWTUN|CTLFLAG_PRISON|CTLFLAG_SECURE, + NULL, 0, sysctl_pax_aslr_debug, "I", + "ASLR debug mode"); + +SYSCTL_PROC(_security_pax_aslr, OID_AUTO, mmap_len, + CTLTYPE_INT|CTLFLAG_RWTUN|CTLFLAG_PRISON|CTLFLAG_SECURE, + NULL, 0, sysctl_pax_aslr_mmap, "I", + "Number of bits randomized for mmap(2) calls. " + "32 bit: [8,16] 64 bit: [16,32]"); + +SYSCTL_PROC(_security_pax_aslr, OID_AUTO, stack_len, + CTLTYPE_INT|CTLFLAG_RWTUN|CTLFLAG_PRISON|CTLFLAG_SECURE, + NULL, 0, sysctl_pax_aslr_stack, "I", + "Number of bits randomized for the stack. " + "32 bit: [6,12] 64 bit: [12,21]"); + +SYSCTL_PROC(_security_pax_aslr, OID_AUTO, exec_len, + CTLTYPE_INT|CTLFLAG_RWTUN|CTLFLAG_PRISON|CTLFLAG_SECURE, + NULL, 0, sysctl_pax_aslr_exec, "I", + "Number of bits randomized for the PIE exec base. " + "32 bit: [6,12] 64 bit: [12,21]"); + +static int +sysctl_pax_aslr_status(SYSCTL_HANDLER_ARGS) +{ + struct prison *pr; + int err, val; + + pr = pax_get_prison(req->td->td_proc); + + val = (pr != NULL) ? pr->pr_pax_aslr_status : pax_aslr_status; + err = sysctl_handle_int(oidp, &val, sizeof(int), req); + if (err || (req->newptr == NULL)) + return (err); + + switch (val) { + case PAX_FEATURE_DISABLED: + case PAX_FEATURE_OPTIN: + case PAX_FEATURE_OPTOUT: + case PAX_FEATURE_FORCE_ENABLED: + if ((pr == NULL) || (pr == &prison0)) + pax_aslr_status = val; + + if (pr != NULL) { + prison_lock(pr); + pr->pr_pax_aslr_status = val; + prison_unlock(pr); + } + break; + default: + return (EINVAL); + } + + return (0); +} + +static int +sysctl_pax_aslr_debug(SYSCTL_HANDLER_ARGS) +{ + struct prison *pr=NULL; + int err, val; + + pr = pax_get_prison(req->td->td_proc); + + val = (pr != NULL) ? pr->pr_pax_aslr_debug : pax_aslr_debug; + err = sysctl_handle_int(oidp, &val, sizeof(int), req); + if (err || !req->newptr) + return (err); + + switch (val) { + case 0: + case 1: + break; + default: + return (EINVAL); + + } + + if ((pr == NULL) || (pr == &prison0)) + pax_aslr_debug = val; + + if (pr != NULL) { + prison_lock(pr); + pr->pr_pax_aslr_debug = val; + prison_unlock(pr); + } + + return (0); +} + +static int +sysctl_pax_aslr_mmap(SYSCTL_HANDLER_ARGS) +{ + struct prison *pr=NULL; + int err, val; + + pr = pax_get_prison(req->td->td_proc); + + val = (pr != NULL) ? pr->pr_pax_aslr_mmap_len : pax_aslr_mmap_len; + err = sysctl_handle_int(oidp, &val, sizeof(int), req); + if (err || !req->newptr) + return (err); + + if (val < PAX_ASLR_DELTA_MMAP_MIN_LEN || + val > PAX_ASLR_DELTA_MMAP_MAX_LEN) + return (EINVAL); + + if ((pr == NULL) || (pr == &prison0)) + pax_aslr_mmap_len = val; + + if (pr != NULL) { + prison_lock(pr); + pr->pr_pax_aslr_mmap_len = val; + prison_unlock(pr); + } + + return (0); +} + +static int +sysctl_pax_aslr_stack(SYSCTL_HANDLER_ARGS) +{ + struct prison *pr=NULL; + int err, val; + + pr = pax_get_prison(req->td->td_proc); + + val = (pr != NULL) ? pr->pr_pax_aslr_stack_len : pax_aslr_stack_len; + err = sysctl_handle_int(oidp, &val, sizeof(int), req); + if (err || !req->newptr) + return (err); + + if (val < PAX_ASLR_DELTA_STACK_MIN_LEN || + val > PAX_ASLR_DELTA_STACK_MAX_LEN) + return (EINVAL); + + if ((pr == NULL) || (pr == &prison0)) + pax_aslr_stack_len = val; + + if (pr != NULL) { + prison_lock(pr); + pr->pr_pax_aslr_stack_len = val; + prison_unlock(pr); + } + + return (0); +} + +static int +sysctl_pax_aslr_exec(SYSCTL_HANDLER_ARGS) +{ + struct prison *pr=NULL; + int err, val; + + pr = pax_get_prison(req->td->td_proc); + + val = (pr != NULL) ? pr->pr_pax_aslr_exec_len : pax_aslr_exec_len; + err = sysctl_handle_int(oidp, &val, sizeof(int), req); + if (err || (req->newptr == NULL)) + return (err); + + if (val < PAX_ASLR_DELTA_EXEC_MIN_LEN || + val > PAX_ASLR_DELTA_EXEC_MAX_LEN) + return (EINVAL); + + if ((pr == NULL) || (pr == &prison0)) + pax_aslr_exec_len = val; + + if (pr != NULL) { + prison_lock(pr); + pr->pr_pax_aslr_exec_len = val; + prison_unlock(pr); + } + + return (0); +} + +/* + * COMPAT_FREEBSD32 and linuxulator.. + */ +#ifdef COMPAT_FREEBSD32 +static int sysctl_pax_aslr_compat_status(SYSCTL_HANDLER_ARGS); +static int sysctl_pax_aslr_compat_mmap(SYSCTL_HANDLER_ARGS); +static int sysctl_pax_aslr_compat_stack(SYSCTL_HANDLER_ARGS); +static int sysctl_pax_aslr_compat_exec(SYSCTL_HANDLER_ARGS); + +SYSCTL_NODE(_security_pax_aslr, OID_AUTO, compat, CTLFLAG_RD, 0, + "Setting for COMPAT_FREEBSD32 and linuxulator."); + +SYSCTL_PROC(_security_pax_aslr_compat, OID_AUTO, status, + CTLTYPE_INT|CTLFLAG_RWTUN|CTLFLAG_PRISON, + NULL, 0, sysctl_pax_aslr_compat_status, "I", + "Restrictions status. " + "0 - disabled, " + "1 - enabled, " + "2 - global enabled, " + "3 - force global enabled"); + +SYSCTL_PROC(_security_pax_aslr_compat, OID_AUTO, mmap_len, + CTLTYPE_INT|CTLFLAG_RWTUN|CTLFLAG_PRISON, + NULL, 0, sysctl_pax_aslr_compat_mmap, "I", + "Number of bits randomized for mmap(2) calls. " + "32 bit: [8,16]"); + +SYSCTL_PROC(_security_pax_aslr_compat, OID_AUTO, stack_len, + CTLTYPE_INT|CTLFLAG_RWTUN|CTLFLAG_PRISON, + NULL, 0, sysctl_pax_aslr_compat_stack, "I", + "Number of bits randomized for the stack. " + "32 bit: [6,12]"); + +SYSCTL_PROC(_security_pax_aslr_compat, OID_AUTO, exec_len, + CTLTYPE_INT|CTLFLAG_RWTUN|CTLFLAG_PRISON, + NULL, 0, sysctl_pax_aslr_compat_exec, "I", + "Number of bits randomized for the PIE exec base. " + "32 bit: [6,12]"); + +static int +sysctl_pax_aslr_compat_status(SYSCTL_HANDLER_ARGS) +{ + struct prison *pr; + int err, val; + + pr = pax_get_prison(req->td->td_proc); + + val = (pr != NULL) ?pr->pr_pax_aslr_compat_status : pax_aslr_compat_status; + err = sysctl_handle_int(oidp, &val, sizeof(int), req); + if (err || (req->newptr == NULL)) + return (err); + + switch (val) { + case PAX_FEATURE_DISABLED: + case PAX_FEATURE_OPTIN: + case PAX_FEATURE_OPTOUT: + case PAX_FEATURE_FORCE_ENABLED: + if ((pr == NULL) || (pr == &prison0)) + pax_aslr_compat_status = val; + + if (pr != NULL) { + prison_lock(pr); + pr->pr_pax_aslr_compat_status = val; + prison_unlock(pr); + } + break; + default: + return (EINVAL); + } + + return (0); +} + +static int +sysctl_pax_aslr_compat_mmap(SYSCTL_HANDLER_ARGS) +{ + struct prison *pr; + int err, val; + + pr = pax_get_prison(req->td->td_proc); + + val = (pr != NULL) ? pr->pr_pax_aslr_compat_mmap_len : pax_aslr_compat_mmap_len; + err = sysctl_handle_int(oidp, &val, sizeof(int), req); + if (err || !req->newptr) + return (err); + + if (val < PAX_ASLR_COMPAT_DELTA_MMAP_MIN_LEN || + val > PAX_ASLR_COMPAT_DELTA_MMAP_MAX_LEN) + return (EINVAL); + + if ((pr == NULL) || (pr == &prison0)) + pax_aslr_compat_mmap_len = val; + + if (pr != NULL) { + prison_lock(pr); + pr->pr_pax_aslr_compat_mmap_len = val; + prison_unlock(pr); + } + + return (0); +} + +static int +sysctl_pax_aslr_compat_stack(SYSCTL_HANDLER_ARGS) +{ + struct prison *pr; + int err, val; + + pr = pax_get_prison(req->td->td_proc); + + val = (pr != NULL) ? pr->pr_pax_aslr_compat_stack_len : pax_aslr_compat_stack_len; + err = sysctl_handle_int(oidp, &val, sizeof(int), req); + if (err || !req->newptr) + return (err); + + if (val < PAX_ASLR_COMPAT_DELTA_STACK_MIN_LEN || + val > PAX_ASLR_COMPAT_DELTA_STACK_MAX_LEN) + return (EINVAL); + + if ((pr == NULL) || (pr == &prison0)) + pax_aslr_compat_stack_len = val; + + if (pr != NULL) { + prison_lock(pr); + pr->pr_pax_aslr_compat_stack_len = val; + prison_unlock(pr); + } + + return (0); +} + +static int +sysctl_pax_aslr_compat_exec(SYSCTL_HANDLER_ARGS) +{ + struct prison *pr; + int err, val; + + pr = pax_get_prison(req->td->td_proc); + + if (pr != NULL) + val = pr->pr_pax_aslr_compat_exec_len; + else + val = pax_aslr_compat_exec_len; + + err = sysctl_handle_int(oidp, &val, sizeof(int), req); + if (err || !req->newptr) + return (err); + + if (val < PAX_ASLR_COMPAT_DELTA_EXEC_MIN_LEN || + val > PAX_ASLR_COMPAT_DELTA_EXEC_MAX_LEN) + return (EINVAL); + + if ((pr == NULL) || (pr == &prison0)) + pax_aslr_compat_exec_len = val; + + if (pr != NULL) { + prison_lock(pr); + pr->pr_pax_aslr_compat_exec_len = val; + prison_unlock(pr); + } + + return (0); +} + +#endif /* COMPAT_FREEBSD32 */ +#endif /* PAX_SYSCTLS */ + + +/* + * ASLR functions + */ + +static void +pax_aslr_sysinit(void) +{ + switch (pax_aslr_status) { + case PAX_FEATURE_DISABLED: + case PAX_FEATURE_OPTIN: + case PAX_FEATURE_OPTOUT: + case PAX_FEATURE_FORCE_ENABLED: + break; + default: + printf("[PAX ASLR] WARNING, invalid PAX settings in loader.conf!" + " (pax_aslr_status = %d)\n", pax_aslr_status); + pax_aslr_status = PAX_FEATURE_FORCE_ENABLED; + break; + } + printf("[PAX ASLR] status: %s\n", pax_status_str[pax_aslr_status]); + printf("[PAX ASLR] mmap: %d bit\n", pax_aslr_mmap_len); + printf("[PAX ASLR] exec base: %d bit\n", pax_aslr_exec_len); + printf("[PAX ASLR] stack: %d bit\n", pax_aslr_stack_len); +} +SYSINIT(pax_aslr, SI_SUB_PAX, SI_ORDER_SECOND, pax_aslr_sysinit, NULL); + +bool +pax_aslr_active(struct proc *proc) +{ + u_int flags; + bool ret; + + ret = pax_get_flags(proc, &flags); + if (ret != 0) + /* + * invalid flags, we should force ASLR + */ + return (true); + + CTR3(KTR_PAX, "%s: pid = %d p_pax = %x", + __func__, proc->p_pid, flags); + + if ((flags & PAX_NOTE_ASLR) == PAX_NOTE_ASLR) + return (true); + + if ((flags & PAX_NOTE_NOASLR) == PAX_NOTE_NOASLR) + return (false); + + return (true); +} + +void +_pax_aslr_init(struct vmspace *vm, struct proc *p) +{ + struct prison *pr; + + KASSERT(vm != NULL, ("%s: vm is null", __func__)); + + pr = pax_get_prison(p); + if (pr != NULL) { + vm->vm_aslr_delta_mmap = PAX_ASLR_DELTA(arc4random(), + PAX_ASLR_DELTA_MMAP_LSB, + pr->pr_pax_aslr_mmap_len); + + vm->vm_aslr_delta_stack = PAX_ASLR_DELTA(arc4random(), + PAX_ASLR_DELTA_STACK_LSB, + pr->pr_pax_aslr_stack_len); + vm->vm_aslr_delta_stack = ALIGN(vm->vm_aslr_delta_stack); + + vm->vm_aslr_delta_exec = PAX_ASLR_DELTA(arc4random(), + PAX_ASLR_DELTA_EXEC_LSB, + pr->pr_pax_aslr_exec_len); + } else { + vm->vm_aslr_delta_mmap = PAX_ASLR_DELTA(arc4random(), + PAX_ASLR_DELTA_MMAP_LSB, + pax_aslr_mmap_len); + + vm->vm_aslr_delta_stack = PAX_ASLR_DELTA(arc4random(), + PAX_ASLR_DELTA_STACK_LSB, + pax_aslr_stack_len); + vm->vm_aslr_delta_stack = ALIGN(vm->vm_aslr_delta_stack); + + vm->vm_aslr_delta_exec = PAX_ASLR_DELTA(arc4random(), + PAX_ASLR_DELTA_EXEC_LSB, + pax_aslr_exec_len); + } + + CTR2(KTR_PAX, "%s: vm_aslr_delta_mmap=%p\n", + __func__, (void *)vm->vm_aslr_delta_mmap); + CTR2(KTR_PAX, "%s: vm_aslr_delta_stack=%p\n", + __func__, (void *)vm->vm_aslr_delta_stack); + CTR2(KTR_PAX, "%s: vm_aslr_delta_exec=%p\n", + __func__, (void *)vm->vm_aslr_delta_exec); +} + +#ifdef COMPAT_FREEBSD32 +static void +pax_compat_aslr_sysinit(void) +{ + switch (pax_aslr_compat_status) { + case PAX_FEATURE_DISABLED: + case PAX_FEATURE_OPTIN: + case PAX_FEATURE_OPTOUT: + case PAX_FEATURE_FORCE_ENABLED: + break; + default: + printf("[PAX ASLR (compat)] WARNING, invalid PAX settings in loader.conf! " + "(pax_aslr_compat_status = %d)\n", pax_aslr_compat_status); + pax_aslr_compat_status = PAX_FEATURE_FORCE_ENABLED; + break; + } + printf("[PAX ASLR (compat)] status: %s\n", pax_status_str[pax_aslr_compat_status]); + printf("[PAX ASLR (compat)] mmap: %d bit\n", pax_aslr_compat_mmap_len); + printf("[PAX ASLR (compat)] exec base: %d bit\n", pax_aslr_compat_exec_len); + printf("[PAX ASLR (compat)] stack: %d bit\n", pax_aslr_compat_stack_len); +} +SYSINIT(pax_compat_aslr, SI_SUB_PAX, SI_ORDER_SECOND, pax_compat_aslr_sysinit, NULL); + +void +_pax_aslr_init32(struct vmspace *vm, struct proc *p) +{ + struct prison *pr; + + KASSERT(vm != NULL, ("%s: vm is null", __func__)); + + pr = pax_get_prison(p); + if (pr != NULL) { + vm->vm_aslr_delta_mmap = PAX_ASLR_DELTA(arc4random(), + PAX_ASLR_COMPAT_DELTA_MMAP_LSB, + pr->pr_pax_aslr_compat_mmap_len); + + vm->vm_aslr_delta_stack = PAX_ASLR_DELTA(arc4random(), + PAX_ASLR_COMPAT_DELTA_STACK_LSB, + pr->pr_pax_aslr_compat_stack_len); + vm->vm_aslr_delta_stack = ALIGN(vm->vm_aslr_delta_stack); + + vm->vm_aslr_delta_exec = PAX_ASLR_DELTA(arc4random(), + PAX_ASLR_COMPAT_DELTA_EXEC_LSB, + pr->pr_pax_aslr_compat_exec_len); + } else { + vm->vm_aslr_delta_mmap = PAX_ASLR_DELTA(arc4random(), + PAX_ASLR_COMPAT_DELTA_MMAP_LSB, + pax_aslr_compat_mmap_len); + + vm->vm_aslr_delta_stack = PAX_ASLR_DELTA(arc4random(), + PAX_ASLR_COMPAT_DELTA_STACK_LSB, + pax_aslr_compat_stack_len); + vm->vm_aslr_delta_stack = ALIGN(vm->vm_aslr_delta_stack); + + vm->vm_aslr_delta_exec = PAX_ASLR_DELTA(arc4random(), + PAX_ASLR_COMPAT_DELTA_EXEC_LSB, + pax_aslr_compat_exec_len); + } + + CTR2(KTR_PAX, "%s: vm_aslr_delta_mmap=%p\n", + __func__, (void *)vm->vm_aslr_delta_mmap); + CTR2(KTR_PAX, "%s: vm_aslr_delta_stack=%p\n", + __func__, (void *)vm->vm_aslr_delta_stack); + CTR2(KTR_PAX, "%s: vm_aslr_delta_exec=%p\n", + __func__, (void *)vm->vm_aslr_delta_exec); +} +#endif + +void +pax_aslr_init(struct image_params *imgp) +{ + struct vmspace *vm; + struct proc *p; + + KASSERT(imgp != NULL, ("%s: imgp is null", __func__)); + p = imgp->proc; + + if (!pax_aslr_active(p)) + return; + + vm = p->p_vmspace; + + if (imgp->sysent->sv_pax_aslr_init != NULL) + imgp->sysent->sv_pax_aslr_init(vm, p); +} + +void +pax_aslr_mmap(struct proc *p, vm_offset_t *addr, vm_offset_t orig_addr, int flags) +{ + int len_32bit; + + if (!pax_aslr_active(p)) + return; + +#ifdef COMPAT_FREEBSD32 + len_32bit = pax_aslr_compat_mmap_len; +#else + len_32bit = PAX_ASLR_COMPAT_DELTA_MMAP_MIN_LEN; +#endif + + if (!(flags & MAP_FIXED) && ((orig_addr == 0) || !(flags & MAP_ANON))) { + CTR4(KTR_PAX, "%s: applying to %p orig_addr=%p flags=%x\n", + __func__, (void *)*addr, (void *)orig_addr, flags); + +#ifdef MAP_32BIT + if (flags & MAP_32BIT) + *addr += PAX_ASLR_DELTA(arc4random(), + PAX_ASLR_COMPAT_DELTA_MMAP_LSB, + len_32bit); + else +#endif /* MAP_32BIT */ + *addr += p->p_vmspace->vm_aslr_delta_mmap; + CTR2(KTR_PAX, "%s: result %p\n", __func__, (void *)*addr); + } else + CTR4(KTR_PAX, "%s: not applying to %p orig_addr=%p flags=%x\n", + __func__, (void *)*addr, (void *)orig_addr, flags); +} + +void +pax_aslr_stack(struct thread *td, uintptr_t *addr) +{ + uintptr_t orig_addr; + + if (!pax_aslr_active(td->td_proc)) + return; + + orig_addr = *addr; + *addr -= td->td_proc->p_vmspace->vm_aslr_delta_stack; + CTR3(KTR_PAX, "%s: orig_addr=%p, new_addr=%p\n", + __func__, (void *)orig_addr, (void *)*addr); +} + +u_int +pax_aslr_setup_flags(struct image_params *imgp, u_int mode) +{ + struct prison *pr; + u_int flags, status; + + flags = 0; + status = 0; + + pr = pax_get_prison(imgp->proc); + if (pr != NULL) + status = pr->pr_pax_aslr_status; + else + status = pax_aslr_status; + + if (status == PAX_FEATURE_DISABLED) { + flags &= ~PAX_NOTE_ASLR; + flags |= PAX_NOTE_NOASLR; + + return (flags); + } + + if (status == PAX_FEATURE_FORCE_ENABLED) { + flags |= PAX_NOTE_ASLR; + flags &= ~PAX_NOTE_NOASLR; + + return (flags); + } + + if (status == PAX_FEATURE_OPTIN) { + if (mode & MBI_ASLR_ENABLED) { + flags |= PAX_NOTE_ASLR; + flags &= ~PAX_NOTE_NOASLR; + } else { + flags &= ~PAX_NOTE_ASLR; + flags |= PAX_NOTE_NOASLR; + } + + return (flags); + } + + if (status == PAX_FEATURE_OPTOUT) { + if (mode & MBI_ASLR_DISABLED) { + flags &= ~PAX_NOTE_ASLR; + flags |= PAX_NOTE_NOASLR; + } else { + flags |= PAX_NOTE_ASLR; + flags &= ~PAX_NOTE_NOASLR; + } + + return (flags); + } + + /* + * unknown status, force ASLR + */ + flags |= PAX_NOTE_ASLR; + flags &= ~PAX_NOTE_NOASLR; + + return (flags); +} Index: sys/mips/mips/elf_machdep.c =================================================================== --- sys/mips/mips/elf_machdep.c +++ sys/mips/mips/elf_machdep.c @@ -28,6 +28,8 @@ #include __FBSDID("$FreeBSD$"); +#include "opt_pax.h" + #include #include #include @@ -36,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -83,6 +86,9 @@ .sv_fetch_syscall_args = cpu_fetch_syscall_args, .sv_syscallnames = syscallnames, .sv_schedtail = NULL, +#ifdef PAX_ASLR + .sv_pax_aslr_init = _pax_aslr_init, +#endif }; static Elf64_Brandinfo freebsd_brand_info = { @@ -139,6 +145,9 @@ .sv_fetch_syscall_args = cpu_fetch_syscall_args, .sv_syscallnames = syscallnames, .sv_schedtail = NULL, +#ifdef PAX_ASLR + .sv_pax_aslr_init = _pax_aslr_init32, +#endif }; static Elf32_Brandinfo freebsd_brand_info = { Index: sys/mips/mips/freebsd32_machdep.c =================================================================== --- sys/mips/mips/freebsd32_machdep.c +++ sys/mips/mips/freebsd32_machdep.c @@ -31,6 +31,7 @@ */ #include "opt_compat.h" +#include "opt_pax.h" #define __ELF_WORD_SIZE 32 @@ -45,6 +46,7 @@ #include #include #include +#include #include #include #include @@ -106,6 +108,9 @@ .sv_fetch_syscall_args = cpu_fetch_syscall_args, .sv_syscallnames = freebsd32_syscallnames, .sv_schedtail = NULL, +#ifdef PAX_ASLR + .sv_pax_aslr_init = _pax_aslr_init32, +#endif }; INIT_SYSENTVEC(elf32_sysvec, &elf32_freebsd_sysvec); Index: sys/powerpc/powerpc/elf32_machdep.c =================================================================== --- sys/powerpc/powerpc/elf32_machdep.c +++ sys/powerpc/powerpc/elf32_machdep.c @@ -25,6 +25,8 @@ * $FreeBSD$ */ +#include "opt_pax.h" + #include #include #include @@ -34,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -107,6 +110,9 @@ .sv_shared_page_base = FREEBSD32_SHAREDPAGE, .sv_shared_page_len = PAGE_SIZE, .sv_schedtail = NULL, +#ifdef PAX_ASLR + .sv_pax_aslr_init = _pax_aslr_init32, +#endif }; INIT_SYSENTVEC(elf32_sysvec, &elf32_freebsd_sysvec); Index: sys/powerpc/powerpc/elf64_machdep.c =================================================================== --- sys/powerpc/powerpc/elf64_machdep.c +++ sys/powerpc/powerpc/elf64_machdep.c @@ -25,12 +25,15 @@ * $FreeBSD$ */ +#include "opt_pax.h" + #include #include #include #include #include #include +#include #include #include #include @@ -83,6 +86,9 @@ .sv_shared_page_base = SHAREDPAGE, .sv_shared_page_len = PAGE_SIZE, .sv_schedtail = NULL, +#ifdef PAX_ASLR + .sv_pax_aslr_init = _pax_aslr_init, +#endif }; INIT_SYSENTVEC(elf64_sysvec, &elf64_freebsd_sysvec); Index: sys/security/mac_bsdextended/mac_bsdextended.h =================================================================== --- sys/security/mac_bsdextended/mac_bsdextended.h +++ sys/security/mac_bsdextended/mac_bsdextended.h @@ -54,6 +54,10 @@ #define MBI_ALLPERM (MBI_EXEC | MBI_WRITE | MBI_READ | MBI_ADMIN | \ MBI_STAT | MBI_APPEND) +#define MBI_ASLR_ENABLED 0x01 +#define MBI_ASLR_DISABLED 0x02 +#define MBI_ALLPAX (MBI_ASLR_ENABLED | MBI_ASLR_DISABLED) + #define MBS_UID_DEFINED 0x00000001 /* uid field should be matched */ #define MBS_GID_DEFINED 0x00000002 /* gid field should be matched */ #define MBS_PRISON_DEFINED 0x00000004 /* prison field should be matched */ Index: sys/sparc64/sparc64/elf_machdep.c =================================================================== --- sys/sparc64/sparc64/elf_machdep.c +++ sys/sparc64/sparc64/elf_machdep.c @@ -34,12 +34,15 @@ #include __FBSDID("$FreeBSD$"); +#include "opt_pax.h" + #include #include #include #include #include #include +#include #include #include #include @@ -87,6 +90,9 @@ .sv_fetch_syscall_args = cpu_fetch_syscall_args, .sv_syscallnames = syscallnames, .sv_schedtail = NULL, +#ifdef PAX_ASLR + .sv_pax_aslr_init = _pax_aslr_init, +#endif }; static Elf64_Brandinfo freebsd_brand_info = { Index: sys/sys/imgact.h =================================================================== --- sys/sys/imgact.h +++ sys/sys/imgact.h @@ -80,6 +80,7 @@ unsigned long pagesizes; int pagesizeslen; vm_prot_t stack_prot; + int pax_flags; }; #ifdef _KERNEL Index: sys/sys/jail.h =================================================================== --- sys/sys/jail.h +++ sys/sys/jail.h @@ -184,6 +184,17 @@ char pr_hostname[MAXHOSTNAMELEN]; /* (p) jail hostname */ char pr_domainname[MAXHOSTNAMELEN]; /* (p) jail domainname */ char pr_hostuuid[HOSTUUIDLEN]; /* (p) jail hostuuid */ + /* Lock only needed for pax_* if pr_pax_set == 0 */ + int pr_pax_set; /* (p) PaX settings initialized */ + int pr_pax_aslr_status; /* (p) PaX ASLR enabled */ + int pr_pax_aslr_debug; /* (p) PaX ASLR debug */ + int pr_pax_aslr_mmap_len; /* (p) Number of bits randomized with mmap */ + int pr_pax_aslr_stack_len; /* (p) Number of bits randomized with stack */ + int pr_pax_aslr_exec_len; /* (p) Number of bits randomized with the execbase */ + int pr_pax_aslr_compat_status; /* (p) PaX ASLR enabled (compat32) */ + int pr_pax_aslr_compat_mmap_len; /* (p) Number of bits randomized with mmap (compat32) */ + int pr_pax_aslr_compat_stack_len; /* (p) Number of bits randomized with stack (compat32) */ + int pr_pax_aslr_compat_exec_len; /* (p) Number of bits randomized with the execbase (compat32) */ }; struct prison_racct { Index: sys/sys/kernel.h =================================================================== --- sys/sys/kernel.h +++ sys/sys/kernel.h @@ -102,6 +102,7 @@ SI_SUB_WITNESS = 0x1A80000, /* witness initialization */ SI_SUB_MTX_POOL_DYNAMIC = 0x1AC0000, /* dynamic mutex pool */ SI_SUB_LOCK = 0x1B00000, /* various locks */ + SI_SUB_PAX = 0x1B80000, /* pax setup */ SI_SUB_EVENTHANDLER = 0x1C00000, /* eventhandler init */ SI_SUB_VNET_PRELINK = 0x1E00000, /* vnet init before modules */ SI_SUB_KLD = 0x2000000, /* KLD and module setup */ Index: sys/sys/ktr_class.h =================================================================== --- sys/sys/ktr_class.h +++ sys/sys/ktr_class.h @@ -71,7 +71,8 @@ #define KTR_INET6 0x10000000 /* IPv6 stack */ #define KTR_SCHED 0x20000000 /* Machine parsed sched info. */ #define KTR_BUF 0x40000000 /* Buffer cache */ -#define KTR_ALL 0x7fffffff +#define KTR_PAX 0x80000000 /* PaX */ +#define KTR_ALL 0xffffffff /* KTR trace classes to compile in */ #ifdef KTR Index: sys/sys/pax.h =================================================================== --- /dev/null +++ sys/sys/pax.h @@ -0,0 +1,248 @@ +/*- + * Copyright (c) 2006 Elad Efrat + * Copyright (c) 2013-2014, by Oliver Pinter + * Copyright (c) 2014, by Shawn Webb + * All rights reserved. + * + * 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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$ + */ + +#ifndef __SYS_PAX_H +#define __SYS_PAX_H + +#ifdef _KERNEL + +struct image_params; +struct prison; +struct thread; +struct proc; +struct vnode; +struct vmspace; +struct vm_offset_t; + +/* + * used in sysctl handler + */ +#define PAX_FEATURE_DISABLED 0 +#define PAX_FEATURE_OPTIN 1 +#define PAX_FEATURE_OPTOUT 2 +#define PAX_FEATURE_FORCE_ENABLED 3 +#define PAX_FEATURE_UNKNOWN_STATUS 4 + +extern const char *pax_status_str[]; + +#define PAX_FEATURE_SIMPLE_DISABLED 0 +#define PAX_FEATURE_SIMPLE_ENABLED 1 + +extern const char *pax_status_simple_str[]; + +#ifndef PAX_ASLR_DELTA +#define PAX_ASLR_DELTA(delta, lsb, len) \ + (((delta) & ((1UL << (len)) - 1)) << (lsb)) +#endif /* PAX_ASLR_DELTA */ + +/* + * generic ASLR values + * + * MMAP | 32 bit | 64 bit | + * +-------+--------+--------+ + * | MIN | 8 bit | 16 bit | + * +-------+--------+--------+ + * | DEF | 8 bit | 21 bit | + * +-------+--------+--------+ + * | MAX | 16 bit | 32 bit | + * +-------+--------+--------+ + * + * STACK | 32 bit | 64 bit | + * +-------+--------+--------+ + * | MIN | 6 bit | 12 bit | + * +-------+--------+--------+ + * | DEF | 6 bit | 16 bit | + * +-------+--------+--------+ + * | MAX | 10 bit | 21 bit | + * +-------+--------+--------+ + * + * EXEC | 32 bit | 64 bit | + * +-------+--------+--------+ + * | MIN | 6 bit | 12 bit | + * +-------+--------+--------+ + * | DEF | 6 bit | 21 bit | + * +-------+--------+--------+ + * | MAX | 10 bit | 21 bit | + * +-------+--------+--------+ + * + */ +#ifndef PAX_ASLR_DELTA_MMAP_LSB +#define PAX_ASLR_DELTA_MMAP_LSB PAGE_SHIFT +#endif /* PAX_ASLR_DELTA_MMAP_LSB */ + +#ifndef PAX_ASLR_DELTA_MMAP_MIN_LEN +#define PAX_ASLR_DELTA_MMAP_MIN_LEN ((sizeof(void *) * NBBY) / 4) +#endif /* PAX_ASLR_DELTA_MMAP_MAX_LEN */ + +#ifndef PAX_ASLR_DELTA_MMAP_MAX_LEN +#define PAX_ASLR_DELTA_MMAP_MAX_LEN ((sizeof(void *) * NBBY) / 2) +#endif /* PAX_ASLR_DELTA_MMAP_MAX_LEN */ + +#ifndef PAX_ASLR_DELTA_STACK_LSB +#define PAX_ASLR_DELTA_STACK_LSB 3 +#endif /* PAX_ASLR_DELTA_STACK_LSB */ + +#ifndef PAX_ASLR_DELTA_STACK_MIN_LEN +#define PAX_ASLR_DELTA_STACK_MIN_LEN ((sizeof(void *) * NBBY) / 5) +#endif /* PAX_ASLR_DELTA_STACK_MAX_LEN */ + +#ifndef PAX_ASLR_DELTA_STACK_MAX_LEN +#define PAX_ASLR_DELTA_STACK_MAX_LEN ((sizeof(void *) * NBBY) / 3) +#endif /* PAX_ASLR_DELTA_STACK_MAX_LEN */ + +#ifndef PAX_ASLR_DELTA_EXEC_LSB +#define PAX_ASLR_DELTA_EXEC_LSB PAGE_SHIFT +#endif /* PAX_ASLR_DELTA_EXEC_LSB */ + +#ifndef PAX_ASLR_DELTA_EXEC_MIN_LEN +#define PAX_ASLR_DELTA_EXEC_MIN_LEN ((sizeof(void *) * NBBY) / 5) +#endif /* PAX_ASLR_DELTA_EXEC_MAX_LEN */ + +#ifndef PAX_ASLR_DELTA_EXEC_MAX_LEN +#define PAX_ASLR_DELTA_EXEC_MAX_LEN ((sizeof(void *) * NBBY) / 3) +#endif /* PAX_ASLR_DELTA_EXEC_MAX_LEN */ + +/* + * ASLR default values for native host + */ +#ifdef __amd64__ +#ifndef PAX_ASLR_DELTA_MMAP_DEF_LEN +#define PAX_ASLR_DELTA_MMAP_DEF_LEN 21 +#endif /* PAX_ASLR_DELTA_MMAP_DEF_LEN */ +#ifndef PAX_ASLR_DELTA_STACK_DEF_LEN +#define PAX_ASLR_DELTA_STACK_DEF_LEN 16 +#endif /* PAX_ASLR_DELTA_STACK_DEF_LEN */ +#ifndef PAX_ASLR_DELTA_EXEC_DEF_LEN +#define PAX_ASLR_DELTA_EXEC_DEF_LEN 21 +#endif /* PAX_ASLR_DELTA_EXEC_DEF_LEN */ +#else +#ifndef PAX_ASLR_DELTA_MMAP_DEF_LEN +#define PAX_ASLR_DELTA_MMAP_DEF_LEN PAX_ASLR_DELTA_MMAP_MIN_LEN +#endif /* PAX_ASLR_DELTA_MMAP_DEF_LEN */ +#ifndef PAX_ASLR_DELTA_STACK_DEF_LEN +#define PAX_ASLR_DELTA_STACK_DEF_LEN PAX_ASLR_DELTA_STACK_MIN_LEN +#endif /* PAX_ASLR_DELTA_STACK_DEF_LEN */ +#ifndef PAX_ASLR_DELTA_EXEC_DEF_LEN +#define PAX_ASLR_DELTA_EXEC_DEF_LEN PAX_ASLR_DELTA_EXEC_MIN_LEN +#endif /* PAX_ASLR_DELTA_EXEC_DEF_LEN */ +#endif /* __amd64__ */ + +/* + * ASLR values for COMPAT_FREEBSD32 and COMPAT_LINUX + */ +#ifndef PAX_ASLR_COMPAT_DELTA_MMAP_LSB +#define PAX_ASLR_COMPAT_DELTA_MMAP_LSB PAGE_SHIFT +#endif /* PAX_ASLR_COMPAT_DELTA_MMAP_LSB */ + +#ifndef PAX_ASLR_COMPAT_DELTA_MMAP_MIN_LEN +#define PAX_ASLR_COMPAT_DELTA_MMAP_MIN_LEN ((sizeof(int) * NBBY) / 4) +#endif /* PAX_ASLR_COMPAT_DELTA_MMAP_MAX_LEN */ + +#ifndef PAX_ASLR_COMPAT_DELTA_MMAP_MAX_LEN +#define PAX_ASLR_COMPAT_DELTA_MMAP_MAX_LEN ((sizeof(int) * NBBY) / 2) +#endif /* PAX_ASLR_COMPAT_DELTA_MMAP_MAX_LEN */ + +#ifndef PAX_ASLR_COMPAT_DELTA_STACK_LSB +#define PAX_ASLR_COMPAT_DELTA_STACK_LSB 3 +#endif /* PAX_ASLR_COMPAT_DELTA_STACK_LSB */ + +#ifndef PAX_ASLR_COMPAT_DELTA_STACK_MIN_LEN +#define PAX_ASLR_COMPAT_DELTA_STACK_MIN_LEN ((sizeof(int) * NBBY) / 5) +#endif /* PAX_ASLR_COMPAT_DELTA_STACK_MAX_LEN */ + +#ifndef PAX_ASLR_COMPAT_DELTA_STACK_MAX_LEN +#define PAX_ASLR_COMPAT_DELTA_STACK_MAX_LEN ((sizeof(int) * NBBY) / 3) +#endif /* PAX_ASLR_COMPAT_DELTA_STACK_MAX_LEN */ + +#ifndef PAX_ASLR_COMPAT_DELTA_EXEC_LSB +#define PAX_ASLR_COMPAT_DELTA_EXEC_LSB PAGE_SHIFT +#endif /* PAX_ASLR_COMPAT_DELTA_EXEC_LSB */ + +#ifndef PAX_ASLR_COMPAT_DELTA_EXEC_MIN_LEN +#define PAX_ASLR_COMPAT_DELTA_EXEC_MIN_LEN ((sizeof(int) * NBBY) / 5) +#endif /* PAX_ASLR_COMPAT_DELTA_EXEC_MAX_LEN */ + +#ifndef PAX_ASLR_COMPAT_DELTA_EXEC_MAX_LEN +#define PAX_ASLR_COMPAT_DELTA_EXEC_MAX_LEN ((sizeof(int) * NBBY) / 3) +#endif /* PAX_ASLR_COMPAT_DELTA_EXEC_MAX_LEN */ + +extern int pax_aslr_status; +extern int pax_aslr_debug; + +extern int pax_aslr_mmap_len; +extern int pax_aslr_stack_len; +extern int pax_aslr_exec_len; +#ifdef COMPAT_FREEBSD32 +extern int pax_aslr_compat_status; +extern int pax_aslr_compat_mmap_len; +extern int pax_aslr_compat_stack_len; +extern int pax_aslr_compat_exec_len; +#endif /* COMPAT_FREEBSD32 */ + +#define PAX_NOTE_MPROTECT 0x00000001 +#define PAX_NOTE_NOMPROTECT 0x00000002 +#define PAX_NOTE_SEGVGUARD 0x00000004 +#define PAX_NOTE_NOSEGVGUARD 0x00000008 +#define PAX_NOTE_ASLR 0x00000010 +#define PAX_NOTE_NOASLR 0x00000020 + +#define PAX_NOTE_RESERVED0 0x40000000 +#define PAX_NOTE_FINALIZED 0x80000000 + +#define PAX_NOTE_ALL_ENABLED \ + (PAX_NOTE_MPROTECT | PAX_NOTE_SEGVGUARD | PAX_NOTE_ASLR) +#define PAX_NOTE_ALL_DISABLED \ + (PAX_NOTE_NOMPROTECT | PAX_NOTE_NOSEGVGUARD | PAX_NOTE_NOASLR) +#define PAX_NOTE_ALL (PAX_NOTE_ALL_ENABLED | PAX_NOTE_ALL_DISABLED) + +/* + * generic pax functions + */ +int pax_elf(struct image_params *, uint32_t); +int pax_get_flags(struct proc *proc, uint32_t *flags); +struct prison *pax_get_prison(struct proc *proc); +void pax_init_prison(struct prison *pr); + +/* + * ASLR related functions + */ +bool pax_aslr_active(struct proc *proc); +void _pax_aslr_init(struct vmspace *vm, struct proc *p); +void _pax_aslr_init32(struct vmspace *vm, struct proc *p); +void pax_aslr_init(struct image_params *imgp); +void pax_aslr_mmap(struct proc *p, vm_offset_t *addr, + vm_offset_t orig_addr, int flags); +u_int pax_aslr_setup_flags(struct image_params *imgp, u_int mode); +void pax_aslr_stack(struct thread *td, uintptr_t *addr); + +#endif /* _KERNEL */ + +#endif /* __SYS_PAX_H */ Index: sys/sys/proc.h =================================================================== --- sys/sys/proc.h +++ sys/sys/proc.h @@ -539,6 +539,7 @@ u_int p_stops; /* (c) Stop event bitmask. */ u_int p_stype; /* (c) Stop event type. */ char p_step; /* (c) Process is stopped. */ + u_int p_pax; /* (b) PaX is enabled to this process */ u_char p_pfsflags; /* (c) Procfs flags. */ struct nlminfo *p_nlminfo; /* (?) Only used by/for lockd. */ struct kaioinfo *p_aioinfo; /* (y) ASYNC I/O info. */ Index: sys/sys/sysent.h =================================================================== --- sys/sys/sysent.h +++ sys/sys/sysent.h @@ -38,6 +38,7 @@ struct sysent; struct thread; struct ksiginfo; +struct proc; typedef int sy_call_t(struct thread *, void *); @@ -77,9 +78,11 @@ #define SY_THR_INCR 0x8 struct image_params; +struct prison; struct __sigset; struct syscall_args; struct trapframe; +struct vmspace; struct vnode; struct sysentvec { @@ -130,6 +133,7 @@ uint32_t sv_timekeep_gen; void *sv_shared_page_obj; void (*sv_schedtail)(struct thread *); + void (*sv_pax_aslr_init)(struct vmspace *vm, struct proc *p); }; #define SV_ILP32 0x000100 Index: sys/vm/vm_map.h =================================================================== --- sys/vm/vm_map.h +++ sys/vm/vm_map.h @@ -241,6 +241,9 @@ caddr_t vm_taddr; /* (c) user virtual address of text */ caddr_t vm_daddr; /* (c) user virtual address of data */ caddr_t vm_maxsaddr; /* user VA at max stack growth */ + vm_size_t vm_aslr_delta_mmap; /* mmap() random delta for ASLR */ + vm_size_t vm_aslr_delta_stack; /* stack random delta for ASLR */ + vm_size_t vm_aslr_delta_exec; /* exec base random delta for ASLR */ volatile int vm_refcnt; /* number of references */ /* * Keep the PMAP last, so that CPU-specific variations of that Index: sys/vm/vm_map.c =================================================================== --- sys/vm/vm_map.c +++ sys/vm/vm_map.c @@ -65,6 +65,8 @@ #include __FBSDID("$FreeBSD$"); +#include "opt_pax.h" + #include #include #include @@ -297,6 +299,12 @@ vm->vm_taddr = 0; vm->vm_daddr = 0; vm->vm_maxsaddr = 0; +#ifdef PAX_ASLR + vm->vm_aslr_delta_mmap = 0; + vm->vm_aslr_delta_stack = 0; + vm->vm_aslr_delta_exec = 0; +#endif + return (vm); } Index: sys/vm/vm_mmap.c =================================================================== --- sys/vm/vm_mmap.c +++ sys/vm/vm_mmap.c @@ -45,6 +45,7 @@ #include "opt_compat.h" #include "opt_hwpmc_hooks.h" +#include "opt_pax.h" #include #include @@ -54,6 +55,7 @@ #include #include #include +#include #include #include #include @@ -202,6 +204,9 @@ struct file *fp; struct vnode *vp; vm_offset_t addr; +#ifdef PAX_ASLR + vm_offset_t orig_addr; +#endif vm_size_t size, pageoff; vm_prot_t cap_maxprot, maxprot; void *handle; @@ -212,6 +217,9 @@ cap_rights_t rights; addr = (vm_offset_t) uap->addr; +#ifdef PAX_ASLR + orig_addr = addr; +#endif size = uap->len; prot = uap->prot; flags = uap->flags; @@ -434,6 +442,10 @@ td->td_fpop = fp; maxprot &= cap_maxprot; +#ifdef PAX_ASLR + pax_aslr_mmap(td->td_proc, &addr, orig_addr, flags); +#endif + /* This relies on VM_PROT_* matching PROT_*. */ error = vm_mmap(&vms->vm_map, &addr, size, prot, maxprot, flags, handle_type, handle, pos);