HBSD OPNsense: Separate out the ASLR code.

On OPNsense's 16.7 roadmap is HardenedBSD's ASLR code. This commit
separates out the ASLR code from the rest of our exploit mitigation
and system hardening code.

Testing and verification still need to be performed. Initial testing
(compile + boot + `procstat -v PIDofPIEapplication) has been
performed. More thorough testing should occur.

Shared object load order randomization in the RTLD is not included in
this patch. That will be discussed with the fine folks at OPNsense at
a later time.

Since OPNsense is based on FreeBSD 10.x, this patch will need to be
backported to 10-STABLE. However, a "horizontal port" to 11-CURRENT,
which is what this commit is, needed to be done first.

Signed-off-by:	Shawn Webb <shawn.webb@hardenedbsd.org>
This commit is contained in:
Shawn Webb 2016-03-21 21:02:14 -04:00 committed by Franco Fichtner
parent e0977fd0da
commit e13c0d42eb
55 changed files with 2259 additions and 82 deletions

View file

@ -26,12 +26,15 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include "opt_pax.h"
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/systm.h>
#include <sys/exec.h>
#include <sys/imgact.h>
#include <sys/linker.h>
#include <sys/pax.h>
#include <sys/proc.h>
#include <sys/sysent.h>
#include <sys/imgact_elf.h>
@ -82,6 +85,7 @@ struct sysentvec elf64_freebsd_sysvec = {
.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);

View file

@ -425,7 +425,7 @@ sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
}
regs->tf_rsp = (long)sfp;
regs->tf_rip = p->p_sysent->sv_sigcode_base;
regs->tf_rip = p->p_sigcode_base;
regs->tf_rflags &= ~(PSL_T | PSL_D);
regs->tf_cs = _ucodesel;
regs->tf_ds = _udatasel;

View file

@ -364,3 +364,6 @@ device xenpci # Xen HVM Hypervisor services driver
# VMware support
device vmx # VMware VMXNET3 Ethernet
options PAX
options PAX_ASLR

View file

@ -419,7 +419,7 @@ ia32_osendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
}
regs->tf_rsp = (uintptr_t)fp;
regs->tf_rip = p->p_sysent->sv_psstrings - sz_ia32_osigcode;
regs->tf_rip = p->p_ps_strings - sz_ia32_osigcode;
regs->tf_rflags &= ~(PSL_T | PSL_D);
regs->tf_cs = _ucode32sel;
regs->tf_ds = _udatasel;
@ -534,7 +534,7 @@ freebsd4_ia32_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
}
regs->tf_rsp = (uintptr_t)sfp;
regs->tf_rip = p->p_sysent->sv_sigcode_base + sz_ia32_sigcode -
regs->tf_rip = p->p_sigcode_base + sz_ia32_sigcode -
sz_freebsd4_ia32_sigcode;
regs->tf_rflags &= ~(PSL_T | PSL_D);
regs->tf_cs = _ucode32sel;
@ -682,7 +682,7 @@ ia32_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
}
regs->tf_rsp = (uintptr_t)sfp;
regs->tf_rip = p->p_sysent->sv_sigcode_base;
regs->tf_rip = p->p_sigcode_base;
regs->tf_rflags &= ~(PSL_T | PSL_D);
regs->tf_cs = _ucode32sel;
regs->tf_ss = _udatasel;

View file

@ -230,7 +230,7 @@ setup_lcall_gate(void)
bzero(&uap, sizeof(uap));
uap.start = 0;
uap.num = 1;
lcall_addr = curproc->p_sysent->sv_psstrings - sz_lcall_tramp;
lcall_addr = curproc->p_psstrings - sz_lcall_tramp;
bzero(&desc, sizeof(desc));
desc.sd_type = SDT_MEMERA;
desc.sd_dpl = SEL_UPL;

View file

@ -63,7 +63,7 @@
#define DFLSSIZ (8UL*1024*1024) /* initial stack size limit */
#endif
#ifndef MAXSSIZ
#define MAXSSIZ (512UL*1024*1024) /* max stack size */
#define MAXSSIZ (1UL*1024*1024*1024) /* max stack size */
#endif
#ifndef SGROWSIZ
#define SGROWSIZ (128UL*1024) /* amount to grow stack */
@ -178,10 +178,11 @@
#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)
#define VM_MIN_ADDRESS (65536)
#define PHYS_TO_DMAP(x) ((x) | DMAP_MIN_ADDRESS)
#define DMAP_TO_PHYS(x) ((x) & ~DMAP_MIN_ADDRESS)

View file

@ -635,7 +635,7 @@ linux_mmap_common(struct thread *td, l_uintptr_t addr, l_size_t len, l_int prot,
* mmap's return value.
*/
PROC_LOCK(p);
p->p_vmspace->vm_maxsaddr = (char *)LINUX32_USRSTACK -
p->p_vmspace->vm_maxsaddr = (char *)p->p_usrstack -
lim_cur(p, RLIMIT_STACK);
PROC_UNLOCK(p);
}

View file

@ -33,6 +33,7 @@
#include <sys/cdefs.h>
__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 @@ __FBSDID("$FreeBSD$");
#include <sys/malloc.h>
#include <sys/module.h>
#include <sys/mutex.h>
#include <sys/pax.h>
#include <sys/proc.h>
#include <sys/resourcevar.h>
#include <sys/signalvar.h>
@ -250,11 +252,11 @@ elf_linux_fixup(register_t **stack_base, struct image_params *imgp)
struct linux32_ps_strings *arginfo;
int issetugid;
arginfo = (struct linux32_ps_strings *)LINUX32_PS_STRINGS;
uplatform = (Elf32_Addr *)((caddr_t)arginfo - linux_szplatform);
KASSERT(curthread->td_proc == imgp->proc,
("unsafe elf_linux_fixup(), should be curproc"));
arginfo = (struct linux32_ps_strings *)imgp->proc->p_psstrings;
uplatform = (Elf32_Addr *)((caddr_t)arginfo - linux_szplatform);
base = (Elf32_Addr *)*stack_base;
args = (Elf32_Auxargs *)imgp->auxargs;
pos = base + (imgp->args->argc + imgp->args->envc + 2);
@ -869,7 +871,7 @@ linux_copyout_strings(struct image_params *imgp)
* Calculate string base and vector table pointers.
* Also deal with signal trampoline code for this exec type.
*/
arginfo = (struct linux32_ps_strings *)LINUX32_PS_STRINGS;
arginfo = (struct linux32_ps_strings *)imgp->proc->p_psstrings;
destp = (caddr_t)arginfo - SPARE_USRSPACE - linux_szplatform -
roundup((ARG_MAX - imgp->args->stringspace),
sizeof(char *));
@ -1039,6 +1041,7 @@ struct sysentvec elf_linux_sysvec = {
.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);

View file

@ -26,6 +26,8 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include "opt_pax.h"
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/systm.h>
@ -34,6 +36,7 @@ __FBSDID("$FreeBSD$");
#include <sys/linker.h>
#include <sys/sysent.h>
#include <sys/imgact_elf.h>
#include <sys/pax.h>
#include <sys/proc.h>
#include <sys/syscall.h>
#include <sys/signalvar.h>
@ -79,6 +82,7 @@ struct sysentvec elf32_freebsd_sysvec = {
.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 = {

View file

@ -44,6 +44,7 @@
#include "opt_compat.h"
#include "opt_ddb.h"
#include "opt_pax.h"
#include "opt_platform.h"
#include "opt_sched.h"
#include "opt_timer.h"
@ -69,6 +70,7 @@ __FBSDID("$FreeBSD$");
#include <sys/malloc.h>
#include <sys/msgbuf.h>
#include <sys/mutex.h>
#include <sys/pax.h>
#include <sys/pcpu.h>
#include <sys/ptrace.h>
#include <sys/rwlock.h>
@ -278,7 +280,7 @@ sendsig(catcher, ksi, mask)
tf->tf_r5 = (register_t)&fp->sf_uc;
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));
tf->tf_usr_lr = (register_t)(p->p_psstrings - *(p->p_sysent->sv_szsigcode));
CTR3(KTR_SIG, "sendsig: return td=%p pc=%#x sp=%#x", td, tf->tf_usr_lr,
tf->tf_usr_sp);

View file

@ -30,6 +30,7 @@ __FBSDID("$FreeBSD$");
#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 @@ __FBSDID("$FreeBSD$");
#include <sys/mount.h>
#include <sys/mutex.h>
#include <sys/namei.h>
#include <sys/pax.h>
#include <sys/proc.h>
#include <sys/procctl.h>
#include <sys/reboot.h>
@ -2865,12 +2867,16 @@ freebsd32_copyout_strings(struct image_params *imgp)
execpath_len = strlen(imgp->execpath) + 1;
else
execpath_len = 0;
arginfo = (struct freebsd32_ps_strings *)curproc->p_sysent->
sv_psstrings;
if (imgp->proc->p_sysent->sv_sigcode_base == 0)
arginfo = (struct freebsd32_ps_strings *)curproc->p_psstrings;
imgp->proc->p_sigcode_base = imgp->proc->p_sysent->sv_sigcode_base;
if (imgp->proc->p_sigcode_base == 0)
szsigcode = *(imgp->proc->p_sysent->sv_szsigcode);
else
else {
szsigcode = 0;
#ifdef PAX_ASLR
pax_aslr_vdso(imgp->proc, &(imgp->proc->p_sigcode_base));
#endif
}
destp = (uintptr_t)arginfo;
/*

View file

@ -29,6 +29,7 @@
__FBSDID("$FreeBSD$");
#include "opt_compat.h"
#include "opt_pax.h"
#define __ELF_WORD_SIZE 32
@ -42,6 +43,7 @@ __FBSDID("$FreeBSD$");
#include <sys/mutex.h>
#include <sys/mman.h>
#include <sys/namei.h>
#include <sys/pax.h>
#include <sys/pioctl.h>
#include <sys/proc.h>
#include <sys/procfs.h>
@ -139,6 +141,7 @@ struct sysentvec ia32_freebsd_sysvec = {
.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);

View file

@ -2993,3 +2993,8 @@ options RANDOM_RWFILE # Read and write entropy cache
# Intel em(4) driver
options EM_MULTIQUEUE # Activate multiqueue features/disable MSI-X
# PAX and HardenedBSD related knobs
options PAX
options PAX_ASLR
options PAX_SYSCTLS

View file

@ -2957,6 +2957,10 @@ gnu/fs/reiserfs/reiserfs_stree.c optional reiserfs
gnu/fs/reiserfs/reiserfs_vfsops.c optional reiserfs
gnu/fs/reiserfs/reiserfs_vnops.c optional reiserfs
#
hardenedbsd/hbsd_pax_common.c optional pax
hardenedbsd/hbsd_pax_log.c optional pax
hardenedbsd/hbsd_pax_aslr.c optional pax pax_aslr
#
isa/isa_if.m standard
isa/isa_common.c optional isa
isa/isahint.c optional isa

View file

@ -930,6 +930,21 @@ RACCT_DEFAULT_TO_DISABLED opt_global.h
# Resource Limits
RCTL opt_global.h
# PaX-inspired hardening features
PAX opt_pax.h
PAX_ASLR opt_pax.h
PAX_SYSCTLS opt_pax.h
# ASLR overwritable defaults
PAX_ASLR_DELTA_MMAP_DEF_LEN opt_pax.h
PAX_ASLR_DELTA_STACK_DEF_LEN opt_pax.h
PAX_ASLR_DELTA_VDSO_DEF_LEN opt_pax.h
PAX_ASLR_DELTA_EXEC_DEF_LEN opt_pax.h
PAX_ASLR_COMPAT_DELTA_MMAP_DEF_LEN opt_pax.h
PAX_ASLR_COMPAT_DELTA_STACK_DEF_LEN opt_pax.h
PAX_ASLR_COMPAT_DELTA_EXEC_DEF_LEN opt_pax.h
PAX_ASLR_COMPAT_DELTA_VDSO_DEF_LEN opt_pax.h
# Random number generator(s)
RANDOM_YARROW opt_random.h
RANDOM_FORTUNA opt_random.h

View file

@ -71,3 +71,9 @@ HYPERV opt_global.h
# options for the Intel C600 SAS driver (isci)
ISCI_LOGGING opt_isci.h
# HardenedBSD ASLR options
PAX_ASLR_DELTA_MAP32BIT_DEF_LEN opt_pax.h
PAX_ASLR_DELTA_MAP32BIT_MIN_LEN opt_pax.h
PAX_ASLR_DELTA_MAP32BIT_MAX_LEN opt_pax.h
PAX_ASLR_DELTA_MAP32BIT_LSB opt_pax.h

View file

@ -29,3 +29,9 @@ SCHIZO_DEBUG opt_schizo.h
SUNKBD_DFLT_KEYMAP opt_sunkbd.h
SUNKBD_EMULATE_ATKBD opt_sunkbd.h
# HardenedBSD ASLR options
PAX_ASLR_DELTA_MAP32BIT_DEF_LEN opt_pax.h
PAX_ASLR_DELTA_MAP32BIT_MIN_LEN opt_pax.h
PAX_ASLR_DELTA_MAP32BIT_MAX_LEN opt_pax.h
PAX_ASLR_DELTA_MAP32BIT_LSB opt_pax.h

View file

@ -30,10 +30,13 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include "opt_pax.h"
#include <sys/param.h>
#include <sys/cons.h>
#include <sys/jail.h>
#include <sys/kdb.h>
#include <sys/pax.h>
#include <sys/proc.h>
#include <sys/sysent.h>
#include <sys/systm.h>
@ -316,6 +319,9 @@ DB_SHOW_COMMAND(thread, db_show_thread)
(void *)(td->td_kstack + td->td_kstack_pages * PAGE_SIZE - 1));
db_printf(" flags: %#x ", td->td_flags);
db_printf(" pflags: %#x\n", td->td_pflags);
#ifdef PAX
pax_db_printf_flags_td(td, PAX_LOG_DEFAULT);
#endif
db_printf(" state: ");
switch (td->td_state) {
case TDS_INACTIVE:
@ -423,6 +429,9 @@ DB_SHOW_COMMAND(proc, db_show_proc)
if (p->p_args != NULL)
db_printf(" arguments: %.*s\n", (int)p->p_args->ar_length,
p->p_args->ar_args);
#ifdef PAX
pax_db_printf_flags(p, PAX_LOG_DEFAULT);
#endif
db_printf(" threads: %d\n", p->p_numthreads);
FOREACH_THREAD_IN_PROC(p, td) {
dumpthread(p, td, 1);

View file

@ -0,0 +1,858 @@
/*-
* Copyright (c) 2006 Elad Efrat <elad@NetBSD.org>
* Copyright (c) 2013-2016, by Oliver Pinter <oliver.pinter@hardenedbsd.org>
* Copyright (c) 2014-2015, by Shawn Webb <shawn.webb@hardenedbsd.org>
* 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 <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include "opt_compat.h"
#include "opt_pax.h"
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/elf_common.h>
#include <sys/exec.h>
#include <sys/imgact.h>
#include <sys/imgact_elf.h>
#include <sys/jail.h>
#include <sys/ktr.h>
#include <sys/libkern.h>
#include <sys/mman.h>
#include <sys/pax.h>
#include <sys/proc.h>
#include <sys/sysctl.h>
#include <sys/sysent.h>
#include <vm/pmap.h>
#include <vm/vm_map.h>
#include <vm/vm_extern.h>
#include "hbsd_pax_internal.h"
#ifndef PAX_ASLR_DELTA
#define PAX_ASLR_DELTA(delta, lsb, len) \
(((delta) & ((1UL << (len)) - 1)) << (lsb))
#endif /* PAX_ASLR_DELTA */
/*-
* generic ASLR values
*
* | 32 bit | 64 bit | compat |
* +-------+--------+--------+--------+
* | MMAP | 14 bit | 30 bit | 14 bit |
* +-------+--------+--------+--------+
* | STACK | 10 bit | 42 bit | 10 bit |
* +-------+--------+--------+--------+
* | EXEC | 14 bit | 30 bit | 14 bit |
* +-------+--------+--------+--------+
* | VDSO | 10 bit | 28 bit | 10 bit |
* +-------+--------+--------+--------+
* | M32B | N.A. | 18 bit | N.A. |
* +-------+--------+--------+--------+
*
*/
#ifndef PAX_ASLR_DELTA_MMAP_LSB
#define PAX_ASLR_DELTA_MMAP_LSB PAGE_SHIFT
#endif /* PAX_ASLR_DELTA_MMAP_LSB */
#ifndef PAX_ASLR_DELTA_STACK_LSB
#define PAX_ASLR_DELTA_STACK_LSB PAGE_SHIFT
#endif /* PAX_ASLR_DELTA_STACK_LSB */
#ifndef PAX_ASLR_DELTA_STACK_WITH_GAP_LSB
#define PAX_ASLR_DELTA_STACK_WITH_GAP_LSB 3
#endif /* PAX_ASLR_DELTA_STACK_WITH_GAP_LSB */
#ifndef PAX_ASLR_DELTA_EXEC_LSB
#define PAX_ASLR_DELTA_EXEC_LSB PAGE_SHIFT
#endif /* PAX_ASLR_DELTA_EXEC_LSB */
#ifndef PAX_ASLR_DELTA_VDSO_LSB
#define PAX_ASLR_DELTA_VDSO_LSB PAGE_SHIFT
#endif /* PAX_ASLR_DELTA_VDSO_LSB */
#ifdef MAP_32BIT
#ifndef PAX_ASLR_DELTA_MAP32BIT_LSB
#define PAX_ASLR_DELTA_MAP32BIT_LSB PAGE_SHIFT
#endif /* PAX_ASLR_DELTA_MAP32BIT_LSB */
#endif /* MAP_32BIT */
/*
* ASLR default values for native host
*/
#ifdef __LP64__
#ifndef PAX_ASLR_DELTA_MMAP_DEF_LEN
#define PAX_ASLR_DELTA_MMAP_DEF_LEN 30
#endif /* PAX_ASLR_DELTA_MMAP_DEF_LEN */
#ifndef PAX_ASLR_DELTA_STACK_DEF_LEN
#define PAX_ASLR_DELTA_STACK_DEF_LEN 42
#endif /* PAX_ASLR_DELTA_STACK_DEF_LEN */
#ifndef PAX_ASLR_DELTA_EXEC_DEF_LEN
#define PAX_ASLR_DELTA_EXEC_DEF_LEN 30
#endif /* PAX_ASLR_DELTA_EXEC_DEF_LEN */
#ifndef PAX_ASLR_DELTA_VDSO_DEF_LEN
#define PAX_ASLR_DELTA_VDSO_DEF_LEN 28
#endif /* PAX_ASLR_DELTA_VDSO_DEF_LEN */
#ifdef MAP_32BIT
#ifndef PAX_ASLR_DELTA_MAP32BIT_DEF_LEN
#define PAX_ASLR_DELTA_MAP32BIT_DEF_LEN 18
#endif /* PAX_ASLR_DELTA_MAP32BIT_DEF_LEN */
#endif /* MAP_32BIT */
#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 10
#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 */
#ifndef PAX_ASLR_DELTA_VDSO_DEF_LEN
#define PAX_ASLR_DELTA_VDSO_DEF_LEN 10
#endif /* PAX_ASLR_DELTA_VDSO_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_STACK_LSB
#define PAX_ASLR_COMPAT_DELTA_STACK_LSB 3
#endif /* PAX_ASLR_COMPAT_DELTA_STACK_LSB */
#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_VDSO_LSB
#define PAX_ASLR_COMPAT_DELTA_VDSO_LSB PAGE_SHIFT
#endif /* PAX_ASLR_COMPAT_DELTA_VDSO_LSB */
#ifndef PAX_ASLR_COMPAT_DELTA_MMAP_DEF_LEN
#define PAX_ASLR_COMPAT_DELTA_MMAP_DEF_LEN 14
#endif /* PAX_ASLR_COMPAT_DELTA_MMAP_DEF_LEN */
#ifndef PAX_ASLR_COMPAT_DELTA_STACK_DEF_LEN
#define PAX_ASLR_COMPAT_DELTA_STACK_DEF_LEN 10
#endif /* PAX_ASLR_COMPAT_DELTA_STACK_DEF_LEN */
#ifndef PAX_ASLR_COMPAT_DELTA_EXEC_DEF_LEN
#define PAX_ASLR_COMPAT_DELTA_EXEC_DEF_LEN 14
#endif /* PAX_ASLR_COMPAT_DELTA_EXEC_DEF_LEN */
#ifndef PAX_ASLR_COMPAT_DELTA_VDSO_DEF_LEN
#define PAX_ASLR_COMPAT_DELTA_VDSO_DEF_LEN 10
#endif /* PAX_ASLR_COMPAT_DELTA_VDSO_DEF_LEN */
#endif
FEATURE(hbsd_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;
static int pax_aslr_vdso_len = PAX_ASLR_DELTA_VDSO_DEF_LEN;
#ifdef MAP_32BIT
static int pax_aslr_map32bit_len = PAX_ASLR_DELTA_MAP32BIT_DEF_LEN;
#ifdef PAX_HARDENING
static int pax_disallow_map32bit_status_global = PAX_FEATURE_OPTOUT;
#else
static int pax_disallow_map32bit_status_global = PAX_FEATURE_OPTIN;
#endif
#endif
#ifdef COMPAT_FREEBSD32
static int pax_aslr_compat_status = PAX_FEATURE_OPTOUT;
static int pax_aslr_compat_mmap_len = PAX_ASLR_COMPAT_DELTA_MMAP_DEF_LEN;
static int pax_aslr_compat_stack_len = PAX_ASLR_COMPAT_DELTA_STACK_DEF_LEN;
static int pax_aslr_compat_exec_len = PAX_ASLR_COMPAT_DELTA_EXEC_DEF_LEN;
static int pax_aslr_compat_vdso_len = PAX_ASLR_COMPAT_DELTA_VDSO_DEF_LEN;
#endif /* COMPAT_FREEBSD32 */
TUNABLE_INT("hardening.pax.aslr.status", &pax_aslr_status);
TUNABLE_INT("hardening.pax.aslr.mmap_len", &pax_aslr_mmap_len);
TUNABLE_INT("hardening.pax.aslr.stack_len", &pax_aslr_stack_len);
TUNABLE_INT("hardening.pax.aslr.exec_len", &pax_aslr_exec_len);
TUNABLE_INT("hardening.pax.aslr.vdso_len", &pax_aslr_vdso_len);
#ifdef MAP_32BIT
TUNABLE_INT("hardening.pax.aslr.map32bit_len", &pax_aslr_map32bit_len);
TUNABLE_INT("hardening.pax.disallow_map32bit.status", &pax_disallow_map32bit_status_global);
#endif
#ifdef COMPAT_FREEBSD32
TUNABLE_INT("hardening.pax.aslr.compat.status", &pax_aslr_compat_status);
TUNABLE_INT("hardening.pax.aslr.compat.mmap_len", &pax_aslr_compat_mmap_len);
TUNABLE_INT("hardening.pax.aslr.compat.stack_len", &pax_aslr_compat_stack_len);
TUNABLE_INT("hardening.pax.aslr.compat.exec_len", &pax_aslr_compat_exec_len);
TUNABLE_INT("hardening.pax.aslr.compat.vdso_len", &pax_aslr_compat_vdso_len);
#endif
#ifdef PAX_SYSCTLS
SYSCTL_DECL(_hardening_pax);
SYSCTL_NODE(_hardening_pax, OID_AUTO, aslr, CTLFLAG_RD, 0,
"Address Space Layout Randomization.");
SYSCTL_HBSD_4STATE(pax_aslr_status, pr_hbsd.aslr.status,
_hardening_pax_aslr, status,
CTLTYPE_INT|CTLFLAG_RWTUN|CTLFLAG_PRISON|CTLFLAG_SECURE);
/* COMPAT_FREEBSD32 and linuxulator. */
#ifdef COMPAT_FREEBSD32
SYSCTL_NODE(_hardening_pax_aslr, OID_AUTO, compat, CTLFLAG_RD, 0,
"Settings for COMPAT_FREEBSD32 and linuxulator.");
SYSCTL_HBSD_4STATE(pax_aslr_compat_status, pr_hbsd.aslr.compat_status,
_hardening_pax_aslr_compat, status,
CTLTYPE_INT|CTLFLAG_RWTUN|CTLFLAG_PRISON);
#endif /* COMPAT_FREEBSD32 */
#ifdef MAP_32BIT
SYSCTL_NODE(_hardening_pax, OID_AUTO, disallow_map32bit, CTLFLAG_RD, 0,
"Disallow MAP_32BIT mode mmap(2) calls.");
SYSCTL_HBSD_4STATE(pax_disallow_map32bit_status_global, pr_hbsd.aslr.disallow_map32bit_status,
_hardening_pax_disallow_map32bit, status,
CTLTYPE_INT|CTLFLAG_RWTUN|CTLFLAG_PRISON|CTLFLAG_SECURE);
#endif /* MAP_32BIT */
#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("[HBSD 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("[HBSD ASLR] status: %s\n", pax_status_str[pax_aslr_status]);
printf("[HBSD ASLR] mmap: %d bit\n", pax_aslr_mmap_len);
printf("[HBSD ASLR] exec base: %d bit\n", pax_aslr_exec_len);
printf("[HBSD ASLR] stack: %d bit\n", pax_aslr_stack_len);
printf("[HBSD ASLR] vdso: %d bit\n", pax_aslr_vdso_len);
#ifdef MAP_32BIT
printf("[HBSD ASLR] map32bit: %d bit\n", pax_aslr_map32bit_len);
switch (pax_disallow_map32bit_status_global) {
case PAX_FEATURE_DISABLED:
case PAX_FEATURE_OPTIN:
case PAX_FEATURE_OPTOUT:
case PAX_FEATURE_FORCE_ENABLED:
break;
default:
printf("[HBSD ASLR] WARNING, invalid settings in loader.conf!"
" (hardening.pax.disallow_map32bit.status = %d)\n",
pax_disallow_map32bit_status_global);
pax_disallow_map32bit_status_global = PAX_FEATURE_FORCE_ENABLED;
}
printf("[HBSD ASLR] disallow MAP_32BIT mode mmap: %s\n",
pax_status_str[pax_disallow_map32bit_status_global]);
#endif
}
SYSINIT(pax_aslr, SI_SUB_PAX, SI_ORDER_SECOND, pax_aslr_sysinit, NULL);
bool
pax_aslr_active(struct proc *p)
{
pax_flag_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 (true);
if ((flags & PAX_NOTE_NOASLR) == PAX_NOTE_NOASLR)
return (false);
return (true);
}
void
pax_aslr_init_vmspace(struct proc *p)
{
struct vmspace *vm;
unsigned long rand_buf;
int try;
vm = p->p_vmspace;
KASSERT(vm != NULL, ("%s: vm is null", __func__));
arc4rand(&rand_buf, sizeof(rand_buf), 0);
vm->vm_aslr_delta_mmap = PAX_ASLR_DELTA(rand_buf,
PAX_ASLR_DELTA_MMAP_LSB,
pax_aslr_mmap_len);
arc4rand(&rand_buf, sizeof(rand_buf), 0);
vm->vm_aslr_delta_exec = PAX_ASLR_DELTA(rand_buf,
PAX_ASLR_DELTA_EXEC_LSB,
pax_aslr_exec_len);
try = 3;
try_again:
/*
* In stack case we generate a bigger random, which consists
* of two parts.
* The first upper part [pax_aslr_stack_len .. PAGE_SHIFT+1]
* applied to mapping, the second lower part [PAGE_SHIFT .. 3]
* applied in the mapping as gap.
*/
arc4rand(&rand_buf, sizeof(rand_buf), 0);
vm->vm_aslr_delta_stack = PAX_ASLR_DELTA(rand_buf,
PAX_ASLR_DELTA_STACK_WITH_GAP_LSB,
pax_aslr_stack_len);
vm->vm_aslr_delta_stack = ALIGN(vm->vm_aslr_delta_stack);
arc4rand(&rand_buf, sizeof(rand_buf), 0);
rand_buf = PAX_ASLR_DELTA(rand_buf,
PAX_ASLR_DELTA_VDSO_LSB,
pax_aslr_vdso_len);
/*
* Place the vdso between the stacktop and
* vm_max_user-PAGE_SIZE.
*
* In future this will change, to place them between the
* stack and heap.
*/
/*
* This check required to handle the case
* when PAGE_ALIGN(vm->vm_aslr_delta_stack) == 0.
*/
if ((vm->vm_aslr_delta_stack & (-1UL << PAX_ASLR_DELTA_VDSO_LSB)) != 0) {
if (rand_buf > vm->vm_aslr_delta_stack) {
rand_buf = rand_buf %
((unsigned long)vm->vm_aslr_delta_stack &
(-1UL << PAX_ASLR_DELTA_STACK_LSB));
rand_buf &= (-1UL << PAX_ASLR_DELTA_VDSO_LSB);
}
} else if (try > 0) {
try--;
goto try_again;
} else {
/* XXX: Instead of 0, should we place them at the end of heap? */
pax_log_aslr(p, PAX_LOG_DEFAULT, "%s check your /boot/loader.conf ...", __func__);
rand_buf = 0;
}
vm->vm_aslr_delta_vdso = rand_buf;
#ifdef MAP_32BIT
arc4rand(&rand_buf, sizeof(rand_buf), 0);
vm->vm_aslr_delta_map32bit = PAX_ASLR_DELTA(rand_buf,
PAX_ASLR_DELTA_MAP32BIT_LSB,
pax_aslr_map32bit_len);
#endif
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);
CTR2(KTR_PAX, "%s: vm_aslr_delta_vdso=%p\n",
__func__, (void *)vm->vm_aslr_delta_vdso);
#ifdef MAP_32BIT
CTR2(KTR_PAX, "%s: vm_aslr_delta_map32bit=%p\n",
__func__, (void *)vm->vm_aslr_delta_map32bit);
#endif
}
#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("[HBSD 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("[HBSD ASLR (compat)] status: %s\n", pax_status_str[pax_aslr_compat_status]);
printf("[HBSD ASLR (compat)] mmap: %d bit\n", pax_aslr_compat_mmap_len);
printf("[HBSD ASLR (compat)] exec base: %d bit\n", pax_aslr_compat_exec_len);
printf("[HBSD ASLR (compat)] stack: %d bit\n", pax_aslr_compat_stack_len);
printf("[HBSD ASLR (compat)] vdso: %d bit\n", pax_aslr_compat_vdso_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 vmspace *vm;
long rand_buf;
vm = p->p_vmspace;
KASSERT(vm != NULL, ("%s: vm is null", __func__));
arc4rand(&rand_buf, sizeof(rand_buf), 0);
vm->vm_aslr_delta_mmap = PAX_ASLR_DELTA(rand_buf,
PAX_ASLR_COMPAT_DELTA_MMAP_LSB,
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,
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,
pax_aslr_compat_exec_len);
arc4rand(&rand_buf, sizeof(rand_buf), 0);
vm->vm_aslr_delta_vdso = PAX_ASLR_DELTA(rand_buf,
PAX_ASLR_COMPAT_DELTA_VDSO_LSB,
pax_aslr_compat_vdso_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);
CTR2(KTR_PAX, "%s: vm_aslr_delta_vdso=%p\n",
__func__, (void *)vm->vm_aslr_delta_vdso);
}
#endif /* COMPAT_FREEBSD32 */
void
pax_aslr_init(struct image_params *imgp)
{
struct proc *p;
KASSERT(imgp != NULL, ("%s: imgp is null", __func__));
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_hbsd.aslr.status = pax_aslr_status;
#ifdef MAP_32BIT
pr->pr_hbsd.aslr.disallow_map32bit_status =
pax_disallow_map32bit_status_global;
#endif
} else {
KASSERT(pr->pr_parent != NULL,
("%s: pr->pr_parent == NULL", __func__));
pr_p = pr->pr_parent;
pr->pr_hbsd.aslr.status = pr_p->pr_hbsd.aslr.status;
#ifdef MAP_32BIT
pr->pr_hbsd.aslr.disallow_map32bit_status =
pr_p->pr_hbsd.aslr.disallow_map32bit_status;
#endif
}
}
#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_hbsd.aslr.compat_status = pax_aslr_compat_status;
} else {
KASSERT(pr->pr_parent != NULL,
("%s: pr->pr_parent == NULL", __func__));
pr_p = pr->pr_parent;
pr->pr_hbsd.aslr.compat_status = pr_p->pr_hbsd.aslr.compat_status;
}
}
#endif /* COMPAT_FREEBSD32 */
void
pax_aslr_mmap(struct proc *p, vm_offset_t *addr, vm_offset_t orig_addr, int mmap_flags)
{
PROC_LOCK_ASSERT(p, MA_OWNED);
#ifdef MAP_32BIT
if (((mmap_flags & MAP_32BIT) == MAP_32BIT) || !pax_aslr_active(p))
#else
if (!pax_aslr_active(p))
#endif
return;
#ifdef MAP_32BIT
KASSERT((mmap_flags & MAP_32BIT) != MAP_32BIT,
("%s: we can't handle MAP_32BIT mapping here", __func__));
#endif
KASSERT((mmap_flags & MAP_FIXED) != MAP_FIXED,
("%s: we can't randomize MAP_FIXED mapping", __func__));
/*
* From original PaX doc:
*
* PaX applies randomization (delta_mmap) to TASK_UNMAPPED_BASE in bits 12-27
* (16 bits) and ignores the hint for file mappings (unfortunately there is
* a 'feature' in linuxthreads where the thread stack mappings do not specify
* MAP_FIXED but still expect that behaviour so the hint cannot be overriden
* for anonymous mappings).
*
* https://github.com/HardenedBSD/pax-docs-mirror/blob/master/randmmap.txt#L30
*/
if ((orig_addr == 0) || !(mmap_flags & MAP_ANON)) {
CTR4(KTR_PAX, "%s: applying to %p orig_addr=%p mmap_flags=%x\n",
__func__, (void *)*addr, (void *)orig_addr, mmap_flags);
*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 mmap_flags=%x\n",
__func__, (void *)*addr, (void *)orig_addr, mmap_flags);
}
void
pax_aslr_rtld(struct proc *p, u_long *addr)
{
PROC_LOCK_ASSERT(p, MA_OWNED);
if (!pax_aslr_active(p))
return;
*addr += p->p_vmspace->vm_aslr_delta_mmap;
CTR2(KTR_PAX, "%s: result %p\n", __func__, (void *)*addr);
}
void
pax_aslr_stack(struct proc *p, vm_offset_t *addr)
{
uintptr_t orig_addr;
uintptr_t random;
if (!pax_aslr_active(p))
return;
orig_addr = *addr;
/*
* Apply the random offset to the mapping.
* This should page aligned.
*/
random = p->p_vmspace->vm_aslr_delta_stack;
random &= (-1UL << PAX_ASLR_DELTA_STACK_LSB);
*addr -= random;
CTR3(KTR_PAX, "%s: orig_addr=%p, new_addr=%p\n",
__func__, (void *)orig_addr, (void *)*addr);
}
void
pax_aslr_stack_with_gap(struct proc *p, vm_offset_t *addr)
{
uintptr_t orig_addr;
uintptr_t random;
if (!pax_aslr_active(p))
return;
orig_addr = *addr;
/*
* Apply the random gap offset withing the page.
*/
random = p->p_vmspace->vm_aslr_delta_stack;
*addr -= random;
CTR3(KTR_PAX, "%s: orig_addr=%p, new_addr=%p\n",
__func__, (void *)orig_addr, (void *)*addr);
}
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;
}
void
pax_aslr_vdso(struct proc *p, vm_offset_t *addr)
{
uintptr_t orig_addr;
if (!pax_aslr_active(p))
return;
orig_addr = *addr;
*addr -= p->p_vmspace->vm_aslr_delta_vdso;
CTR3(KTR_PAX, "%s: orig_addr=%p, new_addr=%p\n",
__func__, (void *)orig_addr, (void *)*addr);
}
pax_flag_t
pax_aslr_setup_flags(struct image_params *imgp, struct thread *td, pax_flag_t mode)
{
struct prison *pr;
pax_flag_t flags;
uint32_t status;
KASSERT(imgp->proc == td->td_proc,
("%s: imgp->proc != td->td_proc", __func__));
flags = 0;
status = 0;
pr = pax_get_prison_td(td);
status = pr->pr_hbsd.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);
}
/*
* Unknown status, force ASLR.
*/
flags |= PAX_NOTE_ASLR;
flags &= ~PAX_NOTE_NOASLR;
return (flags);
}
#ifdef MAP_32BIT
void
pax_aslr_mmap_map_32bit(struct proc *p, vm_offset_t *addr, vm_offset_t orig_addr, int mmap_flags)
{
PROC_LOCK_ASSERT(p, MA_OWNED);
if (((mmap_flags & MAP_32BIT) != MAP_32BIT) || !pax_aslr_active(p))
return;
KASSERT((mmap_flags & MAP_32BIT) == MAP_32BIT,
("%s: we can't handle not MAP_32BIT mapping here", __func__));
KASSERT((mmap_flags & MAP_FIXED) != MAP_FIXED,
("%s: we can't randomize MAP_FIXED mapping", __func__));
/*
* From original PaX doc:
*
* PaX applies randomization (delta_mmap) to TASK_UNMAPPED_BASE in bits 12-27
* (16 bits) and ignores the hint for file mappings (unfortunately there is
* a 'feature' in linuxthreads where the thread stack mappings do not specify
* MAP_FIXED but still expect that behaviour so the hint cannot be overriden
* for anonymous mappings).
*
* https://github.com/HardenedBSD/pax-docs-mirror/blob/master/randmmap.txt#L30
*/
if ((orig_addr == 0) || !(mmap_flags & MAP_ANON)) {
CTR4(KTR_PAX, "%s: applying to %p orig_addr=%p mmap_flags=%x\n",
__func__, (void *)*addr, (void *)orig_addr, mmap_flags);
*addr += p->p_vmspace->vm_aslr_delta_map32bit;
CTR2(KTR_PAX, "%s: result %p\n", __func__, (void *)*addr);
}
}
bool
pax_disallow_map32bit_active(struct thread *td, int mmap_flags)
{
pax_flag_t flags;
if ((mmap_flags & MAP_32BIT) != MAP_32BIT)
/*
* Fast path, the mmap request does not
* contains MAP_32BIT flag.
*/
return (false);
pax_get_flags_td(td, &flags);
CTR3(KTR_PAX, "%S: pid = %d p_pax = %x",
__func__, td->td_proc->p_pid, flags);
if ((flags & PAX_NOTE_DISALLOWMAP32BIT) == PAX_NOTE_DISALLOWMAP32BIT)
return (true);
if ((flags & PAX_NOTE_NODISALLOWMAP32BIT) == PAX_NOTE_NODISALLOWMAP32BIT)
return (false);
return (true);
}
pax_flag_t
pax_disallow_map32bit_setup_flags(struct image_params *imgp, struct thread *td, pax_flag_t mode)
{
struct prison *pr;
pax_flag_t flags;
uint32_t status;
KASSERT(imgp->proc == td->td_proc,
("%s: imgp->proc != td->td_proc", __func__));
flags = 0;
status = 0;
pr = pax_get_prison_td(td);
status = pr->pr_hbsd.aslr.disallow_map32bit_status;
if (status == PAX_FEATURE_DISABLED) {
flags &= ~PAX_NOTE_DISALLOWMAP32BIT;
flags |= PAX_NOTE_NODISALLOWMAP32BIT;
return (flags);
}
if (status == PAX_FEATURE_FORCE_ENABLED) {
flags &= ~PAX_NOTE_NODISALLOWMAP32BIT;
flags |= PAX_NOTE_DISALLOWMAP32BIT;
return (flags);
}
if (status == PAX_FEATURE_OPTIN) {
if (mode & PAX_NOTE_DISALLOWMAP32BIT) {
flags |= PAX_NOTE_DISALLOWMAP32BIT;
flags &= ~PAX_NOTE_NODISALLOWMAP32BIT;
} else {
flags &= ~PAX_NOTE_DISALLOWMAP32BIT;
flags |= PAX_NOTE_NODISALLOWMAP32BIT;
}
return (flags);
}
if (status == PAX_FEATURE_OPTOUT) {
if (mode & PAX_NOTE_NODISALLOWMAP32BIT) {
flags |= PAX_NOTE_NODISALLOWMAP32BIT;
flags &= ~PAX_NOTE_DISALLOWMAP32BIT;
} else {
flags &= ~PAX_NOTE_NODISALLOWMAP32BIT;
flags |= PAX_NOTE_DISALLOWMAP32BIT;
}
return (flags);
}
/* Unknown status, force MAP32 restriction. */
flags |= PAX_NOTE_DISALLOWMAP32BIT;
flags &= ~PAX_NOTE_NODISALLOWMAP32BIT;
return (flags);
}
#endif /* MAP_32BIT */

View file

@ -0,0 +1,334 @@
/*-
* Copyright (c) 2006 Elad Efrat <elad@NetBSD.org>
* Copyright (c) 2013-2016, by Oliver Pinter <oliver.pinter@hardenedbsd.org>
* Copyright (c) 2014-2015, by Shawn Webb <shawn.webb@hardenedbsd.org>
* 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 <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include "opt_compat.h"
#include "opt_pax.h"
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/exec.h>
#include <sys/imgact.h>
#include <sys/imgact_elf.h>
#include <sys/jail.h>
#include <sys/ktr.h>
#include <sys/libkern.h>
#include <sys/mman.h>
#include <sys/pax.h>
#include <sys/proc.h>
#include <sys/stat.h>
#include <sys/sysctl.h>
#include <machine/_inttypes.h>
static void pax_set_flags(struct proc *p, struct thread *td, const pax_flag_t flags);
static void pax_set_flags_td(struct thread *td, const pax_flag_t flags);
static int pax_validate_flags(const pax_flag_t flags);
static int pax_check_conflicting_modes(const pax_flag_t mode);
CTASSERT((sizeof((struct proc *)NULL)->p_pax) == sizeof(pax_flag_t));
CTASSERT((sizeof((struct thread *)NULL)->td_pax) == sizeof(pax_flag_t));
SYSCTL_NODE(_hardening, 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",
};
const char *pax_status_simple_str[] = {
[PAX_FEATURE_SIMPLE_DISABLED] = "disabled",
[PAX_FEATURE_SIMPLE_ENABLED] = "enabled"
};
/*
* @brief Get the current process prison.
*
* @param p The current process pointer.
*
* @return prion0's address if failed or kernel process
* the actual process' prison's address else
*
*/
struct prison *
pax_get_prison(struct proc *p)
{
KASSERT(p != NULL, ("%s: p == NULL", __func__));
PROC_LOCK_ASSERT(p, MA_OWNED);
if (p->p_ucred == NULL)
return (&prison0);
return (p->p_ucred->cr_prison);
}
struct prison *
pax_get_prison_td(struct thread *td)
{
if (td == NULL || td->td_ucred == NULL)
return (&prison0);
return (td->td_ucred->cr_prison);
}
/*
* @brief Get the current PaX status from process.
*
* @param p The controlled process pointer.
* @param flags Where to write the current state.
*
* @return none
*/
void
pax_get_flags(struct proc *p, pax_flag_t *flags)
{
KASSERT(p == curthread->td_proc,
("%s: p != curthread->td_proc", __func__));
#ifdef HBSD_DEBUG
struct thread *td;
FOREACH_THREAD_IN_PROC(p, td) {
KASSERT(td->td_pax == p->p_pax, ("%s: td->td_pax != p->p_pax",
__func__));
}
#endif
*flags = p->p_pax;
}
void
pax_get_flags_td(struct thread *td, pax_flag_t *flags)
{
KASSERT(td == curthread,
("%s: td != curthread", __func__));
#ifdef HBSD_DEBUG
struct proc *p;
struct thread *td0;
p = td->td_proc;
FOREACH_THREAD_IN_PROC(p, td0) {
KASSERT(td0->td_proc == p,
("%s: td0->td_proc != p", __func__));
KASSERT(td0->td_pax == p->p_pax, ("%s: td0->td_pax != p->p_pax",
__func__));
}
#endif
*flags = td->td_pax;
}
void
pax_set_flags(struct proc *p, struct thread *td, const pax_flag_t flags)
{
struct thread *td0;
KASSERT(td == curthread,
("%s: td != curthread", __func__));
KASSERT(td->td_proc == p,
("%s: td->td_proc != p", __func__));
PROC_LOCK(p);
p->p_pax = flags;
FOREACH_THREAD_IN_PROC(p, td0) {
pax_set_flags_td(td0, flags);
}
PROC_UNLOCK(p);
}
void
pax_set_flags_td(struct thread *td, const pax_flag_t flags)
{
td->td_pax = flags;
}
/*
* rename to pax_valid_flags, and change return values and type to bool
*/
static int
pax_validate_flags(const pax_flag_t flags)
{
if ((flags & ~PAX_NOTE_ALL) != 0)
return (1);
return (0);
}
/*
* same as pax_valid_flags
*/
static int
pax_check_conflicting_modes(const pax_flag_t mode)
{
if (((mode & PAX_NOTE_ALL_ENABLED) & ((mode & PAX_NOTE_ALL_DISABLED) >> 1)) != 0)
return (1);
return (0);
}
/*
* @bried Initialize the new process PaX state
*
* @param imgp Executable image's structure.
* @param mode Requested mode.
*
* @return ENOEXEC on fail
* 0 on success
*/
int
pax_elf(struct image_params *imgp, struct thread *td, pax_flag_t mode)
{
pax_flag_t flags;
if (pax_validate_flags(mode) != 0) {
pax_log_internal_imgp(imgp, PAX_LOG_DEFAULT,
"unknown paxflags: %x", mode);
pax_ulog_internal("unknown paxflags: %x\n", mode);
return (ENOEXEC);
}
if (pax_check_conflicting_modes(mode) != 0) {
/*
* indicate flags inconsistencies in dmesg and in user terminal
*/
pax_log_internal_imgp(imgp, PAX_LOG_DEFAULT,
"inconsistent paxflags: %x", mode);
pax_ulog_internal("inconsistent paxflags: %x\n", mode);
return (ENOEXEC);
}
flags = 0;
#ifdef PAX_ASLR
flags |= pax_aslr_setup_flags(imgp, td, mode);
#ifdef MAP_32BIT
flags |= pax_disallow_map32bit_setup_flags(imgp, td, mode);
#endif
#endif
CTR3(KTR_PAX, "%s : flags = %x mode = %x",
__func__, flags, mode);
/*
* Recheck the flags after the parsing: prevent broken setups.
*/
if (pax_validate_flags(flags) != 0) {
pax_log_internal_imgp(imgp, PAX_LOG_DEFAULT,
"unknown paxflags after the setup: %x", flags);
pax_ulog_internal("unknown paxflags after the setup: %x\n", flags);
return (ENOEXEC);
}
/*
* Recheck the flags after the parsing: prevent conflicting setups.
* This check should be always false.
*/
if (pax_check_conflicting_modes(flags) != 0) {
/*
* indicate flags inconsistencies in dmesg and in user terminal
*/
pax_log_internal_imgp(imgp, PAX_LOG_DEFAULT,
"inconsistent paxflags after the setup: %x", flags);
pax_ulog_internal("inconsistent paxflags after the setup: %x\n", flags);
return (ENOEXEC);
}
pax_set_flags(imgp->proc, td, flags);
/*
* if we enable/disable features with secadm, print out a warning
*/
if (mode != 0) {
pax_log_internal_imgp(imgp, PAX_LOG_DEFAULT,
"the process has non-default settings");
}
return (0);
}
/*
* @brief Print out PaX settings on boot time, and validate some of them.
*
* @return none
*/
static void
pax_sysinit(void)
{
}
SYSINIT(pax, SI_SUB_PAX, SI_ORDER_FIRST, pax_sysinit, NULL);
/*
* @brief Initialize prison's state.
*
* The prison0 state initialized with global state.
* The child prisons state initialized with it's parent's state.
*
* @param pr Initializable prison's pointer.
*
* @return none
*/
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
}

View file

@ -0,0 +1,107 @@
/*-
* Copyright (c) 2016, by Oliver Pinter <oliver.pinter@hardenedbsd.org>
* 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 __HBSD_PAX_INTERNAL_H
#define __HBSD_PAX_INTERNAL_H
#define SYSCTL_HBSD_2STATE(g_status, pr_status, parent, name, access, desc) \
static int sysctl ## parent ## _ ## name (SYSCTL_HANDLER_ARGS); \
SYSCTL_PROC(parent, OID_AUTO, name, access, \
NULL, 0, sysctl ## parent ## _ ## name, "I", \
desc " status: " \
"0 - disabled, " \
"1 - enabled"); \
\
static int \
sysctl ## parent ## _ ## name (SYSCTL_HANDLER_ARGS) \
{ \
struct prison *pr; \
int err, val; \
\
pr = pax_get_prison_td(req->td); \
\
val = pr->pr_status; \
err = sysctl_handle_int(oidp, &val, sizeof(int), req); \
if (err || (req->newptr == NULL)) \
return (err); \
\
switch (val) { \
case PAX_FEATURE_SIMPLE_DISABLED: \
case PAX_FEATURE_SIMPLE_ENABLED: \
if (pr == &prison0) \
g_status = val; \
pr->pr_status = val; \
break; \
default: \
return (EINVAL); \
} \
\
return (0); \
}
#define SYSCTL_HBSD_4STATE(g_status, pr_status, parent, name, access) \
static int sysctl ## parent ## _ ## name (SYSCTL_HANDLER_ARGS); \
SYSCTL_PROC(parent, OID_AUTO, name, access, \
NULL, 0, sysctl ## parent ## _ ## name, "I", \
"Restrictions status: " \
"0 - disabled, " \
"1 - opt-in, " \
"2 - opt-out, " \
"3 - force enabled"); \
\
static int \
sysctl ## parent ## _ ## name (SYSCTL_HANDLER_ARGS) \
{ \
struct prison *pr; \
int err, val; \
\
pr = pax_get_prison_td(req->td); \
\
val = pr->pr_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) \
g_status = val; \
pr->pr_status = val; \
break; \
default: \
return (EINVAL); \
} \
\
return (0); \
}
#endif /* __HBSD_PAX_INTERNAL_H */

View file

@ -0,0 +1,380 @@
/*-
* Copyright (c) 2014, by Oliver Pinter <oliver.pinter@hardenedbsd.org>
* 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$
*/
#include "opt_pax.h"
#include "opt_ddb.h"
#include <sys/cdefs.h>
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/types.h>
#include <sys/kernel.h>
#include <sys/ktr.h>
#include <sys/imgact.h>
#include <sys/pax.h>
#include <sys/proc.h>
#include <sys/sbuf.h>
#include <sys/jail.h>
#include <machine/stdarg.h>
#ifdef DDB
#include <ddb/ddb.h>
#endif
#include "hbsd_pax_internal.h"
static void pax_log_log(struct proc *p, struct thread *td, pax_log_settings_t flags,
const char *prefix, const char *fmt, va_list ap);
static void pax_log_ulog(const char *prefix, const char *fmt, va_list ap);
#define PAX_LOG_FEATURES_STRING \
"\020" \
"\001PAGEEXEC" \
"\002NOPAGEEXEC" \
"\003MPROTECT" \
"\004NOMPROTECT" \
"\005SEGVGUARD" \
"\006NOSEGVGUARD" \
"\007ASLR" \
"\010NOASLR" \
"\011SHLIBRANDOM" \
"\012NOSHLIBRANDOM" \
"\013DISALLOWMAP32BIT" \
"\014NODISALLOWMAP32BIT" \
"\015<f12>" \
"\016<f13>" \
"\017<f14>" \
"\020<f15>" \
"\021<f16>" \
"\022<f17>" \
"\023<f18>" \
"\024<f19>" \
"\025<f20>" \
"\026<f21>" \
"\027<f22>" \
"\030<f23>" \
"\031<f24>" \
"\032<f25>" \
"\033<f26>" \
"\034<f27>" \
"\035<f28>" \
"\036<f29>" \
"\037<f30>" \
"\040<f31>"
#define __HARDENING_LOG_TEMPLATE(MAIN, SUBJECT, prefix, name) \
void \
prefix##_log_##name(struct proc *p, pax_log_settings_t flags, \
const char* fmt, ...) \
{ \
const char *prefix = "["#MAIN" "#SUBJECT"]"; \
va_list args; \
\
if (hardening_log_log == 0) \
return; \
\
va_start(args, fmt); \
pax_log_log(p, NULL, flags, prefix, fmt, args); \
va_end(args); \
} \
\
void \
prefix##_ulog_##name(const char* fmt, ...) \
{ \
const char *prefix = "["#MAIN" "#SUBJECT"]"; \
va_list args; \
\
if (hardening_log_ulog == 0) \
return; \
\
va_start(args, fmt); \
pax_log_ulog(prefix, fmt, args); \
va_end(args); \
}
static int hardening_log_log = PAX_FEATURE_SIMPLE_ENABLED;
static int hardening_log_ulog = PAX_FEATURE_SIMPLE_DISABLED;
TUNABLE_INT("hardening.log.log", &hardening_log_log);
TUNABLE_INT("hardening.log.ulog", &hardening_log_ulog);
#ifdef PAX_SYSCTLS
SYSCTL_NODE(_hardening, OID_AUTO, log, CTLFLAG_RD, 0,
"Hardening related logging facility.");
SYSCTL_HBSD_2STATE(hardening_log_log, pr_hbsd.log.log, _hardening_log, log,
CTLTYPE_INT|CTLFLAG_RWTUN|CTLFLAG_PRISON|CTLFLAG_SECURE,
"log to syslog ");
SYSCTL_HBSD_2STATE(hardening_log_ulog, pr_hbsd.log.ulog, _hardening_log, ulog,
CTLTYPE_INT|CTLFLAG_RWTUN|CTLFLAG_PRISON|CTLFLAG_SECURE,
"log to syslog ");
#endif
static void
hardening_log_sysinit(void)
{
switch (hardening_log_log) {
case PAX_FEATURE_SIMPLE_DISABLED:
case PAX_FEATURE_SIMPLE_ENABLED:
break;
default:
printf("[HBSD LOG] WARNING, invalid settings in loader.conf!"
" (hardening.log.log = %d)\n", hardening_log_log);
hardening_log_log = PAX_FEATURE_SIMPLE_ENABLED;
}
printf("[HBSD LOG] logging to system: %s\n",
pax_status_simple_str[hardening_log_log]);
switch (hardening_log_ulog) {
case PAX_FEATURE_SIMPLE_DISABLED:
case PAX_FEATURE_SIMPLE_ENABLED:
break;
default:
printf("[HBSD LOG] WARNING, invalid settings in loader.conf!"
" (hardening.log.ulog = %d)\n", hardening_log_ulog);
hardening_log_ulog = PAX_FEATURE_SIMPLE_ENABLED;
}
printf("[HBSD LOG] logging to user: %s\n",
pax_status_simple_str[hardening_log_ulog]);
}
SYSINIT(hardening_log, SI_SUB_PAX, SI_ORDER_SECOND, hardening_log_sysinit, NULL);
void
pax_log_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_hbsd.log.log = hardening_log_log;
pr->pr_hbsd.log.ulog = hardening_log_ulog;
} else {
KASSERT(pr->pr_parent != NULL,
("%s: pr->pr_parent == NULL", __func__));
pr_p = pr->pr_parent;
pr->pr_hbsd.log.log = pr_p->pr_hbsd.log.log;
pr->pr_hbsd.log.ulog = pr_p->pr_hbsd.log.ulog;
}
}
static void
_pax_log_prefix(struct sbuf *sb, pax_log_settings_t flags, const char *prefix)
{
sbuf_printf(sb, "%s ", prefix);
}
static void
_pax_log_indent(struct sbuf *sb, pax_log_settings_t flags)
{
if ((flags & PAX_LOG_NO_INDENT) != PAX_LOG_NO_INDENT)
sbuf_printf(sb, "\n -> ");
}
static void
_pax_log_proc_details(struct sbuf *sb, pax_log_settings_t flags, struct proc *p)
{
if (p != NULL) {
if ((flags & PAX_LOG_P_COMM) == PAX_LOG_P_COMM)
sbuf_printf(sb, "p_comm: %s ", p->p_comm);
sbuf_printf(sb, "pid: %d ", p->p_pid);
sbuf_printf(sb, "ppid: %d ", p->p_pptr->p_pid);
if ((flags & PAX_LOG_NO_P_PAX) != PAX_LOG_NO_P_PAX)
sbuf_printf(sb, "p_pax: 0x%b ", p->p_pax, PAX_LOG_FEATURES_STRING);
}
}
static void
_pax_log_thread_details(struct sbuf *sb, pax_log_settings_t flags, struct thread *td)
{
if (td != NULL) {
sbuf_printf(sb, "tid: %d ", td->td_tid);
}
}
static void
_pax_log_details_end(struct sbuf *sb)
{
sbuf_printf(sb, "\n");
}
static void
_pax_log_imgp_details(struct sbuf *sb, pax_log_settings_t flags, struct image_params *imgp)
{
if (imgp != NULL && imgp->args != NULL)
if (imgp->args->fname != NULL)
sbuf_printf(sb, "fname: %s ",
imgp->args->fname);
}
static void
pax_log_log(struct proc *p, struct thread *td, pax_log_settings_t flags,
const char *prefix, const char *fmt, va_list ap)
{
struct sbuf *sb;
sb = sbuf_new_auto();
if (sb == NULL)
panic("%s: Could not allocate memory", __func__);
_pax_log_prefix(sb, flags, prefix);
sbuf_vprintf(sb, fmt, ap);
if ((flags & PAX_LOG_SKIP_DETAILS) != PAX_LOG_SKIP_DETAILS) {
_pax_log_indent(sb, flags);
_pax_log_proc_details(sb, flags, p);
_pax_log_thread_details(sb, flags, td);
_pax_log_details_end(sb);
}
if (sbuf_finish(sb) != 0)
panic("%s: Could not generate message", __func__);
printf("%s", sbuf_data(sb));
sbuf_delete(sb);
}
static void
pax_log_ulog(const char *prefix, const char *fmt, va_list ap)
{
struct sbuf *sb;
sb = sbuf_new_auto();
if (sb == NULL)
panic("%s: Could not allocate memory", __func__);
if (prefix != NULL)
sbuf_printf(sb, "%s ", prefix);
sbuf_vprintf(sb, fmt, ap);
if (sbuf_finish(sb) != 0)
panic("%s: Could not generate message", __func__);
hbsd_uprintf("%s", sbuf_data(sb)); \
sbuf_delete(sb);
}
void
pax_printf_flags(struct proc *p, pax_log_settings_t flags)
{
if (p != NULL) {
printf("pax flags: 0x%b%c", p->p_pax, PAX_LOG_FEATURES_STRING,
((flags & PAX_LOG_NO_NEWLINE) == PAX_LOG_NO_NEWLINE) ?
' ' : '\n');
}
}
void
pax_printf_flags_td(struct thread *td, pax_log_settings_t flags)
{
if (td != NULL) {
printf("pax flags: 0x%b%c", td->td_pax, PAX_LOG_FEATURES_STRING,
((flags & PAX_LOG_NO_NEWLINE) == PAX_LOG_NO_NEWLINE) ?
' ' : '\n');
}
}
#ifdef DDB
void
pax_db_printf_flags(struct proc *p, pax_log_settings_t flags)
{
if (p != NULL) {
db_printf(" pax flags: 0x%b%c", p->p_pax, PAX_LOG_FEATURES_STRING,
((flags & PAX_LOG_NO_NEWLINE) == PAX_LOG_NO_NEWLINE) ?
' ' : '\n');
}
}
void
pax_db_printf_flags_td(struct thread *td, pax_log_settings_t flags)
{
if (td != NULL) {
db_printf(" pax flags: 0x%b%c", td->td_pax, PAX_LOG_FEATURES_STRING,
((flags & PAX_LOG_NO_NEWLINE) == PAX_LOG_NO_NEWLINE) ?
' ' : '\n');
}
}
#endif
__HARDENING_LOG_TEMPLATE(HBSD, INTERNAL, pax, internal);
__HARDENING_LOG_TEMPLATE(HBSD, ASLR, pax, aslr);
void
pax_log_internal_imgp(struct image_params *imgp, pax_log_settings_t flags, const char* fmt, ...)
{
const char *prefix = "[HBSD INTERNAL]";
struct sbuf *sb;
va_list args;
KASSERT(imgp != NULL, ("%s: imgp == NULL", __func__));
if (hardening_log_log == 0)
return;
sb = sbuf_new_auto();
if (sb == NULL)
panic("%s: Could not allocate memory", __func__);
_pax_log_prefix(sb, flags, prefix);
va_start(args, fmt);
sbuf_vprintf(sb, fmt, args);
va_end(args);
if ((flags & PAX_LOG_SKIP_DETAILS) != PAX_LOG_SKIP_DETAILS) {
_pax_log_indent(sb, flags);
_pax_log_imgp_details(sb, flags, imgp);
_pax_log_indent(sb, flags);
_pax_log_proc_details(sb, flags, imgp->proc);
_pax_log_details_end(sb);
}
if (sbuf_finish(sb) != 0)
panic("%s: Could not generate message", __func__);
printf("%s", sbuf_data(sb));
sbuf_delete(sb);
}

View file

@ -373,3 +373,6 @@ device xenpci # Xen HVM Hypervisor services driver
# VMware support
device vmx # VMware VMXNET3 Ethernet
options PAX
options PAX_ASLR

View file

@ -27,6 +27,7 @@
__FBSDID("$FreeBSD$");
#include "opt_cpu.h"
#include "opt_pax.h"
#include <sys/param.h>
#include <sys/kernel.h>
@ -34,6 +35,7 @@ __FBSDID("$FreeBSD$");
#include <sys/exec.h>
#include <sys/imgact.h>
#include <sys/linker.h>
#include <sys/pax.h>
#include <sys/proc.h>
#include <sys/sysent.h>
#include <sys/imgact_elf.h>
@ -88,6 +90,7 @@ struct sysentvec elf32_freebsd_sysvec = {
.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);

View file

@ -486,11 +486,11 @@ osendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
regs->tf_esp = (int)fp;
if (p->p_sysent->sv_sigcode_base != 0) {
regs->tf_eip = p->p_sysent->sv_sigcode_base + szsigcode -
regs->tf_eip = p->p_sigcode_base + szsigcode -
szosigcode;
} else {
/* a.out sysentvec does not use shared page */
regs->tf_eip = p->p_sysent->sv_psstrings - szosigcode;
regs->tf_eip = p->p_psstrings - szosigcode;
}
regs->tf_eflags &= ~(PSL_T | PSL_D);
regs->tf_cs = _ucodesel;
@ -618,7 +618,7 @@ freebsd4_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
}
regs->tf_esp = (int)sfp;
regs->tf_eip = p->p_sysent->sv_sigcode_base + szsigcode -
regs->tf_eip = p->p_sigcode_base + szsigcode -
szfreebsd4_sigcode;
regs->tf_eflags &= ~(PSL_T | PSL_D);
regs->tf_cs = _ucodesel;
@ -792,9 +792,9 @@ sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
}
regs->tf_esp = (int)sfp;
regs->tf_eip = p->p_sysent->sv_sigcode_base;
regs->tf_eip = p->p_sigcode_base;
if (regs->tf_eip == 0)
regs->tf_eip = p->p_sysent->sv_psstrings - szsigcode;
regs->tf_eip = p->p_psstrings - szsigcode;
regs->tf_eflags &= ~(PSL_T | PSL_D);
regs->tf_cs = _ucodesel;
regs->tf_ds = _udatasel;

View file

@ -541,7 +541,7 @@ linux_mmap_common(struct thread *td, l_uintptr_t addr, l_size_t len, l_int prot,
* mmap's return value.
*/
PROC_LOCK(p);
p->p_vmspace->vm_maxsaddr = (char *)USRSTACK -
p->p_vmspace->vm_maxsaddr = (char *)p->p_usrstack -
lim_cur(p, RLIMIT_STACK);
PROC_UNLOCK(p);
}

View file

@ -29,6 +29,8 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include "opt_pax.h"
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/exec.h>
@ -41,6 +43,7 @@ __FBSDID("$FreeBSD$");
#include <sys/malloc.h>
#include <sys/module.h>
#include <sys/mutex.h>
#include <sys/pax.h>
#include <sys/proc.h>
#include <sys/signalvar.h>
#include <sys/syscallsubr.h>
@ -250,8 +253,8 @@ elf_linux_fixup(register_t **stack_base, struct image_params *imgp)
("unsafe elf_linux_fixup(), should be curproc"));
p = imgp->proc;
arginfo = (struct ps_strings *)p->p_psstrings;
issetugid = imgp->proc->p_flag & P_SUGID ? 1 : 0;
arginfo = (struct ps_strings *)p->p_sysent->sv_psstrings;
uplatform = (Elf32_Addr *)((caddr_t)arginfo - linux_szplatform);
args = (Elf32_Auxargs *)imgp->auxargs;
pos = *stack_base + (imgp->args->argc + imgp->args->envc + 2);
@ -311,7 +314,7 @@ linux_copyout_strings(struct image_params *imgp)
* Also deal with signal trampoline code for this exec type.
*/
p = imgp->proc;
arginfo = (struct ps_strings *)p->p_sysent->sv_psstrings;
arginfo = (struct ps_strings *)p->p_psstrings;
destp = (caddr_t)arginfo - SPARE_USRSPACE - linux_szplatform -
roundup((ARG_MAX - imgp->args->stringspace), sizeof(char *));
@ -975,6 +978,7 @@ struct sysentvec linux_sysvec = {
.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);

View file

@ -33,7 +33,7 @@ __FBSDID("$FreeBSD$");
#include "opt_capsicum.h"
#include "opt_compat.h"
#include "opt_core.h"
#include "opt_pax.h"
#include <sys/param.h>
#include <sys/capsicum.h>
@ -48,6 +48,7 @@ __FBSDID("$FreeBSD$");
#include <sys/mount.h>
#include <sys/mman.h>
#include <sys/namei.h>
#include <sys/pax.h>
#include <sys/pioctl.h>
#include <sys/proc.h>
#include <sys/procfs.h>
@ -791,16 +792,7 @@ __CONCAT(exec_, __elfN(imgact))(struct image_params *imgp)
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;
@ -821,6 +813,20 @@ __CONCAT(exec_, __elfN(imgact))(struct image_params *imgp)
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);
@ -918,6 +924,9 @@ __CONCAT(exec_, __elfN(imgact))(struct image_params *imgp)
*/
addr = round_page((vm_offset_t)vmspace->vm_daddr + lim_max(imgp->proc,
RLIMIT_DATA));
#ifdef PAX_ASLR
pax_aslr_rtld(imgp->proc, &addr);
#endif
PROC_UNLOCK(imgp->proc);
imgp->entry_addr = entry;
@ -1011,7 +1020,7 @@ __elfN(freebsd_fixup)(register_t **stack_base, struct image_params *imgp)
}
if (imgp->sysent->sv_timekeep_base != 0) {
AUXARGS_ENTRY(pos, AT_TIMEKEEP,
imgp->sysent->sv_timekeep_base);
imgp->proc->p_timekeep_base);
}
AUXARGS_ENTRY(pos, AT_STACKPROT, imgp->sysent->sv_shared_page_obj
!= NULL && imgp->stack_prot != 0 ? imgp->stack_prot :
@ -1979,9 +1988,9 @@ __elfN(note_procstat_psstrings)(void *arg, struct sbuf *sb, size_t *sizep)
KASSERT(*sizep == size, ("invalid size"));
structsize = sizeof(ps_strings);
#if defined(COMPAT_FREEBSD32) && __ELF_WORD_SIZE == 32
ps_strings = PTROUT(p->p_sysent->sv_psstrings);
ps_strings = PTROUT(p->p_psstrings);
#else
ps_strings = p->p_sysent->sv_psstrings;
ps_strings = p->p_psstrings;
#endif
sbuf_bcat(sb, &structsize, sizeof(structsize));
sbuf_bcat(sb, &ps_strings, sizeof(ps_strings));

View file

@ -46,6 +46,7 @@ __FBSDID("$FreeBSD$");
#include "opt_ddb.h"
#include "opt_init_path.h"
#include "opt_pax.h"
#include <sys/param.h>
#include <sys/kernel.h>
@ -60,6 +61,7 @@ __FBSDID("$FreeBSD$");
#include <sys/mutex.h>
#include <sys/syscallsubr.h>
#include <sys/sysctl.h>
#include <sys/pax.h>
#include <sys/proc.h>
#include <sys/racct.h>
#include <sys/resourcevar.h>
@ -410,6 +412,7 @@ struct sysentvec null_sysvec = {
.sv_fetch_syscall_args = null_fetch_syscall_args,
.sv_syscallnames = NULL,
.sv_schedtail = NULL,
.sv_pax_aslr_init = NULL,
};
/*
@ -476,6 +479,11 @@ proc0_init(void *dummy __unused)
p->p_flag = P_SYSTEM | P_INMEM;
p->p_flag2 = 0;
p->p_state = PRS_NORMAL;
#ifdef PAX
p->p_pax = PAX_NOTE_ALL_DISABLED;
#endif
p->p_usrstack = USRSTACK;
p->p_psstrings = PS_STRINGS;
knlist_init_mtx(&p->p_klist, &p->p_mtx);
STAILQ_INIT(&p->p_ktr);
p->p_nice = NZERO;
@ -493,6 +501,9 @@ proc0_init(void *dummy __unused)
td->td_flags = TDF_INMEM;
td->td_pflags = TDP_KTHREAD;
td->td_cpuset = cpuset_thread0();
#ifdef PAX
td->td_pax = PAX_NOTE_ALL_DISABLED;
#endif
prison0_init();
p->p_peers = 0;
p->p_leader = p;
@ -713,7 +724,7 @@ start_init(void *dummy)
/*
* Need just enough stack to hold the faked-up "execve()" arguments.
*/
addr = p->p_sysent->sv_usrstack - PAGE_SIZE;
addr = p->p_usrstack - PAGE_SIZE;
if (vm_map_find(&p->p_vmspace->vm_map, NULL, 0, &addr, PAGE_SIZE, 0,
VMFS_NO_SPACE, VM_PROT_ALL, VM_PROT_ALL, 0) != 0)
panic("init: couldn't allocate argument space");
@ -740,7 +751,7 @@ start_init(void *dummy)
* Move out the boot flag argument.
*/
options = 0;
ucp = (char *)p->p_sysent->sv_usrstack;
ucp = (char *)p->p_usrstack;
(void)subyte(--ucp, 0); /* trailing zero */
if (boothowto & RB_SINGLE) {
(void)subyte(--ucp, 's');

View file

@ -31,6 +31,7 @@ __FBSDID("$FreeBSD$");
#include "opt_hwpmc_hooks.h"
#include "opt_kdtrace.h"
#include "opt_ktrace.h"
#include "opt_pax.h"
#include "opt_vm.h"
#include <sys/param.h>
@ -52,6 +53,7 @@ __FBSDID("$FreeBSD$");
#include <sys/imgact_elf.h>
#include <sys/wait.h>
#include <sys/malloc.h>
#include <sys/pax.h>
#include <sys/priv.h>
#include <sys/proc.h>
#include <sys/pioctl.h>
@ -128,11 +130,6 @@ SYSCTL_INT(_kern, OID_AUTO, disallow_high_osrel, CTLFLAG_RW,
&disallow_high_osrel, 0,
"Disallow execution of binaries built for higher version of the world");
static int map_at_zero = 0;
TUNABLE_INT("security.bsd.map_at_zero", &map_at_zero);
SYSCTL_INT(_security_bsd, OID_AUTO, map_at_zero, CTLFLAG_RW, &map_at_zero, 0,
"Permit processes to map an object at virtual address 0.");
static int
sysctl_kern_ps_strings(SYSCTL_HANDLER_ARGS)
{
@ -143,12 +140,12 @@ sysctl_kern_ps_strings(SYSCTL_HANDLER_ARGS)
#ifdef SCTL_MASK32
if (req->flags & SCTL_MASK32) {
unsigned int val;
val = (unsigned int)p->p_sysent->sv_psstrings;
val = (unsigned int)p->p_psstrings;
error = SYSCTL_OUT(req, &val, sizeof(val));
} else
#endif
error = SYSCTL_OUT(req, &p->p_sysent->sv_psstrings,
sizeof(p->p_sysent->sv_psstrings));
error = SYSCTL_OUT(req, &p->p_psstrings,
sizeof(p->p_psstrings));
return error;
}
@ -162,12 +159,12 @@ sysctl_kern_usrstack(SYSCTL_HANDLER_ARGS)
#ifdef SCTL_MASK32
if (req->flags & SCTL_MASK32) {
unsigned int val;
val = (unsigned int)p->p_sysent->sv_usrstack;
val = (unsigned int)p->p_usrstack;
error = SYSCTL_OUT(req, &val, sizeof(val));
} else
#endif
error = SYSCTL_OUT(req, &p->p_sysent->sv_usrstack,
sizeof(p->p_sysent->sv_usrstack));
error = SYSCTL_OUT(req, &p->p_usrstack,
sizeof(p->p_usrstack));
return error;
}
@ -452,6 +449,12 @@ interpret:
imgp->vp = binvp;
}
#ifdef PAX
error = pax_elf(imgp, td, 0);
if (error)
goto exec_fail_dealloc;
#endif
/*
* Check file permissions (also 'opens' file)
*/
@ -565,6 +568,11 @@ interpret:
goto exec_fail_dealloc;
}
p->p_psstrings = p->p_sysent->sv_psstrings;
#ifdef PAX_ASLR
pax_aslr_stack_with_gap(p, &(p->p_psstrings));
#endif
/*
* Copy out strings (args and env) and initialize stack base
*/
@ -1045,10 +1053,7 @@ exec_new_vmspace(imgp, sv)
* not disrupted
*/
map = &vmspace->vm_map;
if (map_at_zero)
sv_minuser = sv->sv_minuser;
else
sv_minuser = MAX(sv->sv_minuser, PAGE_SIZE);
sv_minuser = MAX(sv->sv_minuser, PAGE_SIZE);
if (vmspace->vm_refcnt == 1 && vm_map_min(map) == sv_minuser &&
vm_map_max(map) == sv->sv_maxuser) {
shmexit(vmspace);
@ -1062,19 +1067,44 @@ exec_new_vmspace(imgp, sv)
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) {
p->p_shared_page_base = sv->sv_shared_page_base;
#ifdef PAX_ASLR
PROC_LOCK(imgp->proc);
pax_aslr_vdso(p, &(p->p_shared_page_base));
PROC_UNLOCK(imgp->proc);
#endif
vm_object_reference(obj);
error = vm_map_fixed(map, obj, 0,
sv->sv_shared_page_base, sv->sv_shared_page_len,
p->p_shared_page_base, sv->sv_shared_page_len,
VM_PROT_READ | VM_PROT_EXECUTE,
VM_PROT_READ | VM_PROT_EXECUTE,
MAP_INHERIT_SHARE | MAP_ACC_NO_CHARGE);
if (error) {
#ifdef PAX_ASLR
pax_log_aslr(p, PAX_LOG_DEFAULT,
"failed to map the shared-page @%p",
(void *)p->p_shared_page_base);
#endif
vm_object_deallocate(obj);
return (error);
}
p->p_timekeep_base = sv->sv_timekeep_base;
#ifdef PAX_ASLR
PROC_LOCK(imgp->proc);
if (p->p_timekeep_base != 0)
pax_aslr_vdso(p, &(p->p_timekeep_base));
PROC_UNLOCK(imgp->proc);
#endif
}
/* Allocate a new stack */
@ -1094,13 +1124,27 @@ exec_new_vmspace(imgp, sv)
} else {
ssiz = maxssiz;
}
stack_addr = sv->sv_usrstack - ssiz;
stack_addr = sv->sv_usrstack;
#ifdef PAX_ASLR
/* Randomize the stack top. */
pax_aslr_stack(p, &stack_addr);
#endif
/* Save the process specific randomized stack top */
p->p_usrstack = stack_addr;
/* Calculate the stack's mapping address */
stack_addr -= ssiz;
error = vm_map_stack(map, stack_addr, (vm_size_t)ssiz,
obj != NULL && imgp->stack_prot != 0 ? imgp->stack_prot :
sv->sv_stackprot,
VM_PROT_ALL, MAP_STACK_GROWS_DOWN);
if (error)
if (error) {
#ifdef PAX_ASLR
pax_log_aslr(p, PAX_LOG_DEFAULT,
"failed to map the main stack @%p",
(void *)p->p_usrstack);
#endif
return (error);
}
#ifdef __ia64__
/* Allocate a new register stack */
@ -1278,10 +1322,15 @@ exec_copyout_strings(imgp)
execpath_len = 0;
p = imgp->proc;
szsigcode = 0;
arginfo = (struct ps_strings *)p->p_sysent->sv_psstrings;
if (p->p_sysent->sv_sigcode_base == 0) {
p->p_sigcode_base = p->p_sysent->sv_sigcode_base;
arginfo = (struct ps_strings *)p->p_psstrings;
if (p->p_sigcode_base == 0) {
if (p->p_sysent->sv_szsigcode != NULL)
szsigcode = *(p->p_sysent->sv_szsigcode);
#ifdef PAX_ASLR
} else {
pax_aslr_vdso(p, &(p->p_sigcode_base));
#endif
}
destp = (uintptr_t)arginfo;

View file

@ -481,6 +481,7 @@ do_fork(struct thread *td, int flags, struct proc *p2, struct thread *td2,
__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;

View file

@ -33,6 +33,7 @@ __FBSDID("$FreeBSD$");
#include "opt_ddb.h"
#include "opt_inet.h"
#include "opt_inet6.h"
#include "opt_pax.h"
#include <sys/param.h>
#include <sys/types.h>
@ -249,6 +250,10 @@ prison0_init(void)
prison0.pr_cpuset = cpuset_ref(thread0.td_cpuset);
prison0.pr_osreldate = osreldate;
strlcpy(prison0.pr_osrelease, osrelease, sizeof(prison0.pr_osrelease));
#ifdef PAX
pax_init_prison(&prison0);
#endif
}
#ifdef INET
@ -1367,6 +1372,10 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags)
goto done_releroot;
}
#ifdef PAX
pax_init_prison(pr);
#endif
mtx_lock(&pr->pr_mtx);
/*
* New prisons do not yet have a reference, because we do not
@ -4731,6 +4740,27 @@ db_show_prison(struct prison *pr)
ii == 0 ? "ip6.addr =" : " ",
ip6_sprintf(ip6buf, &pr->pr_ip6[ii]));
#endif
#ifdef PAX
db_printf(" pr_hbsd = {\n");
db_printf(" .aslr = {\n");
db_printf(" .status = %d\n",
pr->pr_hbsd.aslr.status);
db_printf(" .compat_status = %d\n",
pr->pr_hbsd.aslr.compat_status);
db_printf(" .disallow_map32bit_status = %d\n",
pr->pr_hbsd.aslr.disallow_map32bit_status);
db_printf(" }\n");
db_printf(" .log = {\n");
db_printf(" .log = %d\n",
pr->pr_hbsd.log.log);
db_printf(" .ulog = %d\n",
pr->pr_hbsd.log.ulog);
db_printf(" }\n");
db_printf(" }\n");
#endif
}
DB_SHOW_COMMAND(prison, db_show_prison_command)

View file

@ -82,6 +82,8 @@ SYSCTL_ROOT_NODE(OID_AUTO, compat, CTLFLAG_RW, 0,
"Compatibility code");
SYSCTL_ROOT_NODE(OID_AUTO, security, CTLFLAG_RW, 0,
"Security");
SYSCTL_ROOT_NODE(OID_AUTO, hardening, CTLFLAG_RW, 0,
"Kernel hardening features");
#ifdef REGRESSION
SYSCTL_ROOT_NODE(OID_AUTO, regression, CTLFLAG_RW, 0,
"Regression test MIB");

View file

@ -1541,7 +1541,7 @@ get_proc_vector32(struct thread *td, struct proc *p, char ***proc_vectorp,
size_t vsize, size;
int i, error;
error = proc_read_mem(td, p, (vm_offset_t)(p->p_sysent->sv_psstrings),
error = proc_read_mem(td, p, (vm_offset_t)(p->p_psstrings),
&pss, sizeof(pss));
if (error != 0)
return (error);
@ -1617,7 +1617,7 @@ get_proc_vector(struct thread *td, struct proc *p, char ***proc_vectorp,
if (SV_PROC_FLAG(p, SV_ILP32) != 0)
return (get_proc_vector32(td, p, proc_vectorp, vsizep, type));
#endif
error = proc_read_mem(td, p, (vm_offset_t)(p->p_sysent->sv_psstrings),
error = proc_read_mem(td, p, (vm_offset_t)(p->p_psstrings),
&pss, sizeof(pss));
if (error != 0)
return (error);
@ -2609,13 +2609,13 @@ sysctl_kern_proc_ps_strings(SYSCTL_HANDLER_ARGS)
* process.
*/
ps_strings32 = SV_PROC_FLAG(p, SV_ILP32) != 0 ?
PTROUT(p->p_sysent->sv_psstrings) : 0;
PTROUT(p->p_psstrings) : 0;
PROC_UNLOCK(p);
error = SYSCTL_OUT(req, &ps_strings32, sizeof(ps_strings32));
return (error);
}
#endif
ps_strings = p->p_sysent->sv_psstrings;
ps_strings = p->p_psstrings;
PROC_UNLOCK(p);
error = SYSCTL_OUT(req, &ps_strings, sizeof(ps_strings));
return (error);
@ -2719,13 +2719,13 @@ sysctl_kern_proc_sigtramp(SYSCTL_HANDLER_ARGS)
bzero(&kst32, sizeof(kst32));
if (SV_PROC_FLAG(p, SV_ILP32)) {
if (sv->sv_sigcode_base != 0) {
kst32.ksigtramp_start = sv->sv_sigcode_base;
kst32.ksigtramp_end = sv->sv_sigcode_base +
kst32.ksigtramp_start = p->p_sigcode_base;
kst32.ksigtramp_end = p->p_sigcode_base +
*sv->sv_szsigcode;
} else {
kst32.ksigtramp_start = sv->sv_psstrings -
kst32.ksigtramp_start = p->p_psstrings -
*sv->sv_szsigcode;
kst32.ksigtramp_end = sv->sv_psstrings;
kst32.ksigtramp_end = p->p_psstrings;
}
}
PROC_UNLOCK(p);
@ -2735,13 +2735,13 @@ sysctl_kern_proc_sigtramp(SYSCTL_HANDLER_ARGS)
#endif
bzero(&kst, sizeof(kst));
if (sv->sv_sigcode_base != 0) {
kst.ksigtramp_start = (char *)sv->sv_sigcode_base;
kst.ksigtramp_end = (char *)sv->sv_sigcode_base +
kst.ksigtramp_start = (char *)p->p_sigcode_base;
kst.ksigtramp_end = (char *)p->p_sigcode_base +
*sv->sv_szsigcode;
} else {
kst.ksigtramp_start = (char *)sv->sv_psstrings -
kst.ksigtramp_start = (char *)p->p_psstrings -
*sv->sv_szsigcode;
kst.ksigtramp_end = (char *)sv->sv_psstrings;
kst.ksigtramp_end = (char *)p->p_psstrings;
}
PROC_UNLOCK(p);
error = SYSCTL_OUT(req, &kst, sizeof(kst));

View file

@ -38,6 +38,7 @@
__FBSDID("$FreeBSD$");
#include "opt_compat.h"
#include "opt_pax.h"
#include <sys/param.h>
#include <sys/systm.h>
@ -47,6 +48,7 @@ __FBSDID("$FreeBSD$");
#include <sys/lock.h>
#include <sys/malloc.h>
#include <sys/mutex.h>
#include <sys/pax.h>
#include <sys/priv.h>
#include <sys/proc.h>
#include <sys/refcount.h>
@ -776,12 +778,12 @@ kern_proc_setrlimit(struct thread *td, struct proc *p, u_int which,
if (limp->rlim_cur > oldssiz.rlim_cur) {
prot = p->p_sysent->sv_stackprot;
size = limp->rlim_cur - oldssiz.rlim_cur;
addr = p->p_sysent->sv_usrstack -
addr = p->p_usrstack -
limp->rlim_cur;
} else {
prot = VM_PROT_NONE;
size = oldssiz.rlim_cur - limp->rlim_cur;
addr = p->p_sysent->sv_usrstack -
addr = p->p_usrstack -
oldssiz.rlim_cur;
}
addr = trunc_page(addr);

View file

@ -255,6 +255,7 @@ create_thread(struct thread *td, mcontext_t *ctx,
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);

View file

@ -39,6 +39,7 @@ __FBSDID("$FreeBSD$");
#ifdef _KERNEL
#include "opt_ddb.h"
#include "opt_pax.h"
#include "opt_printf.h"
#endif /* _KERNEL */
@ -52,6 +53,7 @@ __FBSDID("$FreeBSD$");
#include <sys/kernel.h>
#include <sys/msgbuf.h>
#include <sys/malloc.h>
#include <sys/pax.h>
#include <sys/priv.h>
#include <sys/proc.h>
#include <sys/stddef.h>
@ -180,6 +182,49 @@ uprintf(const char *fmt, ...)
return (retval);
}
int
hbsd_uprintf(const char *fmt, ...)
{
va_list ap;
struct putchar_arg pca;
struct proc *p;
struct thread *td;
int p_locked, retval;
td = curthread;
if (TD_IS_IDLETHREAD(td))
return (0);
sx_slock(&proctree_lock);
p = td->td_proc;
if ((p_locked = PROC_LOCKED(p)))
PROC_LOCK(p);
if ((p->p_flag & P_CONTROLT) == 0) {
if (p_locked)
PROC_UNLOCK(p);
sx_sunlock(&proctree_lock);
return (0);
}
SESS_LOCK(p->p_session);
pca.tty = p->p_session->s_ttyp;
SESS_UNLOCK(p->p_session);
if (p_locked)
PROC_UNLOCK(p);
if (pca.tty == NULL) {
sx_sunlock(&proctree_lock);
return (0);
}
pca.flags = TOTTY;
pca.p_bufr = NULL;
va_start(ap, fmt);
tty_lock(pca.tty);
sx_sunlock(&proctree_lock);
retval = kvprintf(fmt, putchar, &pca, 10, ap);
tty_unlock(pca.tty);
va_end(ap);
return (retval);
}
/*
* tprintf and vtprintf print on the controlling terminal associated with the
* given session, possibly to the log as well.

View file

@ -33,6 +33,7 @@
__FBSDID("$FreeBSD$");
#include "opt_compat.h"
#include "opt_pax.h"
#include <sys/param.h>
#include <sys/systm.h>
@ -44,6 +45,7 @@ __FBSDID("$FreeBSD$");
#include <sys/priv.h>
#include <sys/proc.h>
#include <sys/vnode.h>
#include <sys/pax.h>
#include <sys/ptrace.h>
#include <sys/rwlock.h>
#include <sys/sx.h>

View file

@ -28,6 +28,8 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include "opt_pax.h"
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/systm.h>
@ -36,6 +38,7 @@ __FBSDID("$FreeBSD$");
#include <sys/linker.h>
#include <sys/sysent.h>
#include <sys/imgact_elf.h>
#include <sys/pax.h>
#include <sys/proc.h>
#include <sys/syscall.h>
#include <sys/signalvar.h>
@ -83,6 +86,7 @@ struct sysentvec elf64_freebsd_sysvec = {
.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 @@ struct sysentvec elf32_freebsd_sysvec = {
.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 = {

View file

@ -31,6 +31,7 @@
*/
#include "opt_compat.h"
#include "opt_pax.h"
#define __ELF_WORD_SIZE 32
@ -42,6 +43,7 @@
#include <sys/exec.h>
#include <sys/imgact.h>
#include <sys/malloc.h>
#include <sys/pax.h>
#include <sys/proc.h>
#include <sys/namei.h>
#include <sys/fcntl.h>
@ -106,6 +108,7 @@ struct sysentvec elf32_freebsd_sysvec = {
.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);
@ -464,7 +467,7 @@ freebsd32_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
/*
* Signal trampoline code is at base of user stack.
*/
td->td_frame->ra = (register_t)(intptr_t)FREEBSD32_PS_STRINGS - *(p->p_sysent->sv_szsigcode);
td->td_frame->ra = (register_t)(intptr_t)p->p_psstrings - *(p->p_sysent->sv_szsigcode);
PROC_LOCK(p);
mtx_lock(&psp->ps_mtx);
}

View file

@ -179,7 +179,7 @@ sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
/*
* Signal trampoline code is at base of user stack.
*/
regs->ra = (register_t)(intptr_t)PS_STRINGS - *(p->p_sysent->sv_szsigcode);
regs->ra = (register_t)(intptr_t)p->p_psstrings - *(p->p_sysent->sv_szsigcode);
PROC_LOCK(p);
mtx_lock(&psp->ps_mtx);
}

View file

@ -25,6 +25,8 @@
* $FreeBSD$
*/
#include "opt_pax.h"
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/systm.h>
@ -34,6 +36,7 @@
#include <sys/exec.h>
#include <sys/imgact.h>
#include <sys/malloc.h>
#include <sys/pax.h>
#include <sys/proc.h>
#include <sys/namei.h>
#include <sys/fcntl.h>
@ -107,6 +110,7 @@ struct sysentvec elf32_freebsd_sysvec = {
.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);

View file

@ -25,12 +25,15 @@
* $FreeBSD$
*/
#include "opt_pax.h"
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/systm.h>
#include <sys/exec.h>
#include <sys/imgact.h>
#include <sys/malloc.h>
#include <sys/pax.h>
#include <sys/proc.h>
#include <sys/namei.h>
#include <sys/fcntl.h>
@ -83,6 +86,7 @@ struct sysentvec elf64_freebsd_sysvec = {
.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);

View file

@ -295,7 +295,7 @@ sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
mtx_unlock(&psp->ps_mtx);
PROC_UNLOCK(p);
tf->srr0 = (register_t)p->p_sysent->sv_sigcode_base;
tf->srr0 = (register_t)p->p_sigcode_base;
/*
* copy the frame out to userland.

View file

@ -31,6 +31,8 @@
* from: NetBSD: mdreloc.c,v 1.42 2008/04/28 20:23:04 martin Exp
*/
#include "opt_pax.h"
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
@ -40,6 +42,7 @@ __FBSDID("$FreeBSD$");
#include <sys/exec.h>
#include <sys/imgact.h>
#include <sys/linker.h>
#include <sys/pax.h>
#include <sys/proc.h>
#include <sys/sysent.h>
#include <sys/imgact_elf.h>
@ -87,6 +90,7 @@ static struct sysentvec elf64_freebsd_sysvec = {
.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 = {

View file

@ -1003,7 +1003,7 @@ exec_setregs(struct thread *td, struct image_params *imgp, u_long stack)
bzero(pcb, sizeof(*pcb));
bzero(tf, sizeof(*tf));
tf->tf_out[0] = stack;
tf->tf_out[3] = p->p_sysent->sv_psstrings;
tf->tf_out[3] = p->p_psstrings;
tf->tf_out[6] = sp - SPOFF - sizeof(struct frame);
tf->tf_tnpc = imgp->entry_addr + 4;
tf->tf_tpc = imgp->entry_addr;

View file

@ -30,6 +30,10 @@
#ifndef _SYS_JAIL_H_
#define _SYS_JAIL_H_
#if defined(_KERNEL) || defined(_WANT_PRISON)
#include <sys/pax.h>
#endif
#ifdef _KERNEL
struct jail_v0 {
u_int32_t version;
@ -187,6 +191,7 @@ struct prison {
char pr_domainname[MAXHOSTNAMELEN]; /* (p) jail domainname */
char pr_hostuuid[HOSTUUIDLEN]; /* (p) jail hostuuid */
char pr_osrelease[OSRELEASELEN]; /* (c) kern.osrelease value */
struct hbsd_features pr_hbsd; /* (p) PaX-inspired hardening features */
};
struct prison_racct {

View file

@ -104,6 +104,7 @@ enum sysinit_sub_id {
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 */

179
sys/sys/pax.h Normal file
View file

@ -0,0 +1,179 @@
/*-
* Copyright (c) 2006 Elad Efrat <elad@NetBSD.org>
* Copyright (c) 2013-2016, by Oliver Pinter <oliver.pinter@hardenedbsd.org>
* Copyright (c) 2014-2015 by Shawn Webb <shawn.webb@hardenedbsd.org>
* 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
#if defined(_KERNEL) || defined(_WANT_PRISON)
struct hbsd_features {
struct hbsd_aslr {
int status; /* (p) PaX ASLR enabled */
int compat_status; /* (p) PaX ASLR enabled (compat32) */
int disallow_map32bit_status; /* (p) MAP_32BIT protection (__LP64__ only) */
} aslr;
struct hbsd_log {
int log; /* (p) Per-jail logging status */
int ulog; /* (p) Per-jail user visible logging status */
} log;
};
#endif
#ifdef _KERNEL
#include <vm/vm.h>
struct image_params;
struct prison;
struct thread;
struct proc;
struct vnode;
struct vm_offset_t;
typedef uint32_t pax_flag_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
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 *imgp, struct thread *td, pax_flag_t mode);
void pax_get_flags(struct proc *p, pax_flag_t *flags);
void pax_get_flags_td(struct thread *td, pax_flag_t *flags);
struct prison *pax_get_prison(struct proc *p);
struct prison *pax_get_prison_td(struct thread *td);
void pax_init_prison(struct prison *pr);
/*
* ASLR related functions
*/
bool pax_aslr_active(struct proc *p);
#ifdef PAX_ASLR
void pax_aslr_init_prison(struct prison *pr);
void pax_aslr_init_prison32(struct prison *pr);
void pax_aslr_init_vmspace(struct proc *p);
void pax_aslr_init_vmspace32(struct proc *p);
#else
#define pax_aslr_init_prison(pr) do {} while (0)
#define pax_aslr_init_prison32(pr) do {} while (0)
#define pax_aslr_init_vmspace NULL
#define pax_aslr_init_vmspace32 NULL
#endif
void pax_aslr_init(struct image_params *imgp);
void pax_aslr_execbase(struct proc *p, u_long *et_dyn_addrp);
void pax_aslr_mmap(struct proc *p, vm_offset_t *addr, vm_offset_t orig_addr, int mmap_flags);
void pax_aslr_mmap_map_32bit(struct proc *p, vm_offset_t *addr, vm_offset_t orig_addr, int mmap_flags);
void pax_aslr_rtld(struct proc *p, u_long *addr);
pax_flag_t pax_aslr_setup_flags(struct image_params *imgp, struct thread *td, pax_flag_t mode);
void pax_aslr_stack(struct proc *p, vm_offset_t *addr);
void pax_aslr_stack_with_gap(struct proc *p, vm_offset_t *addr);
void pax_aslr_vdso(struct proc *p, vm_offset_t *addr);
pax_flag_t pax_disallow_map32bit_setup_flags(struct image_params *imgp, struct thread *td, pax_flag_t mode);
bool pax_disallow_map32bit_active(struct thread *td, int mmap_flags);
/*
* Log related functions
*/
typedef uint64_t pax_log_settings_t;
#define PAX_LOG_DEFAULT 0x00000000
#define PAX_LOG_SKIP_DETAILS 0x00000001
#define PAX_LOG_NO_NEWLINE 0x00000002
#define PAX_LOG_P_COMM 0x00000004
#define PAX_LOG_NO_P_PAX 0x00000008
#define PAX_LOG_NO_INDENT 0x00000010
void pax_log_init_prison(struct prison *pr);
void pax_printf_flags(struct proc *p, pax_log_settings_t flags);
void pax_printf_flags_td(struct thread *td, pax_log_settings_t flags);
void pax_db_printf_flags(struct proc *p, pax_log_settings_t flags);
void pax_db_printf_flags_td(struct thread *td, pax_log_settings_t flags);
int hbsd_uprintf(const char *fmt, ...) __printflike(1, 2);
void pax_log_internal(struct proc *, pax_log_settings_t flags, const char *fmt, ...) __printflike(3, 4);
void pax_log_internal_imgp(struct image_params *imgp, pax_log_settings_t flags, const char* fmt, ...) __printflike(3, 4);
void pax_ulog_internal(const char *fmt, ...) __printflike(1, 2);
void pax_log_aslr(struct proc *, pax_log_settings_t flags, const char *fmt, ...) __printflike(3, 4);
void pax_ulog_aslr(const char *fmt, ...) __printflike(1, 2);
/*
* Hardening related functions
*/
#ifdef PAX_HARDENING
void pax_hardening_init_prison(struct prison *pr);
#else
#define pax_hardening_init_prison(pr) do {} while (0)
#endif
int pax_procfs_harden(struct thread *td);
#define PAX_NOTE_PAGEEXEC 0x00000001
#define PAX_NOTE_NOPAGEEXEC 0x00000002
#define PAX_NOTE_MPROTECT 0x00000004
#define PAX_NOTE_NOMPROTECT 0x00000008
#define PAX_NOTE_SEGVGUARD 0x00000010
#define PAX_NOTE_NOSEGVGUARD 0x00000020
#define PAX_NOTE_ASLR 0x00000040
#define PAX_NOTE_NOASLR 0x00000080
#define PAX_NOTE_SHLIBRANDOM 0x00000100
#define PAX_NOTE_NOSHLIBRANDOM 0x00000200
#define PAX_NOTE_DISALLOWMAP32BIT 0x00000400
#define PAX_NOTE_NODISALLOWMAP32BIT 0x00000800
#define PAX_NOTE_RESERVED0 0x40000000
#define PAX_NOTE_FINALIZED 0x80000000
#define PAX_NOTE_ALL_ENABLED \
(PAX_NOTE_PAGEEXEC | PAX_NOTE_MPROTECT | PAX_NOTE_SEGVGUARD | \
PAX_NOTE_ASLR | PAX_NOTE_SHLIBRANDOM | PAX_NOTE_DISALLOWMAP32BIT)
#define PAX_NOTE_ALL_DISABLED \
(PAX_NOTE_NOPAGEEXEC | PAX_NOTE_NOMPROTECT | \
PAX_NOTE_NOSEGVGUARD | PAX_NOTE_NOASLR | PAX_NOTE_NOSHLIBRANDOM | \
PAX_NOTE_NODISALLOWMAP32BIT)
#define PAX_NOTE_ALL (PAX_NOTE_ALL_ENABLED | PAX_NOTE_ALL_DISABLED | PAX_NOTE_FINALIZED)
#endif /* _KERNEL */
#define PAX_HARDENING_SHLIBRANDOM 0x00000100
#define PAX_HARDENING_NOSHLIBRANDOM 0x00000200
#endif /* !_SYS_PAX_H */

View file

@ -286,6 +286,7 @@ struct thread {
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
/*
@ -561,6 +562,12 @@ struct proc {
rlim_t p_cpulimit; /* (c) Current CPU limit in seconds. */
signed char p_nice; /* (c) Process "nice" value. */
int p_fibnum; /* in this routing domain XXX MRT */
uint32_t p_pax; /* (b) PaX is enabled to this process */
vm_offset_t p_usrstack; /* (b) Process stack top. */
vm_offset_t p_psstrings; /* (b) Process psstrings address. */
vm_offset_t p_timekeep_base; /* (c) Address of timekeep structure. */
vm_offset_t p_shared_page_base; /* (c) Address of shared page. */
vm_offset_t p_sigcode_base; /* Address of sigcode. */
/* End area that is copied on creation. */
#define p_endcopy p_xstat

View file

@ -753,6 +753,7 @@ SYSCTL_DECL(_compat);
SYSCTL_DECL(_regression);
SYSCTL_DECL(_security);
SYSCTL_DECL(_security_bsd);
SYSCTL_DECL(_hardening);
extern char machine[];
extern char osrelease[];

View file

@ -38,6 +38,7 @@ struct rlimit;
struct sysent;
struct thread;
struct ksiginfo;
struct proc;
typedef int sy_call_t(struct thread *, void *);
@ -130,6 +131,7 @@ struct sysentvec {
uint32_t sv_timekeep_gen;
void *sv_shared_page_obj;
void (*sv_schedtail)(struct thread *);
void (* const sv_pax_aslr_init)(struct proc *p);
};
#define SV_ILP32 0x000100

View file

@ -65,12 +65,15 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include "opt_pax.h"
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/ktr.h>
#include <sys/lock.h>
#include <sys/mutex.h>
#include <sys/pax.h>
#include <sys/proc.h>
#include <sys/vmmeter.h>
#include <sys/mman.h>
@ -295,6 +298,15 @@ vmspace_alloc(vm_offset_t min, vm_offset_t max, pmap_pinit_t pinit)
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;
vm->vm_aslr_delta_vdso = 0;
#ifdef __LP64__
vm->vm_aslr_delta_map32bit = 0;
#endif
#endif
return (vm);
}
@ -3275,6 +3287,15 @@ vmspace_fork(struct vmspace *vm1, vm_ooffset_t *fork_charge)
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;
vm2->vm_aslr_delta_vdso = vm1->vm_aslr_delta_vdso;
#ifdef __LP64__
vm2->vm_aslr_delta_map32bit = vm1->vm_aslr_delta_map32bit;
#endif
#endif
vm_map_lock(old_map);
if (old_map->busy)
vm_map_wait_busy(old_map);
@ -3657,7 +3678,8 @@ Retry:
return (KERN_NO_SPACE);
}
is_procstack = (addr >= (vm_offset_t)vm->vm_maxsaddr) ? 1 : 0;
is_procstack = (addr >= (vm_offset_t)vm->vm_maxsaddr &&
addr < (vm_offset_t)p->p_usrstack) ? 1 : 0;
/*
* If this is the main process stack, see if we're over the stack

View file

@ -241,6 +241,13 @@ struct vmspace {
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 */
vm_offset_t vm_aslr_delta_vdso; /* VDSO base random delta for ASLR */
#ifdef __LP64__
vm_offset_t vm_aslr_delta_map32bit; /* random for MAP_32BIT mappings */
#endif
volatile int vm_refcnt; /* number of references */
/*
* Keep the PMAP last, so that CPU-specific variations of that

View file

@ -45,6 +45,7 @@ __FBSDID("$FreeBSD$");
#include "opt_compat.h"
#include "opt_hwpmc_hooks.h"
#include "opt_pax.h"
#include <sys/param.h>
#include <sys/systm.h>
@ -54,6 +55,7 @@ __FBSDID("$FreeBSD$");
#include <sys/mutex.h>
#include <sys/sysproto.h>
#include <sys/filedesc.h>
#include <sys/pax.h>
#include <sys/priv.h>
#include <sys/proc.h>
#include <sys/procctl.h>
@ -211,6 +213,9 @@ sys_mmap(td, uap)
off_t pos;
struct vmspace *vms = td->td_proc->p_vmspace;
cap_rights_t rights;
#ifdef PAX_ASLR
int pax_aslr_done;
#endif
addr = (vm_offset_t) uap->addr;
size = uap->len;
@ -220,6 +225,10 @@ sys_mmap(td, uap)
fp = NULL;
#ifdef PAX_ASLR
pax_aslr_done = 0;
#endif
/*
* Enforce the constraints.
* Mapping of length 0 is only allowed for old binaries.
@ -297,7 +306,13 @@ sys_mmap(td, uap)
*/
if (addr + size > MAP_32BIT_MAX_ADDR)
addr = 0;
#endif
#ifdef PAX_ASLR
PROC_LOCK(td->td_proc);
pax_aslr_mmap_map_32bit(td->td_proc, &addr, (vm_offset_t)uap->addr, flags);
pax_aslr_done = 1;
PROC_UNLOCK(td->td_proc);
#endif /* PAX_ASLR */
#endif /* MAP_32BIT */
} else {
/*
* XXX for non-fixed mappings where no hint is provided or
@ -315,6 +330,12 @@ sys_mmap(td, uap)
addr = round_page((vm_offset_t)vms->vm_daddr +
lim_max(td->td_proc, RLIMIT_DATA));
PROC_UNLOCK(td->td_proc);
#ifdef PAX_ASLR
PROC_LOCK(td->td_proc);
pax_aslr_mmap(td->td_proc, &addr, (vm_offset_t)uap->addr, flags);
pax_aslr_done = 1;
PROC_UNLOCK(td->td_proc);
#endif
}
if (flags & MAP_ANON) {
/*