diff options
author | Patrick Mooney <pmooney@pfmooney.com> | 2017-08-03 18:19:56 +0000 |
---|---|---|
committer | Robert Mustacchi <rm@joyent.com> | 2018-07-19 18:08:35 +0000 |
commit | 284ce987a33170d916c005f044ef6ce9ce8e1517 (patch) | |
tree | 43a616d339bc30b3d6f946b06804a6e53df6c527 /usr/src/uts/common/os/exec.c | |
parent | 4b9a859a90a27a1aaf064cac9a4fa96bcca57337 (diff) | |
download | illumos-joyent-284ce987a33170d916c005f044ef6ce9ce8e1517.tar.gz |
9641 want stack-clash mitigation
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
Reviewed by: Alex Wilson <alex.wilson@joyent.com>
Reviewed by: Mike Gerdts <mike.gerdts@joyent.com>
Reviewed by: Toomas Soome <tsoome@me.com>
Approved by: Robert Mustacchi <rm@joyent.com>
Diffstat (limited to 'usr/src/uts/common/os/exec.c')
-rw-r--r-- | usr/src/uts/common/os/exec.c | 62 |
1 files changed, 58 insertions, 4 deletions
diff --git a/usr/src/uts/common/os/exec.c b/usr/src/uts/common/os/exec.c index 0065b4945b..53c552f135 100644 --- a/usr/src/uts/common/os/exec.c +++ b/usr/src/uts/common/os/exec.c @@ -26,7 +26,7 @@ /* Copyright (c) 1988 AT&T */ /* All Rights Reserved */ /* - * Copyright 2016 Joyent, Inc. + * Copyright 2017 Joyent, Inc. */ #include <sys/types.h> @@ -78,6 +78,7 @@ #include <vm/as.h> #include <vm/seg.h> #include <vm/seg_vn.h> +#include <vm/seg_hole.h> #define PRIV_RESET 0x01 /* needs to reset privs */ #define PRIV_SETID 0x02 /* needs to change uids */ @@ -115,6 +116,14 @@ size_t aslr_max_brk_skew = 16 * 1024 * 1024; /* 16MB */ size_t aslr_max_stack_skew = 64 * 1024; /* 64KB */ /* + * Size of guard segment for 64-bit processes and minimum size it can be shrunk + * to in the case of grow() operations. These are kept as variables in case + * they need to be tuned in an emergency. + */ +size_t stack_guard_seg_sz = 256 * 1024 * 1024; +size_t stack_guard_min_sz = 64 * 1024 * 1024; + +/* * exece() - system call wrapper around exec_common() */ int @@ -1858,6 +1867,15 @@ exec_get_spslew(void) * The initial user stack layout is as follows: * * User Stack + * +---------------+ + * | | + * | stack guard | + * | (64-bit only) | + * | | + * +...............+ <--- stack limit (base - curproc->p_stk_ctl) + * . . + * . . + * . . * +---------------+ <--- curproc->p_usrstack * | | * | slew | @@ -1899,6 +1917,11 @@ exec_get_spslew(void) * +---------------+ <--- argv[] * | argc | * +---------------+ <--- stack base + * + * In 64-bit processes, a stack guard segment is allocated at the address + * immediately below where the stack limit ends. This protects new library + * mappings (such as the linker) from being placed in relatively dangerous + * proximity to the stack. */ int exec_args(execa_t *uap, uarg_t *args, intpdata_t *intp, void **auxvpp) @@ -1912,6 +1935,9 @@ exec_args(execa_t *uap, uarg_t *args, intpdata_t *intp, void **auxvpp) struct as *as; extern int use_stk_lpg; size_t sp_slew; +#if defined(_LP64) + const size_t sg_sz = (stack_guard_seg_sz & PAGEMASK); +#endif /* defined(_LP64) */ args->from_model = p->p_model; if (p->p_model == DATAMODEL_NATIVE) { @@ -2060,6 +2086,8 @@ exec_args(execa_t *uap, uarg_t *args, intpdata_t *intp, void **auxvpp) p->p_brkpageszc = 0; p->p_stksize = 0; p->p_stkpageszc = 0; + p->p_stkg_start = 0; + p->p_stkg_end = 0; p->p_model = args->to_model; p->p_usrstack = usrstack; p->p_stkprot = args->stk_prot; @@ -2097,10 +2125,36 @@ exec_args(execa_t *uap, uarg_t *args, intpdata_t *intp, void **auxvpp) (void) hat_setup(as->a_hat, HAT_ALLOC); hat_join_srd(as->a_hat, args->ex_vp); - /* - * Finally, write out the contents of the new stack. - */ + /* Write out the contents of the new stack. */ error = stk_copyout(args, usrstack - sp_slew, auxvpp, up); kmem_free(args->stk_base, args->stk_size); + +#if defined(_LP64) + /* Add stack guard segment (if needed) after successful copyout */ + if (error == 0 && p->p_model == DATAMODEL_LP64 && sg_sz != 0) { + seghole_crargs_t sca; + caddr_t addr_end = (caddr_t)(((uintptr_t)usrstack - + p->p_stk_ctl) & PAGEMASK); + caddr_t addr_start = addr_end - sg_sz; + + DTRACE_PROBE4(stack__guard__chk, proc_t *, p, + caddr_t, addr_start, caddr_t, addr_end, size_t, sg_sz); + + if (addr_end >= usrstack || addr_start >= addr_end || + valid_usr_range(addr_start, sg_sz, PROT_NONE, as, + as->a_userlimit) != RANGE_OKAY) { + return (E2BIG); + } + + /* Create un-mappable area in AS with seg_hole */ + sca.name = "stack_guard"; + error = as_map(as, addr_start, sg_sz, seghole_create, &sca); + if (error == 0) { + p->p_stkg_start = (uintptr_t)addr_start; + p->p_stkg_end = (uintptr_t)addr_start + sg_sz; + } + } +#endif /* defined(_LP64) */ + return (error); } |