summaryrefslogtreecommitdiff
path: root/usr/src/uts/common/os/exec.c
diff options
context:
space:
mode:
authorJerry Jelinek <jerry.jelinek@joyent.com>2016-10-17 13:02:40 +0000
committerJerry Jelinek <jerry.jelinek@joyent.com>2016-10-17 13:02:40 +0000
commit59a59b276f274cff7e883bcc3e10c162cfb3a263 (patch)
tree59b25df56be42eb7c8aae7cb02d6f1d39ec61b15 /usr/src/uts/common/os/exec.c
parent8259b03da3b4ab815c3b6180f813fcfd57984470 (diff)
parentd2a70789f056fc6c9ce3ab047b52126d80b0e3da (diff)
downloadillumos-joyent-59a59b276f274cff7e883bcc3e10c162cfb3a263.tar.gz
[illumos-gate merge]
commit d2a70789f056fc6c9ce3ab047b52126d80b0e3da 7029 want per-process exploit mitigation features (secflags) 7030 want basic address space layout randomization (ASLR) 7031 noexec_user_stack should be a security-flag 7032 want a means to forbid mappings around NULL commit 8ab1c3f559468e655c4eb8acce993320403dd72b 7469 loader should use acpica provided by OS commit a1964bdd47804c37e09db1a79c23937c9aeac165 7470 acpi build sometimes doesn't descend into SUBDIRS commit abf99a006172ea5aab2246bda23f9d6d935bf1ad 7420 signalfd deadlock on pollwakeup 7421 panic in signalfd Conflicts: usr/src/cmd/sgs/libconv/common/corenote.c usr/src/cmd/zonecfg/zonecfg.c usr/src/cmd/zonecfg/zonecfg.h usr/src/cmd/zonecfg/zonecfg_grammar.y usr/src/cmd/zonecfg/zonecfg_lex.l usr/src/head/libzonecfg.h usr/src/lib/libzonecfg/common/libzonecfg.c usr/src/man/man1m/zonecfg.1m usr/src/man/man4/proc.4 usr/src/pkg/manifests/system-test-ostest.mf usr/src/test/os-tests/tests/Makefile usr/src/uts/common/exec/elf/elf.c usr/src/uts/common/io/signalfd.c usr/src/uts/common/os/sysent.c usr/src/uts/common/os/zone.c usr/src/uts/common/sys/proc.h usr/src/uts/common/sys/zone.h
Diffstat (limited to 'usr/src/uts/common/os/exec.c')
-rw-r--r--usr/src/uts/common/os/exec.c83
1 files changed, 71 insertions, 12 deletions
diff --git a/usr/src/uts/common/os/exec.c b/usr/src/uts/common/os/exec.c
index d46b8538a9..c9fb160831 100644
--- a/usr/src/uts/common/os/exec.c
+++ b/usr/src/uts/common/os/exec.c
@@ -101,6 +101,21 @@ uint_t auxv_hwcap32_2 = 0; /* 32-bit version of auxv_hwcap2 */
#define RANDOM_LEN 16 /* 16 bytes for AT_RANDOM aux entry */
/*
+ * These are consumed within the specific exec modules, but are defined here
+ * because
+ *
+ * 1) The exec modules are unloadable, which would make this near useless.
+ *
+ * 2) We want them to be common across all of them, should more than ELF come
+ * to support them.
+ *
+ * All must be powers of 2.
+ */
+size_t aslr_max_brk_skew = 16 * 1024 * 1024; /* 16MB */
+#pragma weak exec_stackgap = aslr_max_stack_skew /* Old, compatible name */
+size_t aslr_max_stack_skew = 64 * 1024; /* 64KB */
+
+/*
* exece() - system call wrapper around exec_common()
*/
int
@@ -595,6 +610,9 @@ gexec(
int privflags = 0;
int setidfl;
priv_set_t fset;
+ secflagset_t old_secflags;
+
+ secflags_copy(&old_secflags, &pp->p_secflags.psf_effective);
/*
* If the SNOCD or SUGID flag is set, turn it off and remember the
@@ -695,6 +713,9 @@ gexec(
priv_adjust_PA(cred);
}
+ /* The new image gets the inheritable secflags as its secflags */
+ secflags_promote(pp);
+
/* SunOS 4.x buy-back */
if ((vp->v_vfsp->vfs_flag & VFS_NOSETUID) &&
(vattr.va_mode & (VSUID|VSGID))) {
@@ -755,7 +776,8 @@ gexec(
* Use /etc/system variable to determine if the stack
* should be marked as executable by default.
*/
- if (noexec_user_stack)
+ if ((noexec_user_stack != 0) ||
+ secflag_enabled(pp, PROC_SEC_NOEXECSTACK))
args->stk_prot &= ~PROT_EXEC;
args->execswp = eswp; /* Save execsw pointer in uarg for exec_func */
@@ -917,11 +939,17 @@ bad_noclose:
if (error == 0)
error = ENOEXEC;
+ mutex_enter(&pp->p_lock);
if (suidflags) {
- mutex_enter(&pp->p_lock);
pp->p_flag |= suidflags;
- mutex_exit(&pp->p_lock);
}
+ /*
+ * Restore the effective secflags, to maintain the invariant they
+ * never change for a given process
+ */
+ secflags_copy(&pp->p_secflags.psf_effective, &old_secflags);
+ mutex_exit(&pp->p_lock);
+
return (error);
}
@@ -1875,6 +1903,44 @@ stk_copyout(uarg_t *args, char *usrstack, void **auxvpp, user_t *up)
}
/*
+ * Though the actual stack base is constant, slew the %sp by a random aligned
+ * amount in [0,aslr_max_stack_skew). Mostly, this makes life slightly more
+ * complicated for buffer overflows hoping to overwrite the return address.
+ *
+ * On some platforms this helps avoid cache thrashing when identical processes
+ * simultaneously share caches that don't provide enough associativity
+ * (e.g. sun4v systems). In this case stack slewing makes the same hot stack
+ * variables in different processes live in different cache sets increasing
+ * effective associativity.
+ */
+size_t
+exec_get_spslew(void)
+{
+#ifdef sun4v
+ static uint_t sp_color_stride = 16;
+ static uint_t sp_color_mask = 0x1f;
+ static uint_t sp_current_color = (uint_t)-1;
+#endif
+ size_t off;
+
+ ASSERT(ISP2(aslr_max_stack_skew));
+
+ if ((aslr_max_stack_skew == 0) ||
+ !secflag_enabled(curproc, PROC_SEC_ASLR)) {
+#ifdef sun4v
+ uint_t spcolor = atomic_inc_32_nv(&sp_current_color);
+ return ((size_t)((spcolor & sp_color_mask) *
+ SA(sp_color_stride)));
+#else
+ return (0);
+#endif
+ }
+
+ (void) random_get_pseudo_bytes((uint8_t *)&off, sizeof (off));
+ return (SA(P2PHASE(off, aslr_max_stack_skew)));
+}
+
+/*
* Initialize a new user stack with the specified arguments and environment.
* The initial user stack layout is as follows:
*
@@ -2107,17 +2173,10 @@ exec_args(execa_t *uap, uarg_t *args, intpdata_t *intp, void **auxvpp)
p->p_flag |= SAUTOLPG; /* kernel controls page sizes */
mutex_exit(&p->p_lock);
- /*
- * Some platforms may choose to randomize real stack start by adding a
- * small slew (not more than a few hundred bytes) to the top of the
- * stack. This helps avoid cache thrashing when identical processes
- * simultaneously share caches that don't provide enough associativity
- * (e.g. sun4v systems). In this case stack slewing makes the same hot
- * stack variables in different processes to live in different cache
- * sets increasing effective associativity.
- */
sp_slew = exec_get_spslew();
ASSERT(P2PHASE(sp_slew, args->stk_align) == 0);
+ /* Be certain we don't underflow */
+ VERIFY((curproc->p_usrstack - (size + sp_slew)) < curproc->p_usrstack);
exec_set_sp(size + sp_slew);
as = as_alloc();