Index: share/man/man4/Makefile =================================================================== --- share/man/man4/Makefile +++ share/man/man4/Makefile @@ -51,6 +51,7 @@ ${_aout.4} \ ${_apic.4} \ arcmsr.4 \ + aslr.4 \ ${_asmc.4} \ ata.4 \ ath.4 \ Index: share/man/man4/aslr.4 =================================================================== --- /dev/null +++ share/man/man4/aslr.4 @@ -0,0 +1,257 @@ +.\"- +.\" Copyright (c) 2014-2015 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. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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 21, 2015 +.Dt ASLR 4 +.Os +.Sh NAME +.Nm aslr +.Nd Address Space Layout Randomization +.Sh SYNOPSIS +.In sys/types.h +.In sys/pax.h +.Pp +In the kernel configuration file: +.Cd "options PAX_ASLR" +.Sh DESCRIPTION +ASLR randomizes the address space layout of an application, making +exploitation difficult for an attacker. +By randomizing the address space, an attacker won't know where in +memory a vulnerability or a piece of interesting information lies. +.Ss General Overview +When compiled with the PAX_ASLR option, systems will have ASLR +enabled. +For systems with that kernel option enabled, if a user wants +to disable ASLR for a given application, the user must configure that +application to opt-out. +.Pp +Another kernel option, +.Cd PAX_SYSCTLS , +exposes additional +.Xr sysctl 8 +tunables, allowing ASLR behavior control without requiring a reboot. +By default, the +.Xr sysctl 8 +.Va security.pax.aslr.status +can only be changed +at boot time via +.Xr loader.conf 5 . +Enabling the +.Cd PAX_SYSCTLS +kernel option allows a root user to modify +.Va security.pax.aslr.status . +See Appendix A for a list of all the tunables. +.Pp +ASLR tunables are per-jail and each +.Xr jail 8 +inherits its parent jail's settings. +Having per-jail tunables allows more flexibility in shared-hosting +environments. +.Ss Implementation Details +A new +.Xr SYSINIT 9 + subroutine ID, +.Dv SI_SUB_PAX , +initializes ASLR system +variables. +Upon system boot, tunables from +.Xr loader.conf 5 +are checked for validity. +Any invalid values generate a warning message to the console and the +tunable is set to a sensible default. +.Pp +For the sake of performance, the ASLR system relies on per-process +deltas rather than calling +.Xr arc4random 3 +for each mapping. +When a process calls +.Xr execve 2 +.Ns , +the ASLR deltas are initialized. +Deltas are randomly generated for the execution base, +.Xr mmap 2 +.Ns , +and stack addresses. +Only the execution base of applications compiled as Position +Independent Executables (PIEs) is randomized. +The execution base of non-PIE applications is not modified. +The mappings of shared objects are randomized for both PIE and non-PIE +applications. +.Pp +The deltas are used as a hint to the Virtual Memory (VM) system. +The VM system may modify the hint to make a better fit for superpages +and other alignment constraints. +.Pp +The delta applied to the PIE execbase is different than the delta +applied to the base address of shared objects. +In the Executable and Linkable File (ELF) image handler, the +execution base of PIE applications is randomized by adding the delta +controlled by the +.Va security.pax.aslr.exec_len +tunable to +.Va et_dyn_addr , +which is initialized to be +.Dv ET_DYN_LOAD_ADDR +(an architecture- dependent macro). +The base address of shared objects loaded by the dynamic linker are +randomized by applying the delta controlled by the +.Va security.pax.aslr.mmap_len +tunable in +.Fn sys_mmap +.Ns . +Stack randomization is implemented using a stack gap. +On executable image activation, the stack delta is computed and +subtracted from the top of the stack. +.Ss APPENDIX A +NOTE: All tunables can only be changed during boot-time via +.Fa /boot/loader.conf +unless the kernel has been compiled with +.Cd PAX_SYSCTLS +.Ns . +.Bl -bullet +.It +.Va security.pax.aslr.status +.Bl -dash -compact +.It +Type: integer +.It +Description: Toggle system-wide ASLR protection. +.It +Values: +.br +0 - ASLR disabled system-wide. +Individual applications may +.Em NOT +opt in. +.br +1 - ASLR disabled but applications may opt in. +.br +2 - ASLR enabled and applications may opt out. +.br +3 - ASLR enabled for all applications. +Applications may not opt out. +.It +Default: 2 +.El +.It +.Va security.pax.aslr.exec_len +.Bl -dash -compact +.It +Type: integer +.It +Description: Set the number of bits to be randomized for the PIE +execbase. +.It +Values: +.br +For 32-bit systems, minimum of 8, maximum of 21. +For 64-bit systems, minimum of 16, maximum of 42. +.It +Default: For 32-bit systems: 14. +For 64-bit systems: 16. +.El +.It +.Va security.pax.aslr.mmap_len +.Bl -dash -compact +.It +Type: integer +.It +Description: Set the number of bits to be randomized for +.Xr mmap 2 +calls. +.It +Values: +.br +For 32-bit systems, minimum of 8, maximum of 21. +For 64-bit systems, minimum of 16, maximum of 42. +.It +Default: For 32-bit systems: 14. +For 64-bit systems: 21. +.El +.It +.Va security.pax.aslr.stack_len +.Bl -dash -compact +.It +Type: integer +.It +Description: Set the number of bits to be randomized for the stack. +.It +Values: +.br +For 32-bit systems, minimum of 8, maximum of 21. +For 64-bit systems, minimum of 16, maximum of 42. +.It +Default: For 32-bit systems: 8. +For 64-bit systems: 16. +.El +.El +.Sh SEE ALSO +.Xr mmap 2 , +.Xr elf 3 , +.Xr mac 4 +.Rs +.%T "PaX ASLR" +.%U http://pax.grsecurity.net/docs/aslr.txt +.Re +.Rs +.%T "HardenedBSD" +.%U http://hardenedbsd.org/ +.Re +.Rs +.%T "secadm" +.%U https://github.com/HardenedBSD/secadm +.Re +.Sh AUTHORS +This manual page was written by +.An -nosplit +.An Shawn Webb . +The ASLR implementation was written by +.An Oliver Pinter +and +.An Shawn Webb . +.Sh BUGS +The existing gap-based stack randomization is not optimal. +Mapping-base stack randomization is more robust, but hard-coded kernel +structures and addresses, especially +.Va PS_STRINGS , +will need to be modified. +The required changes to +.Va PS_STRINGS +are major and will likely touch +userland along with the kernel. +The original PaX implementation, from which the +.Fx +implementation is inspired, uses a special ELF process header which +requires modification of executable files. +The authors of the +.Fx +implementation have deliberately chosen to go a different route based +on the +.Xr mac 4 +framework. +Support for filesystem extended attributes will be added at a later +time. 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 @@ -82,6 +85,7 @@ .sv_shared_page_base = SHAREDPAGE, .sv_shared_page_len = PAGE_SIZE, .sv_schedtail = NULL, + .sv_pax_aslr_init = pax_aslr_init_vmspace, }; INIT_SYSENTVEC(elf64_sysvec, &elf64_freebsd_sysvec); Index: sys/amd64/conf/GENERIC =================================================================== --- sys/amd64/conf/GENERIC +++ sys/amd64/conf/GENERIC @@ -69,6 +69,8 @@ options CAPABILITY_MODE # Capsicum capability mode options CAPABILITIES # Capsicum capabilities options MAC # TrustedBSD MAC Framework +#options PAX_ASLR # Address Space Layout Randomization +#options PAX_SYSCTLS # Run-time settings for PAX and Hardening options KDTRACE_FRAME # Ensure frames are compiled in options KDTRACE_HOOKS # Kernel DTrace hooks options DDB_CTF # Kernel ELF linker loads CTF data Index: sys/amd64/include/vmparam.h =================================================================== --- sys/amd64/include/vmparam.h +++ sys/amd64/include/vmparam.h @@ -178,7 +178,8 @@ #define VM_MAXUSER_ADDRESS UVADDR(NUPML4E, 0, 0, 0) #define SHAREDPAGE (VM_MAXUSER_ADDRESS - PAGE_SIZE) -#define USRSTACK SHAREDPAGE +#define SHAREDPAGE_GUARD (4 * PAGE_SIZE) +#define USRSTACK (SHAREDPAGE - SHAREDPAGE_GUARD) #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,7 @@ .sv_shared_page_base = LINUX32_SHAREDPAGE, .sv_shared_page_len = PAGE_SIZE, .sv_schedtail = linux_schedtail, + .sv_pax_aslr_init = pax_aslr_init_vmspace32, }; 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,7 @@ .sv_fetch_syscall_args = cpu_fetch_syscall_args, .sv_syscallnames = syscallnames, .sv_schedtail = NULL, + .sv_pax_aslr_init = pax_aslr_init_vmspace, }; static Elf32_Brandinfo freebsd_brand_info = { Index: sys/arm/arm/machdep.c =================================================================== --- sys/arm/arm/machdep.c +++ sys/arm/arm/machdep.c @@ -47,6 +47,7 @@ #include "opt_platform.h" #include "opt_sched.h" #include "opt_timer.h" +#include "opt_pax.h" #include __FBSDID("$FreeBSD$"); @@ -116,6 +117,10 @@ #include #endif +#ifdef PAX_ASLR +#include +#endif + #ifdef DEBUG #define debugf(fmt, args...) printf(fmt, ##args) #else @@ -287,6 +292,9 @@ tf->tf_pc = (register_t)catcher; tf->tf_usr_sp = (register_t)fp; tf->tf_usr_lr = (register_t)(PS_STRINGS - *(p->p_sysent->sv_szsigcode)); +#ifdef PAX_ASLR + pax_aslr_stack(p, &tf->tf_usr_lr); +#endif CTR3(KTR_SIG, "sendsig: return td=%p pc=%#x sp=%#x", td, tf->tf_usr_lr, tf->tf_usr_sp); 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 @@ -2802,6 +2804,10 @@ szsigcode = 0; destp = (uintptr_t)arginfo; +#ifdef PAX_ASLR + pax_aslr_stack(imgp->proc, &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,7 @@ .sv_shared_page_base = FREEBSD32_SHAREDPAGE, .sv_shared_page_len = PAGE_SIZE, .sv_schedtail = NULL, + .sv_pax_aslr_init = pax_aslr_init_vmspace32, }; INIT_SYSENTVEC(elf_ia32_sysvec, &ia32_freebsd_sysvec); Index: sys/conf/NOTES =================================================================== --- sys/conf/NOTES +++ sys/conf/NOTES @@ -2978,6 +2978,9 @@ # Module to enable execution of application via emulators like QEMU options IMAGACT_BINMISC +# PaX-inspired exploit mitigations +options PAX_ASLR # Address Space Layout Randomization +options PAX_SYSCTLS # Run-time settings for PAX and Hardening # zlib I/O stream support # This enables support for compressed core dumps. options GZIO Index: sys/conf/files =================================================================== --- sys/conf/files +++ sys/conf/files @@ -3024,6 +3024,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 @@ -931,6 +931,10 @@ # Resource Limits RCTL opt_global.h +# PaX - hardening options +PAX_ASLR 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 @@ -27,6 +27,7 @@ __FBSDID("$FreeBSD$"); #include "opt_cpu.h" +#include "opt_pax.h" #include #include @@ -34,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -88,6 +90,7 @@ .sv_shared_page_base = SHAREDPAGE, .sv_shared_page_len = PAGE_SIZE, .sv_schedtail = NULL, + .sv_pax_aslr_init = pax_aslr_init_vmspace, }; 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,7 @@ .sv_fetch_syscall_args = cpu_fetch_syscall_args, .sv_syscallnames = NULL, .sv_schedtail = NULL, + .sv_pax_aslr_init = pax_aslr_init_vmspace, }; 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 @@ -973,6 +976,7 @@ .sv_shared_page_base = LINUX_SHAREDPAGE, .sv_shared_page_len = PAGE_SIZE, .sv_schedtail = linux_schedtail, + .sv_pax_aslr_init = pax_aslr_init_vmspace, }; INIT_SYSENTVEC(aout_sysvec, &linux_sysvec); @@ -1011,6 +1015,7 @@ .sv_shared_page_base = LINUX_SHAREDPAGE, .sv_shared_page_len = PAGE_SIZE, .sv_schedtail = linux_schedtail, + .sv_pax_aslr_init = pax_aslr_init_vmspace, }; 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,7 @@ .sv_fetch_syscall_args = cpu_fetch_syscall_args, .sv_syscallnames = syscallnames, .sv_schedtail = NULL, + .sv_pax_aslr_init = pax_aslr_init_vmspace, }; #elif defined(__amd64__) @@ -143,6 +147,7 @@ .sv_set_syscall_retval = ia32_set_syscall_retval, .sv_fetch_syscall_args = ia32_fetch_syscall_args, .sv_syscallnames = freebsd32_syscallnames, + .sv_pax_aslr_init = pax_aslr_init_vmspace32, }; #else #error "Port me" Index: sys/kern/imgact_elf.c =================================================================== --- sys/kern/imgact_elf.c +++ sys/kern/imgact_elf.c @@ -33,6 +33,7 @@ #include "opt_capsicum.h" #include "opt_compat.h" +#include "opt_pax.h" #include "opt_gzio.h" #include @@ -50,6 +51,7 @@ #include #include #include +#include #include #include #include @@ -797,16 +799,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; @@ -827,6 +820,20 @@ 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 + pax_aslr_execbase(imgp->proc, &et_dyn_addr); +#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 @@ -46,6 +46,7 @@ #include "opt_ddb.h" #include "opt_init_path.h" +#include "opt_pax.h" #include "opt_verbose_sysinit.h" #include @@ -61,6 +62,7 @@ #include #include #include +#include #include #include #include @@ -411,6 +413,7 @@ .sv_fetch_syscall_args = null_fetch_syscall_args, .sv_syscallnames = NULL, .sv_schedtail = NULL, + .sv_pax_aslr_init = NULL, }; /* @@ -478,6 +481,9 @@ p->p_flag = P_SYSTEM | P_INMEM; p->p_flag2 = 0; p->p_state = PRS_NORMAL; +#if defined(PAX_ASLR) + p->p_pax = PAX_NOTE_ALL_DISABLED; +#endif knlist_init_mtx(&p->p_klist, &p->p_mtx); STAILQ_INIT(&p->p_ktr); p->p_nice = NZERO; @@ -495,6 +501,9 @@ td->td_flags = TDF_INMEM; td->td_pflags = TDP_KTHREAD; td->td_cpuset = cpuset_thread0(); +#if defined(PAX_ASLR) + td->td_pax = PAX_NOTE_ALL_DISABLED; +#endif prison0_init(); p->p_peers = 0; p->p_leader = p; 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 @@ -65,6 +67,7 @@ #include #include #include +#include #ifdef KTRACE #include #endif @@ -130,6 +133,10 @@ SYSCTL_INT(_security_bsd, OID_AUTO, map_at_zero, CTLFLAG_RWTUN, &map_at_zero, 0, "Permit processes to map an object at virtual address 0."); +#ifdef PAX_ASLR +static int exec_check_aslr(struct image_params *imgp); +#endif + static int sysctl_kern_ps_strings(SYSCTL_HANDLER_ARGS) { @@ -383,6 +390,7 @@ imgp->proc = p; imgp->attr = &attr; imgp->args = args; + imgp->pax_flags = 0; #ifdef MAC error = mac_execve_enter(imgp, mac_p); @@ -1043,6 +1051,12 @@ map = &vmspace->vm_map; } +#ifdef PAX_ASLR + PROC_LOCK(imgp->proc); + pax_aslr_init(imgp); + PROC_UNLOCK(imgp->proc); +#endif + /* Map a shared page */ obj = sv->sv_shared_page_obj; if (obj != NULL) { @@ -1089,6 +1103,9 @@ */ vmspace->vm_ssize = sgrowsiz >> PAGE_SHIFT; vmspace->vm_maxsaddr = (char *)sv->sv_usrstack - ssiz; +#ifdef PAX_ASLR + pax_aslr_stack_fixup(imgp->proc); +#endif return (0); } @@ -1256,6 +1273,9 @@ szsigcode = *(p->p_sysent->sv_szsigcode); } destp = (uintptr_t)arginfo; +#ifdef PAX_ASLR + pax_aslr_stack(p, &destp); +#endif /* * install sigcode @@ -1376,6 +1396,46 @@ return (stack_base); } +#ifdef PAX_ASLR +/* + * If we've disabled ASLR via ptrace, do not allow execution of + * setuid/setgid binaries. + */ +static int +exec_check_aslr(struct image_params *imgp) +{ + struct proc *p = imgp->proc; + struct ucred *oldcred = p->p_ucred; + struct vattr *attr = imgp->attr; + int credential_changing; +#ifdef MAC + struct label *interpvplabel = NULL; + int will_transition; +#endif + + credential_changing = 0; + credential_changing |= (attr->va_mode & S_ISUID) && oldcred->cr_uid != + attr->va_uid; + credential_changing |= (attr->va_mode & S_ISGID) && oldcred->cr_gid != + attr->va_gid; + +#ifdef MAC + will_transition = mac_vnode_execve_will_transition(oldcred, imgp->vp, + interpvplabel, imgp); + credential_changing |= will_transition; +#endif + + if (credential_changing) { + if ((p->p_paxdebug & PAX_NOTE_NOASLR) == PAX_NOTE_NOASLR) { + if (pax_aslr_active(imgp->proc)) + return (EPERM); + } + } + + return (pax_elf(imgp, p->p_paxdebug)); +} +#endif /* PAX_ASLR */ + /* * Check permissions of file to execute. * Called with imgp->vp locked. @@ -1397,6 +1457,16 @@ if (error) return (error); +#if defined(PAX_ASLR) + PROC_LOCK(imgp->proc); + error = exec_check_aslr(imgp); + if (error) { + PROC_UNLOCK(imgp->proc); + return (error); + } + PROC_UNLOCK(imgp->proc); +#endif + #ifdef MAC error = mac_vnode_check_exec(td->td_ucred, imgp->vp, imgp); if (error) Index: sys/kern/kern_fork.c =================================================================== --- sys/kern/kern_fork.c +++ sys/kern/kern_fork.c @@ -471,6 +471,7 @@ __rangeof(struct thread, td_startcopy, td_endcopy)); bcopy(&p2->p_comm, &td2->td_name, sizeof(td2->td_name)); + td2->td_pax = p2->p_pax; td2->td_sigstk = td->td_sigstk; td2->td_flags = TDF_INMEM; td2->td_lend_user_pri = PRI_MAX; 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 @@ -246,6 +248,9 @@ prison0.pr_cpuset = cpuset_ref(thread0.td_cpuset); prison0.pr_osreldate = osreldate; strlcpy(prison0.pr_osrelease, osrelease, sizeof(prison0.pr_osrelease)); +#ifdef PAX_ASLR + pax_init_prison(&prison0); +#endif } #ifdef INET @@ -1357,7 +1362,9 @@ prison_deref(pr, PD_LIST_XLOCKED); goto done_releroot; } - +#ifdef 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,180 @@ +/*- + * Copyright (c) 2006 Elad Efrat + * Copyright (c) 2013-2015, by Oliver Pinter + * Copyright (c) 2014-2015, 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$ + * + * HardenedBSD-version: 2fba75c32739bd7f7c80163ec88e3655c3130753 + * HardenedBSD-version: v16 + * + */ +#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 + +static int pax_validate_flags(uint32_t flags); +static int pax_check_conflicting_modes(uint32_t mode); + +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 *p) +{ + + /* p can be NULL with kernel threads, so use prison0. */ + if (p == NULL || p->p_ucred == NULL) + return (&prison0); + + PROC_LOCK_ASSERT(p, MA_OWNED); + + return (p->p_ucred->cr_prison); +} + +/* +* As it stands right now, only the sysctl(8)s controlling ASLR use +* pax_get_prison_td. Thus this function requires td being equal to +* curthread. +*/ +struct prison * +pax_get_prison_td(struct thread *td) +{ + + KASSERT(td == curthread, ("pax_get_prison_td: td != curthread")); + if (td == NULL || td->td_ucred == NULL) + return (&prison0); + return (td->td_ucred->cr_prison); +} + +void +pax_get_flags(struct proc *p, uint32_t *flags) +{ + + *flags = p->p_pax; +} + +void +pax_get_flags_td(struct thread *td, uint32_t *flags) +{ + + *flags = td->td_pax; +} + +static int +pax_validate_flags(uint32_t flags) +{ + + if ((flags & ~PAX_NOTE_ALL) != 0) + return (1); + return (0); +} + +static int +pax_check_conflicting_modes(uint32_t mode) +{ + + if (((mode & PAX_NOTE_ALL_ENABLED) & ((mode & PAX_NOTE_ALL_DISABLED) >> 1)) != 0) + return (1); + return (0); +} + +int +pax_elf(struct image_params *imgp, uint32_t mode) +{ + uint32_t flags, flags_aslr; + + flags = mode; + flags_aslr = 0; + if (pax_validate_flags(flags) != 0) + return (ENOEXEC); + if (pax_check_conflicting_modes(mode) != 0) + return (ENOEXEC); +#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); + imgp->proc->p_pax = flags; + return (0); +} + +void +pax_init_prison(struct prison *pr) +{ + + CTR2(KTR_PAX, "%s: Setting prison %s PaX variables\n", + __func__, pr->pr_name); + + pax_aslr_init_prison(pr); +#ifdef COMPAT_FREEBSD32 + pax_aslr_init_prison32(pr); +#endif +} Index: sys/kern/kern_pax_aslr.c =================================================================== --- /dev/null +++ sys/kern/kern_pax_aslr.c @@ -0,0 +1,807 @@ +/*- + * Copyright (c) 2006 Elad Efrat + * Copyright (c) 2013-2015, by Oliver Pinter + * Copyright (c) 2014-2015, 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$ + * + * HardenedBSD-version: 2fba75c32739bd7f7c80163ec88e3655c3130753 + * HardenedBSD-version: v16 + * + */ +#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 + +#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 | compat | + * +-------+--------+--------+--------+ + * | MIN | 8 bit | 16 bit | 8 bit | + * +-------+--------+--------+--------+ + * | DEF | 14 bit | 21 bit | 14 bit | + * +-------+--------+--------+--------+ + * | MAX | 21 bit | 42 bit | 21 bit | + * +-------+--------+--------+--------+ + * + * STACK | 32 bit | 64 bit | 32 bit | + * +-------+--------+--------+--------+ + * | MIN | 8 bit | 16 bit | 8 bit | + * +-------+--------+--------+--------+ + * | DEF | 8 bit | 16 bit | 8 bit | + * +-------+--------+--------+--------+ + * | MAX | 21 bit | 42 bit | 21 bit | + * +-------+--------+--------+--------+ + * + * EXEC | 32 bit | 64 bit | 32 bit | + * +-------+--------+--------+--------+ + * | MIN | 8 bit | 16 bit | 8 bit | + * +-------+--------+--------+--------+ + * | DEF | 14 bit | 16 bit | 14 bit | + * +-------+--------+--------+--------+ + * | MAX | 21 bit | 42 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) / 3) +#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) / 4) +#endif /* PAX_ASLR_DELTA_STACK_MAX_LEN */ + +#ifndef PAX_ASLR_DELTA_STACK_MAX_LEN +#define PAX_ASLR_DELTA_STACK_MAX_LEN (((sizeof(void *) * NBBY) * 2) / 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) / 4) +#endif /* PAX_ASLR_DELTA_EXEC_MIN_LEN */ + +#ifndef PAX_ASLR_DELTA_EXEC_MAX_LEN +#define PAX_ASLR_DELTA_EXEC_MAX_LEN (((sizeof(void *) * NBBY) * 2) / 3) +#endif /* PAX_ASLR_DELTA_EXEC_MAX_LEN */ + +/* + * ASLR default values for native host + */ +#ifdef __LP64__ +#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 16 +#endif /* PAX_ASLR_DELTA_EXEC_DEF_LEN */ +#else /* ! __LP64__ */ +#ifndef PAX_ASLR_DELTA_MMAP_DEF_LEN +#define PAX_ASLR_DELTA_MMAP_DEF_LEN 14 +#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 14 +#endif /* PAX_ASLR_DELTA_EXEC_DEF_LEN */ +#endif /* __LP64__ */ + +/* + * ASLR values for COMPAT_FREEBSD32, COMPAT_LINUX and MAP_32BIT + */ +#if defined(COMPAT_LINUX) || defined(COMPAT_FREEBSD32) || defined(MAP_32BIT) +#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) / 3) +#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) / 4) +#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) * 2) / 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) / 4) +#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) * 2) / 3) +#endif /* PAX_ASLR_COMPAT_DELTA_EXEC_MAX_LEN */ +#endif + +FEATURE(aslr, "Address Space Layout Randomization."); + +static int pax_aslr_status = PAX_FEATURE_OPTOUT; +static int pax_aslr_mmap_len = PAX_ASLR_DELTA_MMAP_DEF_LEN; +static int pax_aslr_stack_len = PAX_ASLR_DELTA_STACK_DEF_LEN; +static int pax_aslr_exec_len = PAX_ASLR_DELTA_EXEC_DEF_LEN; + +#ifdef COMPAT_FREEBSD32 +static int pax_aslr_compat_status = PAX_FEATURE_OPTOUT; +static int pax_aslr_compat_mmap_len = PAX_ASLR_COMPAT_DELTA_MMAP_MIN_LEN; +static int pax_aslr_compat_stack_len = PAX_ASLR_COMPAT_DELTA_STACK_MIN_LEN; +static int pax_aslr_compat_exec_len = PAX_ASLR_COMPAT_DELTA_EXEC_MIN_LEN; +#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.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_len", &pax_aslr_compat_mmap_len); +TUNABLE_INT("security.pax.aslr.compat.stack_len", &pax_aslr_compat_stack_len); +TUNABLE_INT("security.pax.aslr.compat.exec_len", &pax_aslr_compat_exec_len); +#endif + +#ifdef PAX_SYSCTLS +SYSCTL_DECL(_security_pax); + +/* + * sysctls + */ +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, 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,21] 64 bit: [16,42]"); + +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: [8,21] 64 bit: [16,42]"); + +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: [8,21] 64 bit: [16,42]"); + +static int +sysctl_pax_aslr_status(SYSCTL_HANDLER_ARGS) +{ + struct prison *pr; + int err, val; + + pr = pax_get_prison_td(req->td); + val = pr->pr_hardening.hf_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 == &prison0) + pax_aslr_status = val; + pr->pr_hardening.hf_pax_aslr_status = val; + break; + + default: + return (EINVAL); + } + return (0); +} + +static int +sysctl_pax_aslr_mmap(SYSCTL_HANDLER_ARGS) +{ + struct prison *pr; + int err, val; + + pr = pax_get_prison_td(req->td); + val = pr->pr_hardening.hf_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 == &prison0) + pax_aslr_mmap_len = val; + pr->pr_hardening.hf_pax_aslr_mmap_len = val; + return (0); +} + +static int +sysctl_pax_aslr_stack(SYSCTL_HANDLER_ARGS) +{ + struct prison *pr; + int err, val; + + pr = pax_get_prison_td(req->td); + val = pr->pr_hardening.hf_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 == &prison0) + pax_aslr_stack_len = val; + pr->pr_hardening.hf_pax_aslr_stack_len = val; + return (0); +} + +static int +sysctl_pax_aslr_exec(SYSCTL_HANDLER_ARGS) +{ + struct prison *pr; + int err, val; + + pr = pax_get_prison_td(req->td); + val = pr->pr_hardening.hf_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 == &prison0) + pax_aslr_exec_len = val; + pr->pr_hardening.hf_pax_aslr_exec_len = val; + 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: [8,16]"); + +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: [8,16]"); + +static int +sysctl_pax_aslr_compat_status(SYSCTL_HANDLER_ARGS) +{ + struct prison *pr; + int err, val; + + pr = pax_get_prison_td(req->td); + val = pr->pr_hardening.hf_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 == &prison0) + pax_aslr_compat_status = val; + pr->pr_hardening.hf_pax_aslr_compat_status = val; + 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_td(req->td); + val = pr->pr_hardening.hf_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 == &prison0) + pax_aslr_compat_mmap_len = val; + pr->pr_hardening.hf_pax_aslr_compat_mmap_len = val; + return (0); +} + +static int +sysctl_pax_aslr_compat_stack(SYSCTL_HANDLER_ARGS) +{ + struct prison *pr; + int err, val; + + pr = pax_get_prison_td(req->td); + val = pr->pr_hardening.hf_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 == &prison0) + pax_aslr_compat_stack_len = val; + pr->pr_hardening.hf_pax_aslr_compat_stack_len = val; + return (0); +} + +static int +sysctl_pax_aslr_compat_exec(SYSCTL_HANDLER_ARGS) +{ + struct prison *pr; + int err, val; + + pr = pax_get_prison_td(req->td); + + val = pr->pr_hardening.hf_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 == &prison0) + pax_aslr_compat_exec_len = val; + pr->pr_hardening.hf_pax_aslr_compat_exec_len = val; + 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("warning: invalid settings in loader.conf:" + " (pax_aslr_status = %d)\n", pax_aslr_status); + pax_aslr_status = PAX_FEATURE_FORCE_ENABLED; + break; + } + if (bootverbose) { + 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_FIRST, pax_aslr_sysinit, NULL); + +int +pax_aslr_active(struct proc *p) +{ + uint32_t flags; + + pax_get_flags(p, &flags); + CTR3(KTR_PAX, "%s: pid = %d p_pax = %x", + __func__, p->p_pid, flags); + if ((flags & PAX_NOTE_ASLR) == PAX_NOTE_ASLR) + return (1); + if ((flags & PAX_NOTE_NOASLR) == PAX_NOTE_NOASLR) + return (0); + return (1); +} + +void +pax_aslr_init_vmspace(struct proc *p) +{ + struct prison *pr; + struct vmspace *vm; + unsigned long rand_buf; + + vm = p->p_vmspace; + pr = pax_get_prison(p); + arc4rand(&rand_buf, sizeof(rand_buf), 0); + vm->vm_aslr_delta_mmap = PAX_ASLR_DELTA(rand_buf, + PAX_ASLR_DELTA_MMAP_LSB, + pr->pr_hardening.hf_pax_aslr_mmap_len); + arc4rand(&rand_buf, sizeof(rand_buf), 0); + vm->vm_aslr_delta_stack = PAX_ASLR_DELTA(rand_buf, + PAX_ASLR_DELTA_STACK_LSB, + pr->pr_hardening.hf_pax_aslr_stack_len); + vm->vm_aslr_delta_stack = ALIGN(vm->vm_aslr_delta_stack); + arc4rand(&rand_buf, sizeof(rand_buf), 0); + vm->vm_aslr_delta_exec = PAX_ASLR_DELTA(rand_buf, + PAX_ASLR_DELTA_EXEC_LSB, + pr->pr_hardening.hf_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("warning: invalid settings in loader.conf! " + "(pax_aslr_compat_status = %d)\n", pax_aslr_compat_status); + pax_aslr_compat_status = PAX_FEATURE_FORCE_ENABLED; + break; + } + if (bootverbose) { + 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_init_vmspace32(struct proc *p) +{ + struct prison *pr; + struct vmspace *vm; + long rand_buf; + + vm = p->p_vmspace; + pr = pax_get_prison(p); + arc4rand(&rand_buf, sizeof(rand_buf), 0); + vm->vm_aslr_delta_mmap = PAX_ASLR_DELTA(rand_buf, + PAX_ASLR_COMPAT_DELTA_MMAP_LSB, + pr->pr_hardening.hf_pax_aslr_compat_mmap_len); + arc4rand(&rand_buf, sizeof(rand_buf), 0); + vm->vm_aslr_delta_stack = PAX_ASLR_DELTA(rand_buf, + PAX_ASLR_COMPAT_DELTA_STACK_LSB, + pr->pr_hardening.hf_pax_aslr_compat_stack_len); + vm->vm_aslr_delta_stack = ALIGN(vm->vm_aslr_delta_stack); + arc4rand(&rand_buf, sizeof(rand_buf), 0); + vm->vm_aslr_delta_exec = PAX_ASLR_DELTA(rand_buf, + PAX_ASLR_COMPAT_DELTA_EXEC_LSB, + pr->pr_hardening.hf_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 proc *p; + + p = imgp->proc; + if (!pax_aslr_active(p)) + return; + if (imgp->sysent->sv_pax_aslr_init != NULL) + imgp->sysent->sv_pax_aslr_init(p); +} + +void +pax_aslr_init_prison(struct prison *pr) +{ + struct prison *pr_p; + + CTR2(KTR_PAX, "%s: Setting prison %s PaX variables\n", + __func__, pr->pr_name); + if (pr == &prison0) { + /* prison0 has no parent, use globals */ + pr->pr_hardening.hf_pax_aslr_status = pax_aslr_status; + pr->pr_hardening.hf_pax_aslr_mmap_len = + pax_aslr_mmap_len; + pr->pr_hardening.hf_pax_aslr_stack_len = + pax_aslr_stack_len; + pr->pr_hardening.hf_pax_aslr_exec_len = + pax_aslr_exec_len; + } else { + KASSERT(pr->pr_parent != NULL, + ("%s: pr->pr_parent == NULL", __func__)); + pr_p = pr->pr_parent; + pr->pr_hardening.hf_pax_aslr_status = + pr_p->pr_hardening.hf_pax_aslr_status; + pr->pr_hardening.hf_pax_aslr_mmap_len = + pr_p->pr_hardening.hf_pax_aslr_mmap_len; + pr->pr_hardening.hf_pax_aslr_stack_len = + pr_p->pr_hardening.hf_pax_aslr_stack_len; + pr->pr_hardening.hf_pax_aslr_exec_len = + pr_p->pr_hardening.hf_pax_aslr_exec_len; + } +} + +#ifdef COMPAT_FREEBSD32 +void +pax_aslr_init_prison32(struct prison *pr) +{ + struct prison *pr_p; + + CTR2(KTR_PAX, "%s: Setting prison %s PaX variables\n", + __func__, pr->pr_name); + if (pr == &prison0) { + /* prison0 has no parent, use globals. */ + + pr->pr_hardening.hf_pax_aslr_compat_status = + pax_aslr_compat_status; + pr->pr_hardening.hf_pax_aslr_compat_mmap_len = + pax_aslr_compat_mmap_len; + pr->pr_hardening.hf_pax_aslr_compat_stack_len = + pax_aslr_compat_stack_len; + pr->pr_hardening.hf_pax_aslr_compat_exec_len = + pax_aslr_compat_exec_len; + } else { + KASSERT(pr->pr_parent != NULL, + ("%s: pr->pr_parent == NULL", __func__)); + pr_p = pr->pr_parent; + pr->pr_hardening.hf_pax_aslr_compat_status = + pr_p->pr_hardening.hf_pax_aslr_compat_status; + pr->pr_hardening.hf_pax_aslr_compat_mmap_len = + pr_p->pr_hardening.hf_pax_aslr_compat_mmap_len; + pr->pr_hardening.hf_pax_aslr_compat_stack_len = + pr_p->pr_hardening.hf_pax_aslr_compat_stack_len; + pr->pr_hardening.hf_pax_aslr_compat_exec_len = + pr_p->pr_hardening.hf_pax_aslr_compat_exec_len; + } +} +#endif /* COMPAT_FREEBSD32 */ + +void +pax_aslr_mmap(struct proc *p, vm_offset_t *addr, vm_offset_t orig_addr, int flags) +{ + + if (!pax_aslr_active(p)) + return; + 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) { + int len_32bit; + +#ifdef COMPAT_FREEBSD32 + len_32bit = pax_aslr_compat_mmap_len; +#else + len_32bit = PAX_ASLR_COMPAT_DELTA_MMAP_MIN_LEN; +#endif + *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 proc *p, uintptr_t *addr) +{ + uintptr_t orig_addr; + + if (!pax_aslr_active(p)) + return; + orig_addr = *addr; + *addr -= p->p_vmspace->vm_aslr_delta_stack; + CTR3(KTR_PAX, "%s: orig_addr=%p, new_addr=%p\n", + __func__, (void *)orig_addr, (void *)*addr); +} + +void +pax_aslr_stack_fixup(struct proc *p) +{ + + if (!pax_aslr_active(p)) + return; + p->p_vmspace->vm_maxsaddr -= p->p_vmspace->vm_aslr_delta_stack; +} + +void +pax_aslr_execbase(struct proc *p, u_long *et_dyn_addrp) +{ + + if (!pax_aslr_active(p)) + return; + *et_dyn_addrp += p->p_vmspace->vm_aslr_delta_exec; +} + +uint32_t +pax_aslr_setup_flags(struct image_params *imgp, uint32_t mode) +{ + struct prison *pr; + uint32_t flags, status; + + flags = 0; + status = 0; + pr = pax_get_prison(imgp->proc); + status = pr->pr_hardening.hf_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 & PAX_NOTE_ASLR) { + 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 & PAX_NOTE_NOASLR) { + flags &= ~PAX_NOTE_ASLR; + flags |= PAX_NOTE_NOASLR; + } else { + flags |= PAX_NOTE_ASLR; + flags &= ~PAX_NOTE_NOASLR; + } + return (flags); + } + + /* + * flags is in an unknown state, so force ASLR. + */ + flags |= PAX_NOTE_ASLR; + flags &= ~PAX_NOTE_NOASLR; + return (flags); +} + Index: sys/kern/kern_thr.c =================================================================== --- sys/kern/kern_thr.c +++ sys/kern/kern_thr.c @@ -254,6 +254,7 @@ td->td_proc->p_flag |= P_HADTHREADS; thread_link(newtd, p); bcopy(p->p_comm, newtd->td_name, sizeof(newtd->td_name)); + newtd->td_pax = p->p_pax; thread_lock(td); /* let the scheduler know about these things. */ sched_fork_thread(td, newtd); Index: sys/kern/sys_process.c =================================================================== --- sys/kern/sys_process.c +++ sys/kern/sys_process.c @@ -33,6 +33,7 @@ __FBSDID("$FreeBSD$"); #include "opt_compat.h" +#include "opt_pax.h" #include #include @@ -41,6 +42,7 @@ #include #include #include +#include #include #include #include @@ -651,6 +653,7 @@ /* Lock proctree before locking the process. */ switch (req) { + case PT_PAX: case PT_TRACE_ME: case PT_ATTACH: case PT_STEP: @@ -668,7 +671,7 @@ } write = 0; - if (req == PT_TRACE_ME) { + if (req == PT_TRACE_ME || req == PT_PAX) { p = td->td_proc; PROC_LOCK(p); } else { @@ -735,6 +738,16 @@ * Permissions check */ switch (req) { + case PT_PAX: + /* securelevel must be 0 to allow this */ + if ((data & PAX_NOTE_NOASLR) == PAX_NOTE_NOASLR) { + if (securelevel_gt(p->p_ucred, 0) != 0) { + error = EPERM; + goto fail; + } + } + break; + case PT_TRACE_ME: /* Always legal. */ break; @@ -820,6 +833,9 @@ td->td_retval[0] = 0; switch (req) { + case PT_PAX: + p->p_paxdebug = data; + break; case PT_TRACE_ME: /* set my trace flag and "owner" so it can read/write me */ p->p_flag |= P_TRACED; 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,7 @@ .sv_fetch_syscall_args = cpu_fetch_syscall_args, .sv_syscallnames = syscallnames, .sv_schedtail = NULL, + .sv_pax_aslr_init = pax_aslr_init_vmspace, }; static Elf64_Brandinfo freebsd_brand_info = { @@ -139,6 +143,7 @@ .sv_fetch_syscall_args = cpu_fetch_syscall_args, .sv_syscallnames = syscallnames, .sv_schedtail = NULL, + .sv_pax_aslr_init = pax_aslr_init_vmspace32, }; 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,7 @@ .sv_fetch_syscall_args = cpu_fetch_syscall_args, .sv_syscallnames = freebsd32_syscallnames, .sv_schedtail = NULL, + .sv_pax_aslr_init = pax_aslr_init_vmspace32, }; 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 @@ -108,6 +111,7 @@ .sv_shared_page_base = FREEBSD32_SHAREDPAGE, .sv_shared_page_len = PAGE_SIZE, .sv_schedtail = NULL, + .sv_pax_aslr_init = pax_aslr_init_vmspace32, }; 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 @@ -84,6 +87,7 @@ .sv_shared_page_base = SHAREDPAGE, .sv_shared_page_len = PAGE_SIZE, .sv_schedtail = NULL, + .sv_pax_aslr_init = pax_aslr_init_vmspace, }; INIT_SYSENTVEC(elf64_sysvec, &elf64_freebsd_sysvec); 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,7 @@ .sv_fetch_syscall_args = cpu_fetch_syscall_args, .sv_syscallnames = syscallnames, .sv_schedtail = NULL, + .sv_pax_aslr_init = pax_aslr_init_vmspace, }; static Elf64_Brandinfo freebsd_brand_info = { Index: sys/sys/imgact.h =================================================================== --- sys/sys/imgact.h +++ sys/sys/imgact.h @@ -81,6 +81,7 @@ int pagesizeslen; vm_prot_t stack_prot; u_long stack_sz; + int pax_flags; }; #ifdef _KERNEL Index: sys/sys/jail.h =================================================================== --- sys/sys/jail.h +++ sys/sys/jail.h @@ -30,6 +30,10 @@ #ifndef _SYS_JAIL_H_ #define _SYS_JAIL_H_ +#if defined(_KERNEL) || defined(_WANT_PRISON) +#include +#endif + #ifdef _KERNEL struct jail_v0 { u_int32_t version; @@ -186,6 +190,7 @@ char pr_hostname[MAXHOSTNAMELEN]; /* (p) jail hostname */ char pr_domainname[MAXHOSTNAMELEN]; /* (p) jail domainname */ char pr_hostuuid[HOSTUUIDLEN]; /* (p) jail hostuuid */ + struct hardening_features pr_hardening; /* (p) PaX-inspired hardening features */ char pr_osrelease[OSRELEASELEN]; /* (c) kern.osrelease value */ }; 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,121 @@ +/*- + * Copyright (c) 2006 Elad Efrat + * Copyright (c) 2013-2015, by Oliver Pinter + * Copyright (c) 2014-2015, 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$ + * + * HardenedBSD-version: 2fba75c32739bd7f7c80163ec88e3655c3130753 + * HardenedBSD-version: v16 + * + */ + +#ifndef _SYS_PAX_H +#define _SYS_PAX_H + +#if defined(_KERNEL) || defined(_WANT_PRISON) +struct hardening_features { + int hf_pax_aslr_status; /* (p) PaX ASLR enabled */ + int hf_pax_aslr_mmap_len; /* (p) Number of bits randomized with mmap */ + int hf_pax_aslr_stack_len; /* (p) Number of bits randomized with stack */ + int hf_pax_aslr_exec_len; /* (p) Number of bits randomized with the execbase */ + int hf_pax_aslr_compat_status; /* (p) PaX ASLR enabled (compat32) */ + int hf_pax_aslr_compat_mmap_len; /* (p) Number of bits randomized with mmap (compat32) */ + int hf_pax_aslr_compat_stack_len; /* (p) Number of bits randomized with stack (compat32) */ + int hf_pax_aslr_compat_exec_len; /* (p) Number of bits randomized with the execbase (compat32) */ +}; +#endif + +#ifdef _KERNEL +#ifdef PAX_ASLR +struct image_params; +struct prison; +struct thread; +struct proc; +struct vnode; +struct vm_offset_t; + +/* + * Used in sysctl handlers. + */ +#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[]; + +/* + * Generic PaX functions. + */ +int pax_elf(struct image_params *, uint32_t); +void pax_get_flags(struct proc *, uint32_t *); +void pax_get_flags_td(struct thread *, uint32_t *); +struct prison *pax_get_prison(struct proc *); +struct prison *pax_get_prison_td(struct thread *); +void pax_init_prison(struct prison *); + +/* + * ASLR related functions. + */ +int pax_aslr_active(struct proc *); +void pax_aslr_execbase(struct proc *, u_long *); +void pax_aslr_init(struct image_params *); +void pax_aslr_init_prison(struct prison *); +void pax_aslr_init_prison32(struct prison *); +uint32_t pax_aslr_setup_flags(struct image_params *, uint32_t); +void pax_aslr_init_vmspace(struct proc *); +void pax_aslr_init_vmspace32(struct proc *); +void pax_aslr_mmap(struct proc *, vm_offset_t *, vm_offset_t, int); +void pax_aslr_stack(struct proc *, uintptr_t *); +void pax_aslr_stack_fixup(struct proc *); + +#else /* PAX_ASLR */ + +#define pax_aslr_init_vmspace NULL +#define pax_aslr_init_vmspace32 NULL +#define pax_aslr_init_prison(pr) do {} while (0) +#define pax_aslr_init_prison32(pr) do {} while (0) + +#endif /* PAX_ASLR */ + +/* + * Keep these values to keep compatibility with HardenedBSD + */ +#define PAX_NOTE_ASLR 0x00000040 +#define PAX_NOTE_NOASLR 0x00000080 +#define PAX_NOTE_ALL_ENABLED (PAX_NOTE_ASLR) +#define PAX_NOTE_ALL_DISABLED (PAX_NOTE_NOASLR) +#define PAX_NOTE_ALL (PAX_NOTE_ALL_ENABLED | PAX_NOTE_ALL_DISABLED) + +#endif /* _KERNEL */ +#endif /* _SYS_PAX_H */ Index: sys/sys/proc.h =================================================================== --- sys/sys/proc.h +++ sys/sys/proc.h @@ -288,6 +288,7 @@ u_char td_pri_class; /* (t) Scheduling class. */ u_char td_user_pri; /* (t) User pri from estcpu and nice. */ u_char td_base_user_pri; /* (t) Base user pri */ + uint32_t td_pax; /* (b) Cached PaX settings from process */ #define td_endcopy td_pcb /* @@ -578,6 +579,8 @@ pid_t p_reapsubtree; /* (e) Pid of the direct child of the reaper which spawned our subtree. */ + u_int p_pax; /* (b) PaX is enabled to this process */ + u_int p_paxdebug; /* (b) PaX flags set via PTrace */ /* End area that is copied on creation. */ #define p_endcopy p_xstat Index: sys/sys/ptrace.h =================================================================== --- sys/sys/ptrace.h +++ sys/sys/ptrace.h @@ -76,6 +76,7 @@ #define PT_VM_ENTRY 41 /* Get VM map (entry) */ #define PT_FIRSTMACH 64 /* for machine-specific requests */ +#define PT_PAX 65 /* Toggle PaX-inspired hardening features */ #include /* machine-specific requests, if any */ struct ptrace_io_desc { 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 *); @@ -136,6 +137,7 @@ uint32_t sv_timekeep_gen; void *sv_shared_page_obj; void (*sv_schedtail)(struct thread *); + void (*sv_pax_aslr_init)(struct proc *); }; #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_offset_t vm_aslr_delta_mmap; /* mmap() random delta for ASLR */ + vm_offset_t vm_aslr_delta_stack; /* stack random delta for ASLR */ + vm_offset_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); } @@ -3260,6 +3268,11 @@ vm2->vm_taddr = vm1->vm_taddr; vm2->vm_daddr = vm1->vm_daddr; vm2->vm_maxsaddr = vm1->vm_maxsaddr; +#ifdef PAX_ASLR + vm2->vm_aslr_delta_exec = vm1->vm_aslr_delta_exec; + vm2->vm_aslr_delta_mmap = vm1->vm_aslr_delta_mmap; + vm2->vm_aslr_delta_stack = vm1->vm_aslr_delta_stack; +#endif vm_map_lock(old_map); if (old_map->busy) vm_map_wait_busy(old_map); 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 "opt_vm.h" #include @@ -55,6 +56,7 @@ #include #include #include +#include #include #include #include @@ -440,6 +442,9 @@ td->td_fpop = fp; maxprot &= cap_maxprot; +#ifdef PAX_ASLR + pax_aslr_mmap(td->td_proc, &addr, (vm_offset_t)uap->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);