Skip to content
Permalink
Browse files

HBSD ASLR2: rewritten stack randomization

* store the stack's top per process (p->p_usrstack) instead of in sysvec
* store the ps_string's top per process (p->p_psstrings) instead of in sysvec
* eliminate USRSTACK where possible
* eliminate PS_STRINGS where possible
* bump stack randomization from 26 bit to 42 bit
* apply randomization to stack mapping
* apply a small random gap inside the mapping too

For more details see http://pax.grsecurity.net/docs/randustack.txt .

This commit should fix firefox startup issues, which was previously
workarounded with secadm rule. This ASLR related firefox rule no longer
needs.

Signed-off-by: Oliver Pinter <oliver.pinter@hardenedbsd.org>
  • Loading branch information...
opntr committed Jun 23, 2015
1 parent 01cdf36 commit bd5cecb4dc7947a5e214fc100834399b4bffdee8
@@ -36,26 +36,6 @@ __FBSDID("$FreeBSD$");

#include "libc_private.h"

/*
* Older FreeBSD 2.0, 2.1 and 2.2 had different ps_strings structures and
* in different locations.
* 1: old_ps_strings at the very top of the stack.
* 2: old_ps_strings at SPARE_USRSPACE below the top of the stack.
* 3: ps_strings at the very top of the stack.
* We only support a kernel providing #3 style ps_strings.
*
* For historical purposes, a definition of the old ps_strings structure
* and location is preserved below:
struct old_ps_strings {
char *old_ps_argvstr;
int old_ps_nargvstr;
char *old_ps_envstr;
int old_ps_nenvstr;
};
#define OLD_PS_STRINGS ((struct old_ps_strings *) \
(USRSTACK - SPARE_USRSPACE - sizeof(struct old_ps_strings)))
*/

#include <stdarg.h>

#define SPT_BUFSIZE 2048 /* from other parts of sendmail */
@@ -415,7 +415,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_psstrings - sz_ia32_osigcode;
regs->tf_rflags &= ~(PSL_T | PSL_D);
regs->tf_cs = _ucode32sel;
regs->tf_ds = _udatasel;
@@ -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;
@@ -250,7 +250,7 @@ linux_mmap2(struct thread *td, struct linux_mmap2_args *args)
* 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_proc(p, RLIMIT_STACK);
PROC_UNLOCK(p);
}
@@ -274,7 +274,7 @@ elf_linux_fixup(register_t **stack_base, struct image_params *imgp)
struct proc *p;

p = imgp->proc;
arginfo = (struct ps_strings *)p->p_sysent->sv_psstrings;
arginfo = (struct ps_strings *)p->p_psstrings;

KASSERT(curthread->td_proc == imgp->proc,
("unsafe elf_linux_fixup(), should be curproc"));
@@ -341,7 +341,7 @@ linux_copyout_strings(struct image_params *imgp)
execpath_len = 0;

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 -
roundup(sizeof(canary), sizeof(char *)) -
roundup(execpath_len, sizeof(char *)) -
@@ -613,7 +613,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_proc(p, RLIMIT_STACK);
PROC_UNLOCK(p);
}
@@ -233,10 +233,10 @@ elf_linux_fixup(register_t **stack_base, struct image_params *imgp)
Elf32_Addr *pos;
struct linux32_ps_strings *arginfo;

arginfo = (struct linux32_ps_strings *)LINUX32_PS_STRINGS;

KASSERT(curthread->td_proc == imgp->proc,
("unsafe elf_linux_fixup(), should be curproc"));

arginfo = (struct linux32_ps_strings *)imgp->proc->p_psstrings;
base = (Elf32_Addr *)*stack_base;
args = (Elf32_Auxargs *)imgp->auxargs;
pos = base + (imgp->args->argc + imgp->args->envc + 2);
@@ -858,7 +858,7 @@ linux_copyout_strings(struct image_params *imgp)
else
execpath_len = 0;

arginfo = (struct linux32_ps_strings *)LINUX32_PS_STRINGS;
arginfo = (struct linux32_ps_strings *)imgp->proc->p_psstrings;
destp = (caddr_t)arginfo - SPARE_USRSPACE -
roundup(sizeof(canary), sizeof(char *)) -
roundup(execpath_len, sizeof(char *)) -
@@ -337,7 +337,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));
#ifdef PAX_ASLR
pax_aslr_stack(td->td_proc, &tf->tf_usr_lr);
#endif
@@ -543,7 +543,7 @@ sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)

tf->tf_elr = (register_t)catcher;
tf->tf_sp = (register_t)fp;
tf->tf_lr = (register_t)(PS_STRINGS - *(p->p_sysent->sv_szsigcode));
tf->tf_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_elr,
tf->tf_sp);
@@ -47,7 +47,7 @@
extern uintptr_t kernbase;
uintptr_t kernelbase = (uintptr_t) &kernbase;

#define INKERNEL(va) (((vm_offset_t)(va)) >= USRSTACK && \
#define INKERNEL(va) (((vm_offset_t)(va)) >= VM_MAXUSER_ADDRESS && \
((vm_offset_t)(va)) < VM_MAX_KERNEL_ADDRESS)

uint8_t dtrace_fuword8_nocheck(void *);
@@ -1043,7 +1043,7 @@ linprocfs_doprocmaps(PFS_FILL_ARGS)
} else if (SV_PROC_ABI(p) == SV_ABI_LINUX) {
if (e_start == p->p_sysent->sv_shared_page_base)
name = vdso_str;
if (e_end == p->p_sysent->sv_usrstack)
if (e_end == p->p_usrstack)
name = stack_str;
}
} else {
@@ -86,7 +86,7 @@ __FBSDID("$FreeBSD$");
* +-------+--------+--------+--------+
* | MIN | 8 bit | 16 bit | 8 bit |
* +-------+--------+--------+--------+
* | DEF | 8 bit | 26 bit | 8 bit |
* | DEF | 8 bit | 42 bit | 8 bit |
* +-------+--------+--------+--------+
* | MAX | 21 bit | 42 bit | 21 bit |
* +-------+--------+--------+--------+
@@ -114,9 +114,13 @@ __FBSDID("$FreeBSD$");
#endif /* PAX_ASLR_DELTA_MMAP_MAX_LEN */

#ifndef PAX_ASLR_DELTA_STACK_LSB
#define PAX_ASLR_DELTA_STACK_LSB 3
#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_STACK_MIN_LEN
#define PAX_ASLR_DELTA_STACK_MIN_LEN ((sizeof(void *) * NBBY) / 4)
#endif /* PAX_ASLR_DELTA_STACK_MAX_LEN */
@@ -145,8 +149,7 @@ __FBSDID("$FreeBSD$");
#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 26
#define PAX_ASLR_DELTA_STACK_DEF_LEN 16
#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 21
@@ -546,7 +549,6 @@ pax_aslr_sysinit(void)
printf("[PAX ASLR] mmap: %d bit\n", pax_aslr_mmap_len);
printf("[PAX ASLR] exec base: %d bit\n", pax_aslr_exec_len);
printf("[PAX ASLR] stack: %d bit\n", pax_aslr_stack_len);
printf("[PAX ASLR] XXXOP stack randomization should be bump from %d bit to 26+ bit, when I created a proper fix to boot issues\n", pax_aslr_stack_len);
}
SYSINIT(pax_aslr, SI_SUB_PAX, SI_ORDER_SECOND, pax_aslr_sysinit, NULL);

@@ -587,7 +589,7 @@ pax_aslr_init_vmspace(struct proc *p)

arc4rand(&rand_buf, sizeof(rand_buf), 0);
vm->vm_aslr_delta_stack = PAX_ASLR_DELTA(rand_buf,
PAX_ASLR_DELTA_STACK_LSB,
PAX_ASLR_DELTA_STACK_WITH_GAP_LSB,
pr->pr_hardening.hr_pax_aslr_stack_len);
vm->vm_aslr_delta_stack = ALIGN(vm->vm_aslr_delta_stack);

@@ -852,41 +854,46 @@ pax_aslr_rtld(struct proc *p, u_long *addr)
}

void
pax_aslr_stack(struct proc *p, uintptr_t *addr)
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;
*addr -= p->p_vmspace->vm_aslr_delta_stack;

/*
* 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_adjust(struct proc *p, u_long *ssiz)
pax_aslr_stack_with_gap(struct proc *p, vm_offset_t *addr)
{
struct rlimit rlim_stack;
uintptr_t orig_addr;
uintptr_t random;

if (!pax_aslr_active(p))
return;

*ssiz += p->p_vmspace->vm_aslr_delta_stack;

orig_addr = *addr;
/*
* This needed because we currently use
* gap based stack randomization.
* Apply the random gap offset withing the page.
*/
PROC_LOCK(p);
lim_rlimit_proc(p, RLIMIT_STACK, &rlim_stack);
PROC_UNLOCK(p);
if (*ssiz > rlim_stack.rlim_max)
rlim_stack.rlim_max = *ssiz;
if (*ssiz > rlim_stack.rlim_cur)
rlim_stack.rlim_cur = *ssiz;
kern_setrlimit(curthread, RLIMIT_STACK, &rlim_stack);
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
@@ -462,7 +462,7 @@ osendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
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;
@@ -762,7 +762,7 @@ sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
regs->tf_esp = (int)sfp;
regs->tf_eip = p->p_sysent->sv_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;
@@ -138,7 +138,7 @@ struct pmc_mdep;

#define PMC_IN_KERNEL_STACK(S,START,END) \
((S) >= (START) && (S) < (END))
#define PMC_IN_KERNEL(va) (((va) >= USRSTACK) && \
#define PMC_IN_KERNEL(va) (((va) >= VM_MAXUSER_ADDRESS) && \
((va) < VM_MAX_KERNEL_ADDRESS))

#define PMC_IN_USERSPACE(va) ((va) <= VM_MAXUSER_ADDRESS)
@@ -32,7 +32,7 @@
/*
* Stack trace.
*/
#define INKERNEL(va) (((vm_offset_t)(va)) >= USRSTACK && \
#define INKERNEL(va) (((vm_offset_t)(va)) >= VM_MAXUSER_ADDRESS && \
((vm_offset_t)(va)) < VM_MAX_KERNEL_ADDRESS)

struct i386_frame {
@@ -508,7 +508,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_proc(p, RLIMIT_STACK);
PROC_UNLOCK(p);
}
@@ -245,7 +245,7 @@ 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_sysent->sv_psstrings;
arginfo = (struct ps_strings *)p->p_psstrings;
uplatform = (Elf32_Addr *)((caddr_t)arginfo - linux_szplatform);
args = (Elf32_Auxargs *)imgp->auxargs;
pos = *stack_base + (imgp->args->argc + imgp->args->envc + 2);
@@ -316,7 +316,7 @@ linux_copyout_strings(struct image_params *imgp)
execpath_len = strlen(imgp->execpath) + 1;
else
execpath_len = 0;
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(sizeof(canary), sizeof(char *)) -
roundup(execpath_len, sizeof(char *)) -
@@ -2028,9 +2028,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));
@@ -485,6 +485,8 @@ proc0_init(void *dummy __unused)
#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;
@@ -729,7 +731,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");
@@ -756,7 +758,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');

0 comments on commit bd5cecb

Please sign in to comment.
You can’t perform that action at this time.