--- old/usr/src/uts/common/exec/elf/elf.c	2015-05-27 19:46:57.010844778 -0400
+++ new/usr/src/uts/common/exec/elf/elf.c	2015-05-27 19:46:57.022843513 -0400
@@ -65,8 +65,10 @@
 #include "elf_impl.h"
 #include <sys/sdt.h>
 #include <sys/siginfo.h>
+#include <sys/random.h>
 
 extern int at_flags;
+extern volatile size_t aslr_max_brk_skew;
 
 #define	ORIGIN_STR	"ORIGIN"
 #define	ORIGIN_STR_SIZE	6
@@ -255,7 +257,8 @@
 	ssize_t		resid;
 	int		fd = -1;
 	intptr_t	voffset;
-	Phdr		*dyphdr = NULL;
+	Phdr		*intphdr = NULL;
+	Phdr		*dynamicphdr = NULL;
 	Phdr		*stphdr = NULL;
 	Phdr		*uphdr = NULL;
 	Phdr		*junk = NULL;
@@ -269,9 +272,11 @@
 	Phdr		*capphdr = NULL;
 	Cap		*cap = NULL;
 	ssize_t		capsize;
+	Dyn		*dyn = NULL;
+	ssize_t		dynsize;
 	int		hasu = 0;
 	int		hasauxv = 0;
-	int		hasdy = 0;
+	int		hasintp = 0;
 	int		branded = 0;
 
 	struct proc *p = ttoproc(curthread);
@@ -364,7 +369,7 @@
 	for (i = nphdrs; i > 0; i--) {
 		switch (phdrp->p_type) {
 		case PT_INTERP:
-			hasauxv = hasdy = 1;
+			hasauxv = hasintp = 1;
 			break;
 		case PT_PHDR:
 			hasu = 1;
@@ -384,6 +389,9 @@
 		case PT_SUNWCAP:
 			capphdr = phdrp;
 			break;
+		case PT_DYNAMIC:
+			dynamicphdr = phdrp;
+			break;
 		}
 		phdrp = (Phdr *)((caddr_t)phdrp + hsize);
 	}
@@ -420,13 +428,14 @@
 		 *	AT_SUN_AUXFLAGS
 		 *	AT_SUN_HWCAP
 		 *	AT_SUN_HWCAP2
+		 *	AT_SUN_SECFLAGS
 		 *	AT_SUN_PLATFORM (added in stk_copyout)
 		 *	AT_SUN_EXECNAME (added in stk_copyout)
 		 *	AT_NULL
 		 *
-		 * total == 9
+		 * total == 10
 		 */
-		if (hasdy && hasu) {
+		if (hasintp && hasu) {
 			/*
 			 * Has PT_INTERP & PT_PHDR - the auxvectors that
 			 * will be built are:
@@ -439,8 +448,8 @@
 			 *
 			 * total = 5
 			 */
-			args->auxsize = (9 + 5) * sizeof (aux_entry_t);
-		} else if (hasdy) {
+			args->auxsize = (10 + 5) * sizeof (aux_entry_t);
+		} else if (hasintp) {
 			/*
 			 * Has PT_INTERP but no PT_PHDR
 			 *
@@ -449,9 +458,9 @@
 			 *
 			 * total = 2
 			 */
-			args->auxsize = (9 + 2) * sizeof (aux_entry_t);
+			args->auxsize = (10 + 2) * sizeof (aux_entry_t);
 		} else {
-			args->auxsize = 9 * sizeof (aux_entry_t);
+			args->auxsize = 10 * sizeof (aux_entry_t);
 		}
 	} else {
 		args->auxsize = 0;
@@ -473,6 +482,44 @@
 		args->auxsize += 4 * sizeof (aux_entry_t);
 	}
 
+	/* If the binary has an explicit ASLR flag, it must be honoured */
+	if (dynamicphdr != NULL) {
+		Dyn *dp;
+
+		dynsize = dynamicphdr->p_filesz;
+		dyn = kmem_alloc(dynsize, KM_SLEEP);
+
+		if ((error = vn_rdwr(UIO_READ, vp, (caddr_t)dyn, dynsize,
+		    (offset_t)dynamicphdr->p_offset, UIO_SYSSPACE, 0, (rlim64_t)0,
+		    CRED(), &resid)) != 0) {
+			uprintf("%s: cannot read .dynamic section\n",
+			    exec_file);
+			goto out;
+		}
+
+		if (resid != 0)
+			goto out;
+
+		dp = dyn;
+		while (dp->d_tag != DT_NULL) {
+			if (dp->d_tag == DT_SUNW_ASLR) {
+				if (dp->d_un.d_val != 0) {
+					curproc->p_secflags.psf_effective |=
+					    PROC_SEC_ASLR;
+					curproc->p_secflags.psf_inherit |=
+					    PROC_SEC_ASLR;
+
+				} else {
+					curproc->p_secflags.psf_effective &=
+					    ~PROC_SEC_ASLR;
+					curproc->p_secflags.psf_inherit &=
+					    ~PROC_SEC_ASLR;
+				}
+			}
+			dp++;
+		}
+	}
+
 	/* Hardware/Software capabilities */
 	if (capphdr != NULL &&
 	    (capsize = capphdr->p_filesz) > 0 &&
@@ -523,12 +570,12 @@
 
 	dtrphdr = NULL;
 
-	if ((error = mapelfexec(vp, ehdrp, nphdrs, phdrbase, &uphdr, &dyphdr,
+	if ((error = mapelfexec(vp, ehdrp, nphdrs, phdrbase, &uphdr, &intphdr,
 	    &stphdr, &dtrphdr, dataphdrp, &bssbase, &brkbase, &voffset, NULL,
 	    len, execsz, &brksize)) != 0)
 		goto bad;
 
-	if (uphdr != NULL && dyphdr == NULL)
+	if (uphdr != NULL && intphdr == NULL)
 		goto bad;
 
 	if (dtrphdr != NULL && dtrace_safe_phdr(dtrphdr, args, voffset) != 0) {
@@ -536,13 +583,13 @@
 		goto bad;
 	}
 
-	if (dyphdr != NULL) {
+	if (intphdr != NULL) {
 		size_t		len;
 		uintptr_t	lddata;
 		char		*p;
 		struct vnode	*nvp;
 
-		dlnsize = dyphdr->p_filesz;
+		dlnsize = intphdr->p_filesz;
 
 		if (dlnsize > MAXPATHLEN || dlnsize <= 0)
 			goto bad;
@@ -550,8 +597,8 @@
 		/*
 		 * Read in "interpreter" pathname.
 		 */
-		if ((error = vn_rdwr(UIO_READ, vp, dlnp, dyphdr->p_filesz,
-		    (offset_t)dyphdr->p_offset, UIO_SYSSPACE, 0, (rlim64_t)0,
+		if ((error = vn_rdwr(UIO_READ, vp, dlnp, intphdr->p_filesz,
+		    (offset_t)intphdr->p_offset, UIO_SYSSPACE, 0, (rlim64_t)0,
 		    CRED(), &resid)) != 0) {
 			uprintf("%s: Cannot obtain interpreter pathname\n",
 			    exec_file);
@@ -760,6 +807,13 @@
 		    ((char *)&aux->a_type -
 		    (char *)bigwad->elfargs));
 		ADDAUX(aux, AT_SUN_AUXFLAGS, auxf);
+
+		/*
+		 * Put the effective security-flags into the aux vector, for
+		 * the sake of flags that need partial (or complete)
+		 * implementation in userland.
+		 */
+		ADDAUX(aux, AT_SUN_SECFLAGS, p->p_secflags.psf_effective);
 		/*
 		 * Hardware capability flag word (performance hints)
 		 * Used for choosing faster library routines.
@@ -900,6 +954,8 @@
 		kmem_free(phdrbase, phdrsize);
 	if (cap != NULL)
 		kmem_free(cap, capsize);
+	if (dyn != NULL)
+		kmem_free(dyn, dynsize);
 	kmem_free(bigwad, sizeof (struct bigwad));
 	return (error);
 }
@@ -1169,7 +1225,7 @@
 	int nphdrs,
 	caddr_t phdrbase,
 	Phdr **uphdr,
-	Phdr **dyphdr,
+	Phdr **intphdr,
 	Phdr **stphdr,
 	Phdr **dtphdr,
 	Phdr *dataphdrp,
@@ -1193,11 +1249,15 @@
 	extern int use_brk_lpg;
 
 	if (ehdr->e_type == ET_DYN) {
+		uint_t flags = 0;
 		/*
 		 * Obtain the virtual address of a hole in the
 		 * address space to map the "interpreter".
 		 */
-		map_addr(&addr, len, (offset_t)0, 1, 0);
+		if (secflag_enabled(curproc, PROC_SEC_ASLR))
+			flags |= _MAP_RANDOMIZE;
+
+		map_addr(&addr, len, (offset_t)0, 1, flags);
 		if (addr == NULL)
 			return (ENOMEM);
 		*voffset = (intptr_t)addr;
@@ -1224,7 +1284,7 @@
 	for (i = nphdrs; i > 0; i--) {
 		switch (phdr->p_type) {
 		case PT_LOAD:
-			if ((*dyphdr != NULL) && (*uphdr == NULL))
+			if ((*intphdr != NULL) && (*uphdr == NULL))
 				return (0);
 
 			ptload = 1;
@@ -1279,6 +1339,13 @@
 				uint_t	szc = curproc->p_brkpageszc;
 				size_t pgsz = page_get_pagesize(szc);
 				caddr_t ebss = addr + phdr->p_memsz;
+				/*
+				 * If we need extra space to keep the BSS an
+				 * integral number of pages in size, some of
+				 * that space may fall beyond p_brkbase, so we
+				 * need to set p_brksize to account for it
+				 * being (logically) part of the brk.
+				 */
 				size_t extra_zfodsz;
 
 				ASSERT(pgsz > PAGESIZE);
@@ -1311,7 +1378,7 @@
 		case PT_INTERP:
 			if (ptload)
 				goto bad;
-			*dyphdr = phdr;
+			*intphdr = phdr;
 			break;
 
 		case PT_SHLIB:
@@ -1345,6 +1412,31 @@
 		*minaddr = (intptr_t)mintmp;
 	}
 
+	if (brkbase != NULL && secflag_enabled(curproc, PROC_SEC_ASLR)) {
+		size_t off;
+		uintptr_t base = (uintptr_t)*brkbase;
+		uintptr_t oend = base + *brksize;
+
+		ASSERT(ISP2(aslr_max_brk_skew));
+
+		(void) random_get_pseudo_bytes((uint8_t *)&off, sizeof (off));
+		base += P2PHASE(off, aslr_max_brk_skew);
+		base = P2ROUNDUP(base, PAGESIZE);
+		*brkbase = (caddr_t)base;
+		/*
+		 * Above, we set *brksize to account for the possibility we
+		 * had to grow the 'brk' in padding out the BSS to a page
+		 * boundary.
+		 *
+		 * We now need to adjust that based on where we now are
+		 * actually putting the brk.
+		 */
+		if (oend > base)
+			*brksize = oend - base;
+		else
+			*brksize = 0;
+	}
+
 	return (0);
 bad:
 	if (error == 0)
