Skip to content
Permalink
Browse files

HBSD ASLR: Randomize the shared page (vdso)

* Move the shared page address to the proc struct.
* Move the sigcode base address to the proc struct.
* Add new sysctls for the VDSO randomization.
* Use vm_map_find() to make VDSO randomization robust.

github-issue: #12
Sponsored-by: SoldierX
Signed-Off-by: Shawn Webb <shawn.webb@hardenedbsd.org>
Signed-off-by: Oliver Pinter <oliver.pinter@hardenedbsd.org>
(cherry picked from commit b3bf41a5e955d121a8394d40c1f7b921278381db)
  • Loading branch information...
lattera authored and opntr committed Jul 4, 2015
1 parent 67cfda1 commit 951a6ca73f270ea5ae7e9f5ab21480c66fa4337b
@@ -435,7 +435,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;
@@ -526,7 +526,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;
@@ -670,7 +670,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;
@@ -283,7 +283,7 @@ elf_linux_fixup(register_t **stack_base, struct image_params *imgp)
pos = base + (imgp->args->argc + imgp->args->envc + 2);

AUXARGS_ENTRY(pos, LINUX_AT_SYSINFO_EHDR,
imgp->proc->p_sysent->sv_shared_page_base);
imgp->proc->p_shared_page_base);
AUXARGS_ENTRY(pos, LINUX_AT_HWCAP, cpu_feature);
AUXARGS_ENTRY(pos, LINUX_AT_CLKTCK, stclohz);
AUXARGS_ENTRY(pos, AT_PHDR, args->phdr);
@@ -242,7 +242,7 @@ elf_linux_fixup(register_t **stack_base, struct image_params *imgp)
pos = base + (imgp->args->argc + imgp->args->envc + 2);

AUXARGS_ENTRY_32(pos, LINUX_AT_SYSINFO_EHDR,
imgp->proc->p_sysent->sv_shared_page_base);
imgp->proc->p_shared_page_base);
AUXARGS_ENTRY_32(pos, LINUX_AT_SYSINFO, linux32_vsyscall);
AUXARGS_ENTRY_32(pos, LINUX_AT_HWCAP, cpu_feature);

@@ -2800,7 +2800,8 @@ freebsd32_copyout_strings(struct image_params *imgp)
execpath_len = 0;
arginfo = (struct freebsd32_ps_strings *)curproc->p_sysent->
sv_psstrings;
if (imgp->proc->p_sysent->sv_sigcode_base == 0)
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
szsigcode = 0;
@@ -1041,7 +1041,7 @@ linprocfs_doprocmaps(PFS_FILL_ARGS)
ino = vat.va_fileid;
vput(vp);
} else if (SV_PROC_ABI(p) == SV_ABI_LINUX) {
if (e_start == p->p_sysent->sv_shared_page_base)
if (e_start == p->p_shared_page_base)
name = vdso_str;
if (e_end == p->p_usrstack)
name = stack_str;
@@ -133,6 +133,10 @@ __FBSDID("$FreeBSD$");
#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 */

#ifndef PAX_ASLR_DELTA_EXEC_MIN_LEN
#define PAX_ASLR_DELTA_EXEC_MIN_LEN ((sizeof(void *) * NBBY) / 4)
#endif /* PAX_ASLR_DELTA_EXEC_MIN_LEN */
@@ -141,6 +145,14 @@ __FBSDID("$FreeBSD$");
#define PAX_ASLR_DELTA_EXEC_MAX_LEN (((sizeof(void *) * NBBY) * 2) / 3)
#endif /* PAX_ASLR_DELTA_EXEC_MAX_LEN */

#ifndef PAX_ASLR_DELTA_VDSO_MIN_LEN
#define PAX_ASLR_DELTA_VDSO_MIN_LEN 12
#endif /* PAX_ASLR_DELTA_VDSO_MIN_LEN */

#ifndef PAX_ASLR_DELTA_VDSO_MAX_LEN
#define PAX_ASLR_DELTA_VDSO_MAX_LEN 22
#endif /* PAX_ASLR_DELTA_VDSO_MAX_LEN */

/*
* ASLR default values for native host
*/
@@ -154,6 +166,9 @@ __FBSDID("$FreeBSD$");
#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 20
#endif /* PAX_ASLR_DELTA_VDSO_DEF_LEN */
#else /* ! __LP64__ */
#ifndef PAX_ASLR_DELTA_MMAP_DEF_LEN
#define PAX_ASLR_DELTA_MMAP_DEF_LEN 14
@@ -164,6 +179,9 @@ __FBSDID("$FreeBSD$");
#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__ */

/*
@@ -198,13 +216,25 @@ __FBSDID("$FreeBSD$");
#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_EXEC_MIN_LEN
#define PAX_ASLR_COMPAT_DELTA_EXEC_MIN_LEN ((sizeof(int) * NBBY) / 4)
#endif /* PAX_ASLR_COMPAT_DELTA_EXEC_MAX_LEN */

#ifndef PAX_ASLR_COMPAT_DELTA_EXEC_MAX_LEN
#define PAX_ASLR_COMPAT_DELTA_EXEC_MAX_LEN (((sizeof(int) * NBBY) * 2) / 3)
#endif /* PAX_ASLR_COMPAT_DELTA_EXEC_MAX_LEN */

#ifndef PAX_ASLR_COMPAT_DELTA_VDSO_MIN_LEN
#define PAX_ASLR_COMPAT_DELTA_VDSO_MIN_LEN 6
#endif /* PAX_ASLR_COMPAT_DELTA_VDSO_MAX_LEN */

#ifndef PAX_ASLR_COMPAT_DELTA_VDSO_MAX_LEN
#define PAX_ASLR_COMPAT_DELTA_VDSO_MAX_LEN 12
#endif /* PAX_ASLR_COMPAT_DELTA_VDSO_MAX_LEN */
#endif

FEATURE(aslr, "Address Space Layout Randomization.");
@@ -213,23 +243,27 @@ 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 COMPAT_FREEBSD32
static int pax_aslr_compat_status = PAX_FEATURE_OPTOUT;
static int pax_aslr_compat_mmap_len = PAX_ASLR_COMPAT_DELTA_MMAP_MIN_LEN;
static int pax_aslr_compat_stack_len = PAX_ASLR_COMPAT_DELTA_STACK_MIN_LEN;
static int pax_aslr_compat_exec_len = PAX_ASLR_COMPAT_DELTA_EXEC_MIN_LEN;
static int pax_aslr_compat_vdso_len = PAX_ASLR_COMPAT_DELTA_VDSO_MIN_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 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
@@ -242,7 +276,7 @@ static int sysctl_pax_aslr_status(SYSCTL_HANDLER_ARGS);
static int sysctl_pax_aslr_mmap(SYSCTL_HANDLER_ARGS);
static int sysctl_pax_aslr_stack(SYSCTL_HANDLER_ARGS);
static int sysctl_pax_aslr_exec(SYSCTL_HANDLER_ARGS);

static int sysctl_pax_aslr_vdso(SYSCTL_HANDLER_ARGS);

SYSCTL_NODE(_hardening_pax, OID_AUTO, aslr, CTLFLAG_RD, 0,
"Address Space Layout Randomization.");
@@ -274,6 +308,12 @@ SYSCTL_PROC(_hardening_pax_aslr, OID_AUTO, exec_len,
"Number of bits randomized for the PIE exec base. "
"32 bit: [6,20] 64 bit: [12,21]");

SYSCTL_PROC(_hardening_pax_aslr, OID_AUTO, vdso_len,
CTLTYPE_INT|CTLFLAG_RWTUN|CTLFLAG_PRISON|CTLFLAG_SECURE,
NULL, 0, sysctl_pax_aslr_vdso, "I",
"Number of bits randomized for the VDSO base. "
"32 bit: [6,20] 64 bit: [12,21]");

static int
sysctl_pax_aslr_status(SYSCTL_HANDLER_ARGS)
{
@@ -379,12 +419,38 @@ sysctl_pax_aslr_exec(SYSCTL_HANDLER_ARGS)
return (0);
}

static int
sysctl_pax_aslr_vdso(SYSCTL_HANDLER_ARGS)
{
struct prison *pr;
int err, val;

pr = pax_get_prison_td(req->td);

val = pr->pr_hardening.hr_pax_aslr_vdso_len;
err = sysctl_handle_int(oidp, &val, sizeof(int), req);
if (err || (req->newptr == NULL))
return (err);

if (val < PAX_ASLR_DELTA_VDSO_MIN_LEN ||
val > PAX_ASLR_DELTA_VDSO_MAX_LEN)
return (EINVAL);

if (pr == &prison0)
pax_aslr_vdso_len = val;

pr->pr_hardening.hr_pax_aslr_vdso_len = val;

return (0);
}

/* COMPAT_FREEBSD32 and linuxulator. */
#ifdef COMPAT_FREEBSD32
static int sysctl_pax_aslr_compat_status(SYSCTL_HANDLER_ARGS);
static int sysctl_pax_aslr_compat_mmap(SYSCTL_HANDLER_ARGS);
static int sysctl_pax_aslr_compat_stack(SYSCTL_HANDLER_ARGS);
static int sysctl_pax_aslr_compat_exec(SYSCTL_HANDLER_ARGS);
static int sysctl_pax_aslr_compat_vdso(SYSCTL_HANDLER_ARGS);

SYSCTL_NODE(_hardening_pax_aslr, OID_AUTO, compat, CTLFLAG_RD, 0,
"Setting for COMPAT_FREEBSD32 and linuxulator.");
@@ -416,6 +482,12 @@ SYSCTL_PROC(_hardening_pax_aslr_compat, OID_AUTO, exec_len,
"Number of bits randomized for the PIE exec base. "
"32 bit: [6,12]");

SYSCTL_PROC(_hardening_pax_aslr_compat, OID_AUTO, vdso_len,
CTLTYPE_INT|CTLFLAG_RWTUN|CTLFLAG_PRISON,
NULL, 0, sysctl_pax_aslr_compat_vdso, "I",
"Number of bits randomized for the VDSO base. "
"32 bit: [6,12]");

static int
sysctl_pax_aslr_compat_status(SYSCTL_HANDLER_ARGS)
{
@@ -521,6 +593,31 @@ sysctl_pax_aslr_compat_exec(SYSCTL_HANDLER_ARGS)
return (0);
}

static int
sysctl_pax_aslr_compat_vdso(SYSCTL_HANDLER_ARGS)
{
struct prison *pr;
int err, val;

pr = pax_get_prison_td(req->td);

val = pr->pr_hardening.hr_pax_aslr_compat_vdso_len;
err = sysctl_handle_int(oidp, &val, sizeof(int), req);
if (err || !req->newptr)
return (err);

if (val < PAX_ASLR_COMPAT_DELTA_VDSO_MIN_LEN ||
val > PAX_ASLR_COMPAT_DELTA_VDSO_MAX_LEN)
return (EINVAL);

if (pr == &prison0)
pax_aslr_compat_vdso_len = val;

pr->pr_hardening.hr_pax_aslr_compat_vdso_len = val;

return (0);
}

#endif /* COMPAT_FREEBSD32 */
#endif /* PAX_SYSCTLS */

@@ -549,6 +646,7 @@ 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] vdso: %d bit\n", pax_aslr_vdso_len);
}
SYSINIT(pax_aslr, SI_SUB_PAX, SI_ORDER_SECOND, pax_aslr_sysinit, NULL);

@@ -598,12 +696,19 @@ pax_aslr_init_vmspace(struct proc *p)
PAX_ASLR_DELTA_EXEC_LSB,
pr->pr_hardening.hr_pax_aslr_exec_len);

arc4rand(&rand_buf, sizeof(rand_buf), 0);
vm->vm_aslr_delta_vdso = PAX_ASLR_DELTA(rand_buf,
PAX_ASLR_DELTA_VDSO_LSB,
pr->pr_hardening.hr_pax_aslr_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);
}

#ifdef COMPAT_FREEBSD32
@@ -627,6 +732,7 @@ pax_compat_aslr_sysinit(void)
printf("[PAX ASLR (compat)] mmap: %d bit\n", pax_aslr_compat_mmap_len);
printf("[PAX ASLR (compat)] exec base: %d bit\n", pax_aslr_compat_exec_len);
printf("[PAX ASLR (compat)] stack: %d bit\n", pax_aslr_compat_stack_len);
printf("[PAX 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);

@@ -657,12 +763,19 @@ pax_aslr_init_vmspace32(struct proc *p)
PAX_ASLR_COMPAT_DELTA_EXEC_LSB,
pr->pr_hardening.hr_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,
pr->pr_hardening.hr_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

@@ -698,6 +811,8 @@ pax_aslr_init_prison(struct prison *pr)
pax_aslr_stack_len;
pr->pr_hardening.hr_pax_aslr_exec_len =
pax_aslr_exec_len;
pr->pr_hardening.hr_pax_aslr_vdso_len =
pax_aslr_vdso_len;
} else {
KASSERT(pr->pr_parent != NULL,
("%s: pr->pr_parent == NULL", __func__));
@@ -711,6 +826,8 @@ pax_aslr_init_prison(struct prison *pr)
pr_p->pr_hardening.hr_pax_aslr_stack_len;
pr->pr_hardening.hr_pax_aslr_exec_len =
pr_p->pr_hardening.hr_pax_aslr_exec_len;
pr->pr_hardening.hr_pax_aslr_vdso_len =
pr_p->pr_hardening.hr_pax_aslr_vdso_len;
}
}

@@ -734,6 +851,8 @@ pax_aslr_init_prison32(struct prison *pr)
pax_aslr_compat_stack_len;
pr->pr_hardening.hr_pax_aslr_compat_exec_len =
pax_aslr_compat_exec_len;
pr->pr_hardening.hr_pax_aslr_compat_vdso_len =
pax_aslr_compat_vdso_len;
} else {
KASSERT(pr->pr_parent != NULL,
("%s: pr->pr_parent == NULL", __func__));
@@ -747,6 +866,8 @@ pax_aslr_init_prison32(struct prison *pr)
pr_p->pr_hardening.hr_pax_aslr_compat_stack_len;
pr->pr_hardening.hr_pax_aslr_compat_exec_len =
pr_p->pr_hardening.hr_pax_aslr_compat_exec_len;
pr->pr_hardening.hr_pax_aslr_compat_vdso_len =
pr_p->pr_hardening.hr_pax_aslr_compat_vdso_len;
}
}
#endif /* COMPAT_FREEBSD32 */
@@ -906,6 +1027,21 @@ pax_aslr_execbase(struct proc *p, u_long *et_dyn_addrp)
*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);
}

uint32_t
pax_aslr_setup_flags(struct image_params *imgp, uint32_t mode)
{

0 comments on commit 951a6ca

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