xref: /illumos-gate/usr/src/uts/common/exec/elf/elf.c (revision 6233c8a8)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5ab9a77c7Sahl  * Common Development and Distribution License (the "License").
6ab9a77c7Sahl  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
21ab9a77c7Sahl 
227c478bd9Sstevel@tonic-gate /*
231022fd2aS  * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
27bc0adaffSPeter Tribble /*	   All Rights Reserved	*/
28ebb8ac07SRobert Mustacchi /*
294e18e297SPatrick Mooney  * Copyright 2019, Joyent, Inc.
30*6233c8a8SAndy Fiddaman  * Copyright 2023 Oxide Computer Company
31ebb8ac07SRobert Mustacchi  */
327c478bd9Sstevel@tonic-gate 
337c478bd9Sstevel@tonic-gate #include <sys/types.h>
347c478bd9Sstevel@tonic-gate #include <sys/param.h>
357c478bd9Sstevel@tonic-gate #include <sys/thread.h>
367c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
377c478bd9Sstevel@tonic-gate #include <sys/signal.h>
387c478bd9Sstevel@tonic-gate #include <sys/cred.h>
397c478bd9Sstevel@tonic-gate #include <sys/user.h>
407c478bd9Sstevel@tonic-gate #include <sys/errno.h>
417c478bd9Sstevel@tonic-gate #include <sys/vnode.h>
427c478bd9Sstevel@tonic-gate #include <sys/mman.h>
437c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
447c478bd9Sstevel@tonic-gate #include <sys/proc.h>
457c478bd9Sstevel@tonic-gate #include <sys/pathname.h>
46d2a70789SRichard Lowe #include <sys/policy.h>
477c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
487c478bd9Sstevel@tonic-gate #include <sys/systm.h>
497c478bd9Sstevel@tonic-gate #include <sys/elf.h>
507c478bd9Sstevel@tonic-gate #include <sys/vmsystm.h>
517c478bd9Sstevel@tonic-gate #include <sys/debug.h>
527c478bd9Sstevel@tonic-gate #include <sys/auxv.h>
537c478bd9Sstevel@tonic-gate #include <sys/exec.h>
547c478bd9Sstevel@tonic-gate #include <sys/prsystm.h>
557c478bd9Sstevel@tonic-gate #include <vm/as.h>
567c478bd9Sstevel@tonic-gate #include <vm/rm.h>
577c478bd9Sstevel@tonic-gate #include <vm/seg.h>
587c478bd9Sstevel@tonic-gate #include <vm/seg_vn.h>
597c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
607c478bd9Sstevel@tonic-gate #include <sys/systeminfo.h>
617c478bd9Sstevel@tonic-gate #include <sys/vmparam.h>
627c478bd9Sstevel@tonic-gate #include <sys/machelf.h>
637c478bd9Sstevel@tonic-gate #include <sys/shm_impl.h>
647c478bd9Sstevel@tonic-gate #include <sys/archsystm.h>
657c478bd9Sstevel@tonic-gate #include <sys/fasttrap.h>
669acbbeafSnn #include <sys/brand.h>
677c478bd9Sstevel@tonic-gate #include "elf_impl.h"
689acbbeafSnn #include <sys/sdt.h>
69f971a346SBryan Cantrill #include <sys/siginfo.h>
70d2a70789SRichard Lowe #include <sys/random.h>
719acbbeafSnn 
728e458de0SRobert Mustacchi #include <core_shstrtab.h>
738e458de0SRobert Mustacchi 
742428aad8SPatrick Mooney #if defined(__x86)
752428aad8SPatrick Mooney #include <sys/comm_page_util.h>
76d0158222SRobert Mustacchi #include <sys/fp.h>
772428aad8SPatrick Mooney #endif /* defined(__x86) */
782428aad8SPatrick Mooney 
792428aad8SPatrick Mooney 
807c478bd9Sstevel@tonic-gate extern int at_flags;
81d2a70789SRichard Lowe extern volatile size_t aslr_max_brk_skew;
827c478bd9Sstevel@tonic-gate 
837c478bd9Sstevel@tonic-gate #define	ORIGIN_STR	"ORIGIN"
847c478bd9Sstevel@tonic-gate #define	ORIGIN_STR_SIZE	6
857c478bd9Sstevel@tonic-gate 
864e18e297SPatrick Mooney static int getelfhead(vnode_t *, cred_t *, Ehdr *, uint_t *, uint_t *,
874e18e297SPatrick Mooney     uint_t *);
884e18e297SPatrick Mooney static int getelfphdr(vnode_t *, cred_t *, const Ehdr *, uint_t, caddr_t *,
894e18e297SPatrick Mooney     size_t *);
904e18e297SPatrick Mooney static int getelfshdr(vnode_t *, cred_t *, const Ehdr *, uint_t, uint_t,
914e18e297SPatrick Mooney     caddr_t *, size_t *, caddr_t *, size_t *);
924e18e297SPatrick Mooney static size_t elfsize(const Ehdr *, uint_t, const caddr_t, uintptr_t *);
934e18e297SPatrick Mooney static int mapelfexec(vnode_t *, Ehdr *, uint_t, caddr_t, Phdr **, Phdr **,
944e18e297SPatrick Mooney     Phdr **, Phdr **, Phdr *, caddr_t *, caddr_t *, intptr_t *, uintptr_t *,
954e18e297SPatrick Mooney     size_t, size_t *, size_t *);
964e18e297SPatrick Mooney 
974e18e297SPatrick Mooney 
984e18e297SPatrick Mooney #ifdef _ELF32_COMPAT
994e18e297SPatrick Mooney /* Link against the non-compat instances when compiling the 32-bit version. */
1004e18e297SPatrick Mooney extern size_t elf_datasz_max;
1014e18e297SPatrick Mooney extern size_t elf_zeropg_sz;
1024e18e297SPatrick Mooney extern void elf_ctx_resize_scratch(elf_core_ctx_t *, size_t);
1034e18e297SPatrick Mooney extern uint_t elf_nphdr_max;
1044e18e297SPatrick Mooney extern uint_t elf_nshdr_max;
1054e18e297SPatrick Mooney extern size_t elf_shstrtab_max;
1064e18e297SPatrick Mooney #else
1074e18e297SPatrick Mooney size_t elf_datasz_max = 1 * 1024 * 1024;
1084e18e297SPatrick Mooney size_t elf_zeropg_sz = 4 * 1024;
1094e18e297SPatrick Mooney uint_t elf_nphdr_max = 1000;
1104e18e297SPatrick Mooney uint_t elf_nshdr_max = 10000;
1114e18e297SPatrick Mooney size_t elf_shstrtab_max = 100 * 1024;
1124e18e297SPatrick Mooney #endif
1137c478bd9Sstevel@tonic-gate 
1147c478bd9Sstevel@tonic-gate static int
dtrace_safe_phdr(Phdr * phdrp,struct uarg * args,uintptr_t base)1157c478bd9Sstevel@tonic-gate dtrace_safe_phdr(Phdr *phdrp, struct uarg *args, uintptr_t base)
1167c478bd9Sstevel@tonic-gate {
1177c478bd9Sstevel@tonic-gate 	ASSERT(phdrp->p_type == PT_SUNWDTRACE);
1187c478bd9Sstevel@tonic-gate 
1197c478bd9Sstevel@tonic-gate 	/*
1207c478bd9Sstevel@tonic-gate 	 * See the comment in fasttrap.h for information on how to safely
1217c478bd9Sstevel@tonic-gate 	 * update this program header.
1227c478bd9Sstevel@tonic-gate 	 */
1237c478bd9Sstevel@tonic-gate 	if (phdrp->p_memsz < PT_SUNWDTRACE_SIZE ||
1247c478bd9Sstevel@tonic-gate 	    (phdrp->p_flags & (PF_R | PF_W | PF_X)) != (PF_R | PF_W | PF_X))
1257c478bd9Sstevel@tonic-gate 		return (-1);
1267c478bd9Sstevel@tonic-gate 
1277c478bd9Sstevel@tonic-gate 	args->thrptr = phdrp->p_vaddr + base;
1287c478bd9Sstevel@tonic-gate 
1297c478bd9Sstevel@tonic-gate 	return (0);
1307c478bd9Sstevel@tonic-gate }
1317c478bd9Sstevel@tonic-gate 
132d2a70789SRichard Lowe static int
handle_secflag_dt(proc_t * p,uint_t dt,uint_t val)133d2a70789SRichard Lowe handle_secflag_dt(proc_t *p, uint_t dt, uint_t val)
134d2a70789SRichard Lowe {
135d2a70789SRichard Lowe 	uint_t flag;
136d2a70789SRichard Lowe 
137d2a70789SRichard Lowe 	switch (dt) {
138d2a70789SRichard Lowe 	case DT_SUNW_ASLR:
139d2a70789SRichard Lowe 		flag = PROC_SEC_ASLR;
140d2a70789SRichard Lowe 		break;
141d2a70789SRichard Lowe 	default:
142d2a70789SRichard Lowe 		return (EINVAL);
143d2a70789SRichard Lowe 	}
144d2a70789SRichard Lowe 
145d2a70789SRichard Lowe 	if (val == 0) {
146d2a70789SRichard Lowe 		if (secflag_isset(p->p_secflags.psf_lower, flag))
147d2a70789SRichard Lowe 			return (EPERM);
148d2a70789SRichard Lowe 		if ((secpolicy_psecflags(CRED(), p, p) != 0) &&
149d2a70789SRichard Lowe 		    secflag_isset(p->p_secflags.psf_inherit, flag))
150d2a70789SRichard Lowe 			return (EPERM);
151d2a70789SRichard Lowe 
152d2a70789SRichard Lowe 		secflag_clear(&p->p_secflags.psf_effective, flag);
153d2a70789SRichard Lowe 	} else {
154d2a70789SRichard Lowe 		if (!secflag_isset(p->p_secflags.psf_upper, flag))
155d2a70789SRichard Lowe 			return (EPERM);
156d2a70789SRichard Lowe 
157d2a70789SRichard Lowe 		if ((secpolicy_psecflags(CRED(), p, p) != 0) &&
158d2a70789SRichard Lowe 		    !secflag_isset(p->p_secflags.psf_inherit, flag))
159d2a70789SRichard Lowe 			return (EPERM);
160d2a70789SRichard Lowe 
161d2a70789SRichard Lowe 		secflag_set(&p->p_secflags.psf_effective, flag);
162d2a70789SRichard Lowe 	}
163d2a70789SRichard Lowe 
164d2a70789SRichard Lowe 	return (0);
165d2a70789SRichard Lowe }
166d2a70789SRichard Lowe 
1674e18e297SPatrick Mooney #ifndef _ELF32_COMPAT
1684e18e297SPatrick Mooney void
elf_ctx_resize_scratch(elf_core_ctx_t * ctx,size_t sz)1694e18e297SPatrick Mooney elf_ctx_resize_scratch(elf_core_ctx_t *ctx, size_t sz)
1704e18e297SPatrick Mooney {
1714e18e297SPatrick Mooney 	size_t target = MIN(sz, elf_datasz_max);
1724e18e297SPatrick Mooney 
1734e18e297SPatrick Mooney 	if (target > ctx->ecc_bufsz) {
1744e18e297SPatrick Mooney 		if (ctx->ecc_buf != NULL) {
1754e18e297SPatrick Mooney 			kmem_free(ctx->ecc_buf, ctx->ecc_bufsz);
1764e18e297SPatrick Mooney 		}
1774e18e297SPatrick Mooney 		ctx->ecc_buf = kmem_alloc(target, KM_SLEEP);
1784e18e297SPatrick Mooney 		ctx->ecc_bufsz = target;
1794e18e297SPatrick Mooney 	}
1804e18e297SPatrick Mooney }
1814e18e297SPatrick Mooney #endif /* _ELF32_COMPAT */
1824e18e297SPatrick Mooney 
1839acbbeafSnn /*
1849acbbeafSnn  * Map in the executable pointed to by vp. Returns 0 on success.
1859acbbeafSnn  */
1869acbbeafSnn int
mapexec_brand(vnode_t * vp,uarg_t * args,Ehdr * ehdr,Addr * uphdr_vaddr,intptr_t * voffset,caddr_t exec_file,int * interp,caddr_t * bssbase,caddr_t * brkbase,size_t * brksize,uintptr_t * lddatap)187396a100bSedp mapexec_brand(vnode_t *vp, uarg_t *args, Ehdr *ehdr, Addr *uphdr_vaddr,
1889acbbeafSnn     intptr_t *voffset, caddr_t exec_file, int *interp, caddr_t *bssbase,
18907678296Ssl     caddr_t *brkbase, size_t *brksize, uintptr_t *lddatap)
1909acbbeafSnn {
1914e18e297SPatrick Mooney 	size_t		len, phdrsize;
1929acbbeafSnn 	struct vattr	vat;
1939acbbeafSnn 	caddr_t		phdrbase = NULL;
1944e18e297SPatrick Mooney 	uint_t		nshdrs, shstrndx, nphdrs;
1959acbbeafSnn 	int		error = 0;
1969acbbeafSnn 	Phdr		*uphdr = NULL;
1979acbbeafSnn 	Phdr		*junk = NULL;
1989acbbeafSnn 	Phdr		*dynphdr = NULL;
1999acbbeafSnn 	Phdr		*dtrphdr = NULL;
2004e18e297SPatrick Mooney 	uintptr_t	lddata, minaddr;
2014e18e297SPatrick Mooney 	size_t		execsz;
2029acbbeafSnn 
20307678296Ssl 	if (lddatap != NULL)
204995a963fSToomas Soome 		*lddatap = 0;
20507678296Ssl 
2069acbbeafSnn 	if (error = execpermissions(vp, &vat, args)) {
2079acbbeafSnn 		uprintf("%s: Cannot execute %s\n", exec_file, args->pathname);
2089acbbeafSnn 		return (error);
2099acbbeafSnn 	}
2109acbbeafSnn 
2119acbbeafSnn 	if ((error = getelfhead(vp, CRED(), ehdr, &nshdrs, &shstrndx,
2129acbbeafSnn 	    &nphdrs)) != 0 ||
2139acbbeafSnn 	    (error = getelfphdr(vp, CRED(), ehdr, nphdrs, &phdrbase,
2149acbbeafSnn 	    &phdrsize)) != 0) {
2159acbbeafSnn 		uprintf("%s: Cannot read %s\n", exec_file, args->pathname);
2169acbbeafSnn 		return (error);
2179acbbeafSnn 	}
2189acbbeafSnn 
2199acbbeafSnn 	if ((len = elfsize(ehdr, nphdrs, phdrbase, &lddata)) == 0) {
2209acbbeafSnn 		uprintf("%s: Nothing to load in %s", exec_file, args->pathname);
2219acbbeafSnn 		kmem_free(phdrbase, phdrsize);
2229acbbeafSnn 		return (ENOEXEC);
2239acbbeafSnn 	}
22407678296Ssl 	if (lddatap != NULL)
22507678296Ssl 		*lddatap = lddata;
2269acbbeafSnn 
2279acbbeafSnn 	if (error = mapelfexec(vp, ehdr, nphdrs, phdrbase, &uphdr, &dynphdr,
2289acbbeafSnn 	    &junk, &dtrphdr, NULL, bssbase, brkbase, voffset, &minaddr,
2299acbbeafSnn 	    len, &execsz, brksize)) {
2309acbbeafSnn 		uprintf("%s: Cannot map %s\n", exec_file, args->pathname);
2314e18e297SPatrick Mooney 		if (uphdr != NULL && uphdr->p_flags == 0)
2324e18e297SPatrick Mooney 			kmem_free(uphdr, sizeof (Phdr));
2339acbbeafSnn 		kmem_free(phdrbase, phdrsize);
2349acbbeafSnn 		return (error);
2359acbbeafSnn 	}
2369acbbeafSnn 
2379acbbeafSnn 	/*
2389acbbeafSnn 	 * Inform our caller if the executable needs an interpreter.
2399acbbeafSnn 	 */
2409acbbeafSnn 	*interp = (dynphdr == NULL) ? 0 : 1;
2419acbbeafSnn 
2429acbbeafSnn 	/*
2439acbbeafSnn 	 * If this is a statically linked executable, voffset should indicate
2449acbbeafSnn 	 * the address of the executable itself (it normally holds the address
2459acbbeafSnn 	 * of the interpreter).
2469acbbeafSnn 	 */
2479acbbeafSnn 	if (ehdr->e_type == ET_EXEC && *interp == 0)
2489acbbeafSnn 		*voffset = minaddr;
2499acbbeafSnn 
2509acbbeafSnn 	if (uphdr != NULL) {
2519acbbeafSnn 		*uphdr_vaddr = uphdr->p_vaddr;
2524e18e297SPatrick Mooney 
2534e18e297SPatrick Mooney 		if (uphdr->p_flags == 0)
2544e18e297SPatrick Mooney 			kmem_free(uphdr, sizeof (Phdr));
2559acbbeafSnn 	} else {
256396a100bSedp 		*uphdr_vaddr = (Addr)-1;
2579acbbeafSnn 	}
2589acbbeafSnn 
2599acbbeafSnn 	kmem_free(phdrbase, phdrsize);
2609acbbeafSnn 	return (error);
2619acbbeafSnn }
2629acbbeafSnn 
2637c478bd9Sstevel@tonic-gate int
elfexec(vnode_t * vp,execa_t * uap,uarg_t * args,intpdata_t * idatap,int level,size_t * execsz,int setid,caddr_t exec_file,cred_t * cred,int brand_action)2647c478bd9Sstevel@tonic-gate elfexec(vnode_t *vp, execa_t *uap, uarg_t *args, intpdata_t *idatap,
2654e18e297SPatrick Mooney     int level, size_t *execsz, int setid, caddr_t exec_file, cred_t *cred,
2669acbbeafSnn     int brand_action)
2677c478bd9Sstevel@tonic-gate {
2687c478bd9Sstevel@tonic-gate 	caddr_t		phdrbase = NULL;
269d0158222SRobert Mustacchi 	caddr_t		bssbase = 0;
270d0158222SRobert Mustacchi 	caddr_t		brkbase = 0;
2717c478bd9Sstevel@tonic-gate 	size_t		brksize = 0;
2724e18e297SPatrick Mooney 	size_t		dlnsize;
2737c478bd9Sstevel@tonic-gate 	aux_entry_t	*aux;
2747c478bd9Sstevel@tonic-gate 	int		error;
2757c478bd9Sstevel@tonic-gate 	ssize_t		resid;
2767c478bd9Sstevel@tonic-gate 	int		fd = -1;
2777c478bd9Sstevel@tonic-gate 	intptr_t	voffset;
278d2a70789SRichard Lowe 	Phdr		*intphdr = NULL;
279d2a70789SRichard Lowe 	Phdr		*dynamicphdr = NULL;
2809acbbeafSnn 	Phdr		*stphdr = NULL;
2819acbbeafSnn 	Phdr		*uphdr = NULL;
2829acbbeafSnn 	Phdr		*junk = NULL;
2837c478bd9Sstevel@tonic-gate 	size_t		len;
2844e18e297SPatrick Mooney 	size_t		postfixsize = 0;
285a647f7a8SCody Peter Mello 	size_t		i;
2867c478bd9Sstevel@tonic-gate 	Phdr		*phdrp;
2877c478bd9Sstevel@tonic-gate 	Phdr		*dataphdrp = NULL;
2887c478bd9Sstevel@tonic-gate 	Phdr		*dtrphdr;
289a0de58d6SRoger A. Faulkner 	Phdr		*capphdr = NULL;
290a0de58d6SRoger A. Faulkner 	Cap		*cap = NULL;
2914e18e297SPatrick Mooney 	size_t		capsize;
2927c478bd9Sstevel@tonic-gate 	int		hasu = 0;
2937c478bd9Sstevel@tonic-gate 	int		hasauxv = 0;
294d2a70789SRichard Lowe 	int		hasintp = 0;
2959acbbeafSnn 	int		branded = 0;
2964e18e297SPatrick Mooney 	boolean_t	dynuphdr = B_FALSE;
2977c478bd9Sstevel@tonic-gate 
2987c478bd9Sstevel@tonic-gate 	struct proc *p = ttoproc(curthread);
2997c478bd9Sstevel@tonic-gate 	struct user *up = PTOU(p);
3007c478bd9Sstevel@tonic-gate 	struct bigwad {
3017c478bd9Sstevel@tonic-gate 		Ehdr	ehdr;
3027c478bd9Sstevel@tonic-gate 		aux_entry_t	elfargs[__KERN_NAUXV_IMPL];
3037c478bd9Sstevel@tonic-gate 		char		dl_name[MAXPATHLEN];
3047c478bd9Sstevel@tonic-gate 		char		pathbuf[MAXPATHLEN];
3057c478bd9Sstevel@tonic-gate 		struct vattr	vattr;
3067c478bd9Sstevel@tonic-gate 		struct execenv	exenv;
3077c478bd9Sstevel@tonic-gate 	} *bigwad;	/* kmem_alloc this behemoth so we don't blow stack */
30830da1432Sahl 	Ehdr		*ehdrp;
3094e18e297SPatrick Mooney 	uint_t		nshdrs, shstrndx, nphdrs;
3104e18e297SPatrick Mooney 	size_t		phdrsize;
3117c478bd9Sstevel@tonic-gate 	char		*dlnp;
3127c478bd9Sstevel@tonic-gate 	char		*pathbufp;
3137c478bd9Sstevel@tonic-gate 	rlim64_t	limit;
3147c478bd9Sstevel@tonic-gate 	rlim64_t	roundlimit;
3157c478bd9Sstevel@tonic-gate 
3167c478bd9Sstevel@tonic-gate 	ASSERT(p->p_model == DATAMODEL_ILP32 || p->p_model == DATAMODEL_LP64);
3177c478bd9Sstevel@tonic-gate 
3187c478bd9Sstevel@tonic-gate 	bigwad = kmem_alloc(sizeof (struct bigwad), KM_SLEEP);
3197c478bd9Sstevel@tonic-gate 	ehdrp = &bigwad->ehdr;
3207c478bd9Sstevel@tonic-gate 	dlnp = bigwad->dl_name;
3217c478bd9Sstevel@tonic-gate 	pathbufp = bigwad->pathbuf;
3227c478bd9Sstevel@tonic-gate 
3237c478bd9Sstevel@tonic-gate 	/*
3247c478bd9Sstevel@tonic-gate 	 * Obtain ELF and program header information.
3257c478bd9Sstevel@tonic-gate 	 */
32630da1432Sahl 	if ((error = getelfhead(vp, CRED(), ehdrp, &nshdrs, &shstrndx,
32730da1432Sahl 	    &nphdrs)) != 0 ||
32830da1432Sahl 	    (error = getelfphdr(vp, CRED(), ehdrp, nphdrs, &phdrbase,
32930da1432Sahl 	    &phdrsize)) != 0)
3307c478bd9Sstevel@tonic-gate 		goto out;
3317c478bd9Sstevel@tonic-gate 
332161d9479Srie 	/*
333161d9479Srie 	 * Prevent executing an ELF file that has no entry point.
334161d9479Srie 	 */
335161d9479Srie 	if (ehdrp->e_entry == 0) {
336161d9479Srie 		uprintf("%s: Bad entry point\n", exec_file);
337161d9479Srie 		goto bad;
338161d9479Srie 	}
339161d9479Srie 
3407c478bd9Sstevel@tonic-gate 	/*
3417c478bd9Sstevel@tonic-gate 	 * Put data model that we're exec-ing to into the args passed to
3427c478bd9Sstevel@tonic-gate 	 * exec_args(), so it will know what it is copying to on new stack.
3437c478bd9Sstevel@tonic-gate 	 * Now that we know whether we are exec-ing a 32-bit or 64-bit
3447c478bd9Sstevel@tonic-gate 	 * executable, we can set execsz with the appropriate NCARGS.
3457c478bd9Sstevel@tonic-gate 	 */
3467c478bd9Sstevel@tonic-gate #ifdef	_LP64
3477c478bd9Sstevel@tonic-gate 	if (ehdrp->e_ident[EI_CLASS] == ELFCLASS32) {
3487c478bd9Sstevel@tonic-gate 		args->to_model = DATAMODEL_ILP32;
3497c478bd9Sstevel@tonic-gate 		*execsz = btopr(SINCR) + btopr(SSIZE) + btopr(NCARGS32-1);
3507c478bd9Sstevel@tonic-gate 	} else {
3517c478bd9Sstevel@tonic-gate 		args->to_model = DATAMODEL_LP64;
3527c478bd9Sstevel@tonic-gate 		args->stk_prot &= ~PROT_EXEC;
35386ef0a63SRichard Lowe #if defined(__x86)
3547c478bd9Sstevel@tonic-gate 		args->dat_prot &= ~PROT_EXEC;
3557c478bd9Sstevel@tonic-gate #endif
3567c478bd9Sstevel@tonic-gate 		*execsz = btopr(SINCR) + btopr(SSIZE) + btopr(NCARGS64-1);
3577c478bd9Sstevel@tonic-gate 	}
3587c478bd9Sstevel@tonic-gate #else	/* _LP64 */
3597c478bd9Sstevel@tonic-gate 	args->to_model = DATAMODEL_ILP32;
3607c478bd9Sstevel@tonic-gate 	*execsz = btopr(SINCR) + btopr(SSIZE) + btopr(NCARGS-1);
3617c478bd9Sstevel@tonic-gate #endif	/* _LP64 */
3627c478bd9Sstevel@tonic-gate 
363396a100bSedp 	/*
364396a100bSedp 	 * We delay invoking the brand callback until we've figured out
365396a100bSedp 	 * what kind of elf binary we're trying to run, 32-bit or 64-bit.
366396a100bSedp 	 * We do this because now the brand library can just check
367396a100bSedp 	 * args->to_model to see if the target is 32-bit or 64-bit without
368396a100bSedp 	 * having do duplicate all the code above.
36993cf283aSJerry Jelinek 	 *
37093cf283aSJerry Jelinek 	 * The level checks associated with brand handling below are used to
37193cf283aSJerry Jelinek 	 * prevent a loop since the brand elfexec function typically comes back
37293cf283aSJerry Jelinek 	 * through this function. We must check <= here since the nested
37393cf283aSJerry Jelinek 	 * handling in the #! interpreter code will increment the level before
37493cf283aSJerry Jelinek 	 * calling gexec to run the final elfexec interpreter.
375396a100bSedp 	 */
37693cf283aSJerry Jelinek 	if ((level <= INTP_MAXDEPTH) &&
377396a100bSedp 	    (brand_action != EBA_NATIVE) && (PROC_IS_BRANDED(p))) {
378ec77975fSedp 		error = BROP(p)->b_elfexec(vp, uap, args,
379396a100bSedp 		    idatap, level + 1, execsz, setid, exec_file, cred,
380ec77975fSedp 		    brand_action);
381ec77975fSedp 		goto out;
382396a100bSedp 	}
383396a100bSedp 
3847c478bd9Sstevel@tonic-gate 	/*
3857c478bd9Sstevel@tonic-gate 	 * Determine aux size now so that stack can be built
3867c478bd9Sstevel@tonic-gate 	 * in one shot (except actual copyout of aux image),
3877c478bd9Sstevel@tonic-gate 	 * determine any non-default stack protections,
3887c478bd9Sstevel@tonic-gate 	 * and still have this code be machine independent.
3897c478bd9Sstevel@tonic-gate 	 */
3904e18e297SPatrick Mooney 	const uint_t hsize = ehdrp->e_phentsize;
3917c478bd9Sstevel@tonic-gate 	phdrp = (Phdr *)phdrbase;
39230da1432Sahl 	for (i = nphdrs; i > 0; i--) {
3937c478bd9Sstevel@tonic-gate 		switch (phdrp->p_type) {
3947c478bd9Sstevel@tonic-gate 		case PT_INTERP:
395d2a70789SRichard Lowe 			hasauxv = hasintp = 1;
3967c478bd9Sstevel@tonic-gate 			break;
3977c478bd9Sstevel@tonic-gate 		case PT_PHDR:
3987c478bd9Sstevel@tonic-gate 			hasu = 1;
3997c478bd9Sstevel@tonic-gate 			break;
4007c478bd9Sstevel@tonic-gate 		case PT_SUNWSTACK:
4017c478bd9Sstevel@tonic-gate 			args->stk_prot = PROT_USER;
4027c478bd9Sstevel@tonic-gate 			if (phdrp->p_flags & PF_R)
4037c478bd9Sstevel@tonic-gate 				args->stk_prot |= PROT_READ;
4047c478bd9Sstevel@tonic-gate 			if (phdrp->p_flags & PF_W)
4057c478bd9Sstevel@tonic-gate 				args->stk_prot |= PROT_WRITE;
4067c478bd9Sstevel@tonic-gate 			if (phdrp->p_flags & PF_X)
4077c478bd9Sstevel@tonic-gate 				args->stk_prot |= PROT_EXEC;
4087c478bd9Sstevel@tonic-gate 			break;
4097c478bd9Sstevel@tonic-gate 		case PT_LOAD:
4107c478bd9Sstevel@tonic-gate 			dataphdrp = phdrp;
4117c478bd9Sstevel@tonic-gate 			break;
412a0de58d6SRoger A. Faulkner 		case PT_SUNWCAP:
413a0de58d6SRoger A. Faulkner 			capphdr = phdrp;
414a0de58d6SRoger A. Faulkner 			break;
415d2a70789SRichard Lowe 		case PT_DYNAMIC:
416d2a70789SRichard Lowe 			dynamicphdr = phdrp;
417d2a70789SRichard Lowe 			break;
4187c478bd9Sstevel@tonic-gate 		}
4197c478bd9Sstevel@tonic-gate 		phdrp = (Phdr *)((caddr_t)phdrp + hsize);
4207c478bd9Sstevel@tonic-gate 	}
4217c478bd9Sstevel@tonic-gate 
4227c478bd9Sstevel@tonic-gate 	if (ehdrp->e_type != ET_EXEC) {
4237c478bd9Sstevel@tonic-gate 		dataphdrp = NULL;
4247c478bd9Sstevel@tonic-gate 		hasauxv = 1;
4257c478bd9Sstevel@tonic-gate 	}
4267c478bd9Sstevel@tonic-gate 
4277c478bd9Sstevel@tonic-gate 	/* Copy BSS permissions to args->dat_prot */
4287c478bd9Sstevel@tonic-gate 	if (dataphdrp != NULL) {
4297c478bd9Sstevel@tonic-gate 		args->dat_prot = PROT_USER;
4307c478bd9Sstevel@tonic-gate 		if (dataphdrp->p_flags & PF_R)
4317c478bd9Sstevel@tonic-gate 			args->dat_prot |= PROT_READ;
4327c478bd9Sstevel@tonic-gate 		if (dataphdrp->p_flags & PF_W)
4337c478bd9Sstevel@tonic-gate 			args->dat_prot |= PROT_WRITE;
4347c478bd9Sstevel@tonic-gate 		if (dataphdrp->p_flags & PF_X)
4357c478bd9Sstevel@tonic-gate 			args->dat_prot |= PROT_EXEC;
4367c478bd9Sstevel@tonic-gate 	}
4377c478bd9Sstevel@tonic-gate 
4387c478bd9Sstevel@tonic-gate 	/*
4397c478bd9Sstevel@tonic-gate 	 * If a auxvector will be required - reserve the space for
4407c478bd9Sstevel@tonic-gate 	 * it now.  This may be increased by exec_args if there are
4417c478bd9Sstevel@tonic-gate 	 * ISA-specific types (included in __KERN_NAUXV_IMPL).
4427c478bd9Sstevel@tonic-gate 	 */
4437c478bd9Sstevel@tonic-gate 	if (hasauxv) {
4447c478bd9Sstevel@tonic-gate 		/*
4457c478bd9Sstevel@tonic-gate 		 * If a AUX vector is being built - the base AUX
4467c478bd9Sstevel@tonic-gate 		 * entries are:
4477c478bd9Sstevel@tonic-gate 		 *
4487c478bd9Sstevel@tonic-gate 		 *	AT_BASE
4497c478bd9Sstevel@tonic-gate 		 *	AT_FLAGS
4507c478bd9Sstevel@tonic-gate 		 *	AT_PAGESZ
451386e9c9eSJerry Jelinek 		 *	AT_SUN_AUXFLAGS
4527c478bd9Sstevel@tonic-gate 		 *	AT_SUN_HWCAP
453ebb8ac07SRobert Mustacchi 		 *	AT_SUN_HWCAP2
45456726c7eSRobert Mustacchi 		 *	AT_SUN_HWCAP3
455386e9c9eSJerry Jelinek 		 *	AT_SUN_PLATFORM (added in stk_copyout)
456386e9c9eSJerry Jelinek 		 *	AT_SUN_EXECNAME (added in stk_copyout)
4577c478bd9Sstevel@tonic-gate 		 *	AT_NULL
4587c478bd9Sstevel@tonic-gate 		 *
45956726c7eSRobert Mustacchi 		 * total == 10
4607c478bd9Sstevel@tonic-gate 		 */
461d2a70789SRichard Lowe 		if (hasintp && hasu) {
4627c478bd9Sstevel@tonic-gate 			/*
4637c478bd9Sstevel@tonic-gate 			 * Has PT_INTERP & PT_PHDR - the auxvectors that
4647c478bd9Sstevel@tonic-gate 			 * will be built are:
4657c478bd9Sstevel@tonic-gate 			 *
4667c478bd9Sstevel@tonic-gate 			 *	AT_PHDR
4677c478bd9Sstevel@tonic-gate 			 *	AT_PHENT
4687c478bd9Sstevel@tonic-gate 			 *	AT_PHNUM
4697c478bd9Sstevel@tonic-gate 			 *	AT_ENTRY
4707c478bd9Sstevel@tonic-gate 			 *	AT_LDDATA
4717c478bd9Sstevel@tonic-gate 			 *
4727c478bd9Sstevel@tonic-gate 			 * total = 5
4737c478bd9Sstevel@tonic-gate 			 */
47456726c7eSRobert Mustacchi 			args->auxsize = (10 + 5) * sizeof (aux_entry_t);
475d2a70789SRichard Lowe 		} else if (hasintp) {
4767c478bd9Sstevel@tonic-gate 			/*
4777c478bd9Sstevel@tonic-gate 			 * Has PT_INTERP but no PT_PHDR
4787c478bd9Sstevel@tonic-gate 			 *
4797c478bd9Sstevel@tonic-gate 			 *	AT_EXECFD
4807c478bd9Sstevel@tonic-gate 			 *	AT_LDDATA
4817c478bd9Sstevel@tonic-gate 			 *
4827c478bd9Sstevel@tonic-gate 			 * total = 2
4837c478bd9Sstevel@tonic-gate 			 */
48456726c7eSRobert Mustacchi 			args->auxsize = (10 + 2) * sizeof (aux_entry_t);
4857c478bd9Sstevel@tonic-gate 		} else {
48656726c7eSRobert Mustacchi 			args->auxsize = 10 * sizeof (aux_entry_t);
4877c478bd9Sstevel@tonic-gate 		}
488a0de58d6SRoger A. Faulkner 	} else {
4897c478bd9Sstevel@tonic-gate 		args->auxsize = 0;
490a0de58d6SRoger A. Faulkner 	}
4917c478bd9Sstevel@tonic-gate 
4929acbbeafSnn 	/*
4939acbbeafSnn 	 * If this binary is using an emulator, we need to add an
4949acbbeafSnn 	 * AT_SUN_EMULATOR aux entry.
4959acbbeafSnn 	 */
4969acbbeafSnn 	if (args->emulator != NULL)
4979acbbeafSnn 		args->auxsize += sizeof (aux_entry_t);
4989acbbeafSnn 
4992428aad8SPatrick Mooney 	/*
5002428aad8SPatrick Mooney 	 * On supported kernels (x86_64) make room in the auxv for the
5012428aad8SPatrick Mooney 	 * AT_SUN_COMMPAGE entry.  This will go unpopulated on i86xpv systems
5022428aad8SPatrick Mooney 	 * which do not provide such functionality.
503d0158222SRobert Mustacchi 	 *
504d0158222SRobert Mustacchi 	 * Additionally cover the floating point information AT_SUN_FPSIZE and
505d0158222SRobert Mustacchi 	 * AT_SUN_FPTYPE.
5062428aad8SPatrick Mooney 	 */
5072428aad8SPatrick Mooney #if defined(__amd64)
508d0158222SRobert Mustacchi 	args->auxsize += 3 * sizeof (aux_entry_t);
5092428aad8SPatrick Mooney #endif /* defined(__amd64) */
5102428aad8SPatrick Mooney 
5119acbbeafSnn 	if ((brand_action != EBA_NATIVE) && (PROC_IS_BRANDED(p))) {
5129acbbeafSnn 		branded = 1;
5139acbbeafSnn 		/*
51407678296Ssl 		 * We will be adding 4 entries to the aux vectors.  One for
51507678296Ssl 		 * the the brandname and 3 for the brand specific aux vectors.
5169acbbeafSnn 		 */
51707678296Ssl 		args->auxsize += 4 * sizeof (aux_entry_t);
5189acbbeafSnn 	}
5199acbbeafSnn 
520d2a70789SRichard Lowe 	/* If the binary has an explicit ASLR flag, it must be honoured */
521a647f7a8SCody Peter Mello 	if ((dynamicphdr != NULL) && (dynamicphdr->p_filesz > 0)) {
522a647f7a8SCody Peter Mello 		const size_t dynfilesz = dynamicphdr->p_filesz;
523a647f7a8SCody Peter Mello 		const size_t dynoffset = dynamicphdr->p_offset;
524a647f7a8SCody Peter Mello 		Dyn *dyn, *dp;
525a647f7a8SCody Peter Mello 
526a647f7a8SCody Peter Mello 		if (dynoffset > MAXOFFSET_T ||
527a647f7a8SCody Peter Mello 		    dynfilesz > MAXOFFSET_T ||
528a647f7a8SCody Peter Mello 		    dynoffset + dynfilesz > MAXOFFSET_T) {
529a647f7a8SCody Peter Mello 			uprintf("%s: cannot read full .dynamic section\n",
530a647f7a8SCody Peter Mello 			    exec_file);
531a647f7a8SCody Peter Mello 			error = EINVAL;
532a647f7a8SCody Peter Mello 			goto out;
533a647f7a8SCody Peter Mello 		}
534d2a70789SRichard Lowe 
535d2a70789SRichard Lowe #define	DYN_STRIDE	100
536a647f7a8SCody Peter Mello 		for (i = 0; i < dynfilesz; i += sizeof (*dyn) * DYN_STRIDE) {
537a647f7a8SCody Peter Mello 			const size_t remdyns = (dynfilesz - i) / sizeof (*dyn);
538a647f7a8SCody Peter Mello 			const size_t ndyns = MIN(DYN_STRIDE, remdyns);
539a647f7a8SCody Peter Mello 			const size_t dynsize = ndyns * sizeof (*dyn);
540d2a70789SRichard Lowe 
541d2a70789SRichard Lowe 			dyn = kmem_alloc(dynsize, KM_SLEEP);
542d2a70789SRichard Lowe 
543d2a70789SRichard Lowe 			if ((error = vn_rdwr(UIO_READ, vp, (caddr_t)dyn,
544a647f7a8SCody Peter Mello 			    (ssize_t)dynsize, (offset_t)(dynoffset + i),
545d2a70789SRichard Lowe 			    UIO_SYSSPACE, 0, (rlim64_t)0,
5464e18e297SPatrick Mooney 			    CRED(), NULL)) != 0) {
547d2a70789SRichard Lowe 				uprintf("%s: cannot read .dynamic section\n",
548d2a70789SRichard Lowe 				    exec_file);
549d2a70789SRichard Lowe 				goto out;
550d2a70789SRichard Lowe 			}
551d2a70789SRichard Lowe 
552d2a70789SRichard Lowe 			for (dp = dyn; dp < (dyn + ndyns); dp++) {
553d2a70789SRichard Lowe 				if (dp->d_tag == DT_SUNW_ASLR) {
554d2a70789SRichard Lowe 					if ((error = handle_secflag_dt(p,
555d2a70789SRichard Lowe 					    DT_SUNW_ASLR,
556d2a70789SRichard Lowe 					    dp->d_un.d_val)) != 0) {
557d2a70789SRichard Lowe 						uprintf("%s: error setting "
558d2a70789SRichard Lowe 						    "security-flag from "
559d2a70789SRichard Lowe 						    "DT_SUNW_ASLR: %d\n",
560d2a70789SRichard Lowe 						    exec_file, error);
561d2a70789SRichard Lowe 						goto out;
562d2a70789SRichard Lowe 					}
563d2a70789SRichard Lowe 				}
564d2a70789SRichard Lowe 			}
565d2a70789SRichard Lowe 
566d2a70789SRichard Lowe 			kmem_free(dyn, dynsize);
567d2a70789SRichard Lowe 		}
568d2a70789SRichard Lowe 	}
569d2a70789SRichard Lowe 
570a0de58d6SRoger A. Faulkner 	/* Hardware/Software capabilities */
571a0de58d6SRoger A. Faulkner 	if (capphdr != NULL &&
572a0de58d6SRoger A. Faulkner 	    (capsize = capphdr->p_filesz) > 0 &&
573a0de58d6SRoger A. Faulkner 	    capsize <= 16 * sizeof (*cap)) {
5744e18e297SPatrick Mooney 		const uint_t ncaps = capsize / sizeof (*cap);
575a0de58d6SRoger A. Faulkner 		Cap *cp;
576a0de58d6SRoger A. Faulkner 
577a0de58d6SRoger A. Faulkner 		cap = kmem_alloc(capsize, KM_SLEEP);
578a0de58d6SRoger A. Faulkner 		if ((error = vn_rdwr(UIO_READ, vp, (caddr_t)cap,
5794e18e297SPatrick Mooney 		    (ssize_t)capsize, (offset_t)capphdr->p_offset,
5804e18e297SPatrick Mooney 		    UIO_SYSSPACE, 0, (rlim64_t)0, CRED(), NULL)) != 0) {
581a0de58d6SRoger A. Faulkner 			uprintf("%s: Cannot read capabilities section\n",
582a0de58d6SRoger A. Faulkner 			    exec_file);
583a0de58d6SRoger A. Faulkner 			goto out;
584a0de58d6SRoger A. Faulkner 		}
585a0de58d6SRoger A. Faulkner 		for (cp = cap; cp < cap + ncaps; cp++) {
586a0de58d6SRoger A. Faulkner 			if (cp->c_tag == CA_SUNW_SF_1 &&
587a0de58d6SRoger A. Faulkner 			    (cp->c_un.c_val & SF1_SUNW_ADDR32)) {
588a0de58d6SRoger A. Faulkner 				if (args->to_model == DATAMODEL_LP64)
589a0de58d6SRoger A. Faulkner 					args->addr32 = 1;
590a0de58d6SRoger A. Faulkner 				break;
591a0de58d6SRoger A. Faulkner 			}
592a0de58d6SRoger A. Faulkner 		}
593a0de58d6SRoger A. Faulkner 	}
594a0de58d6SRoger A. Faulkner 
5957c478bd9Sstevel@tonic-gate 	aux = bigwad->elfargs;
5967c478bd9Sstevel@tonic-gate 	/*
5977c478bd9Sstevel@tonic-gate 	 * Move args to the user's stack.
598386e9c9eSJerry Jelinek 	 * This can fill in the AT_SUN_PLATFORM and AT_SUN_EXECNAME aux entries.
5997c478bd9Sstevel@tonic-gate 	 */
6007c478bd9Sstevel@tonic-gate 	if ((error = exec_args(uap, args, idatap, (void **)&aux)) != 0) {
6017c478bd9Sstevel@tonic-gate 		if (error == -1) {
6027c478bd9Sstevel@tonic-gate 			error = ENOEXEC;
6037c478bd9Sstevel@tonic-gate 			goto bad;
6047c478bd9Sstevel@tonic-gate 		}
6057c478bd9Sstevel@tonic-gate 		goto out;
6067c478bd9Sstevel@tonic-gate 	}
6079acbbeafSnn 	/* we're single threaded after this point */
6087c478bd9Sstevel@tonic-gate 
6097c478bd9Sstevel@tonic-gate 	/*
6107c478bd9Sstevel@tonic-gate 	 * If this is an ET_DYN executable (shared object),
6117c478bd9Sstevel@tonic-gate 	 * determine its memory size so that mapelfexec() can load it.
6127c478bd9Sstevel@tonic-gate 	 */
6137c478bd9Sstevel@tonic-gate 	if (ehdrp->e_type == ET_DYN)
61430da1432Sahl 		len = elfsize(ehdrp, nphdrs, phdrbase, NULL);
6157c478bd9Sstevel@tonic-gate 	else
6167c478bd9Sstevel@tonic-gate 		len = 0;
6177c478bd9Sstevel@tonic-gate 
6187c478bd9Sstevel@tonic-gate 	dtrphdr = NULL;
6197c478bd9Sstevel@tonic-gate 
6204e18e297SPatrick Mooney 	error = mapelfexec(vp, ehdrp, nphdrs, phdrbase, &uphdr, &intphdr,
6219acbbeafSnn 	    &stphdr, &dtrphdr, dataphdrp, &bssbase, &brkbase, &voffset, NULL,
6224e18e297SPatrick Mooney 	    len, execsz, &brksize);
6234e18e297SPatrick Mooney 
6244e18e297SPatrick Mooney 	/*
6254e18e297SPatrick Mooney 	 * Our uphdr has been dynamically allocated if (and only if) its
6264e18e297SPatrick Mooney 	 * program header flags are clear.  To avoid leaks, this must be
6274e18e297SPatrick Mooney 	 * checked regardless of whether mapelfexec() emitted an error.
6284e18e297SPatrick Mooney 	 */
6294e18e297SPatrick Mooney 	dynuphdr = (uphdr != NULL && uphdr->p_flags == 0);
6304e18e297SPatrick Mooney 
6314e18e297SPatrick Mooney 	if (error != 0)
6327c478bd9Sstevel@tonic-gate 		goto bad;
6337c478bd9Sstevel@tonic-gate 
634d2a70789SRichard Lowe 	if (uphdr != NULL && intphdr == NULL)
6357c478bd9Sstevel@tonic-gate 		goto bad;
6367c478bd9Sstevel@tonic-gate 
6377c478bd9Sstevel@tonic-gate 	if (dtrphdr != NULL && dtrace_safe_phdr(dtrphdr, args, voffset) != 0) {
6387c478bd9Sstevel@tonic-gate 		uprintf("%s: Bad DTrace phdr in %s\n", exec_file, exec_file);
6397c478bd9Sstevel@tonic-gate 		goto bad;
6407c478bd9Sstevel@tonic-gate 	}
6417c478bd9Sstevel@tonic-gate 
642d2a70789SRichard Lowe 	if (intphdr != NULL) {
6437c478bd9Sstevel@tonic-gate 		size_t		len;
6447c478bd9Sstevel@tonic-gate 		uintptr_t	lddata;
6457c478bd9Sstevel@tonic-gate 		char		*p;
6467c478bd9Sstevel@tonic-gate 		struct vnode	*nvp;
6477c478bd9Sstevel@tonic-gate 
648d2a70789SRichard Lowe 		dlnsize = intphdr->p_filesz;
6497c478bd9Sstevel@tonic-gate 
6504e18e297SPatrick Mooney 		/*
6514e18e297SPatrick Mooney 		 * Make sure none of the component pieces of dlnsize result in
6524e18e297SPatrick Mooney 		 * an oversized or zeroed result.
6534e18e297SPatrick Mooney 		 */
6544e18e297SPatrick Mooney 		if (intphdr->p_filesz > MAXPATHLEN || dlnsize > MAXPATHLEN ||
6554e18e297SPatrick Mooney 		    dlnsize == 0 || dlnsize < intphdr->p_filesz) {
6567c478bd9Sstevel@tonic-gate 			goto bad;
6574e18e297SPatrick Mooney 		}
6587c478bd9Sstevel@tonic-gate 
6597c478bd9Sstevel@tonic-gate 		/*
6607c478bd9Sstevel@tonic-gate 		 * Read in "interpreter" pathname.
6617c478bd9Sstevel@tonic-gate 		 */
6624e18e297SPatrick Mooney 		if ((error = vn_rdwr(UIO_READ, vp, dlnp,
6634e18e297SPatrick Mooney 		    (ssize_t)intphdr->p_filesz, (offset_t)intphdr->p_offset,
6644e18e297SPatrick Mooney 		    UIO_SYSSPACE, 0, (rlim64_t)0, CRED(), &resid)) != 0) {
6657c478bd9Sstevel@tonic-gate 			uprintf("%s: Cannot obtain interpreter pathname\n",
6667c478bd9Sstevel@tonic-gate 			    exec_file);
6677c478bd9Sstevel@tonic-gate 			goto bad;
6687c478bd9Sstevel@tonic-gate 		}
6697c478bd9Sstevel@tonic-gate 
6707c478bd9Sstevel@tonic-gate 		if (resid != 0 || dlnp[dlnsize - 1] != '\0')
6717c478bd9Sstevel@tonic-gate 			goto bad;
6727c478bd9Sstevel@tonic-gate 
6737c478bd9Sstevel@tonic-gate 		/*
6747c478bd9Sstevel@tonic-gate 		 * Search for '$ORIGIN' token in interpreter path.
6757c478bd9Sstevel@tonic-gate 		 * If found, expand it.
6767c478bd9Sstevel@tonic-gate 		 */
6777c478bd9Sstevel@tonic-gate 		for (p = dlnp; p = strchr(p, '$'); ) {
6787c478bd9Sstevel@tonic-gate 			uint_t	len, curlen;
6797c478bd9Sstevel@tonic-gate 			char	*_ptr;
6807c478bd9Sstevel@tonic-gate 
6817c478bd9Sstevel@tonic-gate 			if (strncmp(++p, ORIGIN_STR, ORIGIN_STR_SIZE))
6827c478bd9Sstevel@tonic-gate 				continue;
6837c478bd9Sstevel@tonic-gate 
68403973b9cSJerry Jelinek 			/*
68503973b9cSJerry Jelinek 			 * We don't support $ORIGIN on setid programs to close
68603973b9cSJerry Jelinek 			 * a potential attack vector.
68703973b9cSJerry Jelinek 			 */
68803973b9cSJerry Jelinek 			if ((setid & EXECSETID_SETID) != 0) {
68903973b9cSJerry Jelinek 				error = ENOEXEC;
69003973b9cSJerry Jelinek 				goto bad;
69103973b9cSJerry Jelinek 			}
69203973b9cSJerry Jelinek 
6937c478bd9Sstevel@tonic-gate 			curlen = 0;
6947c478bd9Sstevel@tonic-gate 			len = p - dlnp - 1;
6957c478bd9Sstevel@tonic-gate 			if (len) {
6967c478bd9Sstevel@tonic-gate 				bcopy(dlnp, pathbufp, len);
6977c478bd9Sstevel@tonic-gate 				curlen += len;
6987c478bd9Sstevel@tonic-gate 			}
6997c478bd9Sstevel@tonic-gate 			if (_ptr = strrchr(args->pathname, '/')) {
7007c478bd9Sstevel@tonic-gate 				len = _ptr - args->pathname;
7017c478bd9Sstevel@tonic-gate 				if ((curlen + len) > MAXPATHLEN)
7027c478bd9Sstevel@tonic-gate 					break;
7037c478bd9Sstevel@tonic-gate 
7047c478bd9Sstevel@tonic-gate 				bcopy(args->pathname, &pathbufp[curlen], len);
7057c478bd9Sstevel@tonic-gate 				curlen += len;
7067c478bd9Sstevel@tonic-gate 			} else {
7077c478bd9Sstevel@tonic-gate 				/*
7087c478bd9Sstevel@tonic-gate 				 * executable is a basename found in the
7097c478bd9Sstevel@tonic-gate 				 * current directory.  So - just substitue
7107c478bd9Sstevel@tonic-gate 				 * '.' for ORIGIN.
7117c478bd9Sstevel@tonic-gate 				 */
7127c478bd9Sstevel@tonic-gate 				pathbufp[curlen] = '.';
7137c478bd9Sstevel@tonic-gate 				curlen++;
7147c478bd9Sstevel@tonic-gate 			}
7157c478bd9Sstevel@tonic-gate 			p += ORIGIN_STR_SIZE;
7167c478bd9Sstevel@tonic-gate 			len = strlen(p);
7177c478bd9Sstevel@tonic-gate 
7187c478bd9Sstevel@tonic-gate 			if ((curlen + len) > MAXPATHLEN)
7197c478bd9Sstevel@tonic-gate 				break;
7207c478bd9Sstevel@tonic-gate 			bcopy(p, &pathbufp[curlen], len);
7217c478bd9Sstevel@tonic-gate 			curlen += len;
7227c478bd9Sstevel@tonic-gate 			pathbufp[curlen++] = '\0';
7237c478bd9Sstevel@tonic-gate 			bcopy(pathbufp, dlnp, curlen);
7247c478bd9Sstevel@tonic-gate 		}
7257c478bd9Sstevel@tonic-gate 
7267c478bd9Sstevel@tonic-gate 		/*
7277c478bd9Sstevel@tonic-gate 		 * /usr/lib/ld.so.1 is known to be a symlink to /lib/ld.so.1
7287c478bd9Sstevel@tonic-gate 		 * (and /usr/lib/64/ld.so.1 is a symlink to /lib/64/ld.so.1).
7297c478bd9Sstevel@tonic-gate 		 * Just in case /usr is not mounted, change it now.
7307c478bd9Sstevel@tonic-gate 		 */
7317c478bd9Sstevel@tonic-gate 		if (strcmp(dlnp, USR_LIB_RTLD) == 0)
7327c478bd9Sstevel@tonic-gate 			dlnp += 4;
7337c478bd9Sstevel@tonic-gate 		error = lookupname(dlnp, UIO_SYSSPACE, FOLLOW, NULLVPP, &nvp);
7347c478bd9Sstevel@tonic-gate 		if (error && dlnp != bigwad->dl_name) {
7357c478bd9Sstevel@tonic-gate 			/* new kernel, old user-level */
7367c478bd9Sstevel@tonic-gate 			error = lookupname(dlnp -= 4, UIO_SYSSPACE, FOLLOW,
73707678296Ssl 			    NULLVPP, &nvp);
7387c478bd9Sstevel@tonic-gate 		}
7397c478bd9Sstevel@tonic-gate 		if (error) {
7407c478bd9Sstevel@tonic-gate 			uprintf("%s: Cannot find %s\n", exec_file, dlnp);
7417c478bd9Sstevel@tonic-gate 			goto bad;
7427c478bd9Sstevel@tonic-gate 		}
7437c478bd9Sstevel@tonic-gate 
7447c478bd9Sstevel@tonic-gate 		/*
7457c478bd9Sstevel@tonic-gate 		 * Setup the "aux" vector.
7467c478bd9Sstevel@tonic-gate 		 */
7477c478bd9Sstevel@tonic-gate 		if (uphdr) {
7487c478bd9Sstevel@tonic-gate 			if (ehdrp->e_type == ET_DYN) {
7497c478bd9Sstevel@tonic-gate 				/* don't use the first page */
7507c478bd9Sstevel@tonic-gate 				bigwad->exenv.ex_brkbase = (caddr_t)PAGESIZE;
7517c478bd9Sstevel@tonic-gate 				bigwad->exenv.ex_bssbase = (caddr_t)PAGESIZE;
7527c478bd9Sstevel@tonic-gate 			} else {
7537c478bd9Sstevel@tonic-gate 				bigwad->exenv.ex_bssbase = bssbase;
7547c478bd9Sstevel@tonic-gate 				bigwad->exenv.ex_brkbase = brkbase;
7557c478bd9Sstevel@tonic-gate 			}
7567c478bd9Sstevel@tonic-gate 			bigwad->exenv.ex_brksize = brksize;
7577c478bd9Sstevel@tonic-gate 			bigwad->exenv.ex_magic = elfmagic;
7587c478bd9Sstevel@tonic-gate 			bigwad->exenv.ex_vp = vp;
7597c478bd9Sstevel@tonic-gate 			setexecenv(&bigwad->exenv);
7607c478bd9Sstevel@tonic-gate 
7617c478bd9Sstevel@tonic-gate 			ADDAUX(aux, AT_PHDR, uphdr->p_vaddr + voffset)
7627c478bd9Sstevel@tonic-gate 			ADDAUX(aux, AT_PHENT, ehdrp->e_phentsize)
76330da1432Sahl 			ADDAUX(aux, AT_PHNUM, nphdrs)
7647c478bd9Sstevel@tonic-gate 			ADDAUX(aux, AT_ENTRY, ehdrp->e_entry + voffset)
7657c478bd9Sstevel@tonic-gate 		} else {
7667c478bd9Sstevel@tonic-gate 			if ((error = execopen(&vp, &fd)) != 0) {
7677c478bd9Sstevel@tonic-gate 				VN_RELE(nvp);
7687c478bd9Sstevel@tonic-gate 				goto bad;
7697c478bd9Sstevel@tonic-gate 			}
7707c478bd9Sstevel@tonic-gate 
7717c478bd9Sstevel@tonic-gate 			ADDAUX(aux, AT_EXECFD, fd)
7727c478bd9Sstevel@tonic-gate 		}
7737c478bd9Sstevel@tonic-gate 
7747c478bd9Sstevel@tonic-gate 		if ((error = execpermissions(nvp, &bigwad->vattr, args)) != 0) {
7757c478bd9Sstevel@tonic-gate 			VN_RELE(nvp);
7767c478bd9Sstevel@tonic-gate 			uprintf("%s: Cannot execute %s\n", exec_file, dlnp);
7777c478bd9Sstevel@tonic-gate 			goto bad;
7787c478bd9Sstevel@tonic-gate 		}
7797c478bd9Sstevel@tonic-gate 
7807c478bd9Sstevel@tonic-gate 		/*
7817c478bd9Sstevel@tonic-gate 		 * Now obtain the ELF header along with the entire program
7827c478bd9Sstevel@tonic-gate 		 * header contained in "nvp".
7837c478bd9Sstevel@tonic-gate 		 */
7847c478bd9Sstevel@tonic-gate 		kmem_free(phdrbase, phdrsize);
7857c478bd9Sstevel@tonic-gate 		phdrbase = NULL;
78630da1432Sahl 		if ((error = getelfhead(nvp, CRED(), ehdrp, &nshdrs,
78730da1432Sahl 		    &shstrndx, &nphdrs)) != 0 ||
78830da1432Sahl 		    (error = getelfphdr(nvp, CRED(), ehdrp, nphdrs, &phdrbase,
7897c478bd9Sstevel@tonic-gate 		    &phdrsize)) != 0) {
7907c478bd9Sstevel@tonic-gate 			VN_RELE(nvp);
7917c478bd9Sstevel@tonic-gate 			uprintf("%s: Cannot read %s\n", exec_file, dlnp);
7927c478bd9Sstevel@tonic-gate 			goto bad;
7937c478bd9Sstevel@tonic-gate 		}
7947c478bd9Sstevel@tonic-gate 
7957c478bd9Sstevel@tonic-gate 		/*
7967c478bd9Sstevel@tonic-gate 		 * Determine memory size of the "interpreter's" loadable
7977c478bd9Sstevel@tonic-gate 		 * sections.  This size is then used to obtain the virtual
7987c478bd9Sstevel@tonic-gate 		 * address of a hole, in the user's address space, large
7997c478bd9Sstevel@tonic-gate 		 * enough to map the "interpreter".
8007c478bd9Sstevel@tonic-gate 		 */
80130da1432Sahl 		if ((len = elfsize(ehdrp, nphdrs, phdrbase, &lddata)) == 0) {
8027c478bd9Sstevel@tonic-gate 			VN_RELE(nvp);
8037c478bd9Sstevel@tonic-gate 			uprintf("%s: Nothing to load in %s\n", exec_file, dlnp);
8047c478bd9Sstevel@tonic-gate 			goto bad;
8057c478bd9Sstevel@tonic-gate 		}
8067c478bd9Sstevel@tonic-gate 
8077c478bd9Sstevel@tonic-gate 		dtrphdr = NULL;
8087c478bd9Sstevel@tonic-gate 
8094e18e297SPatrick Mooney 		error = mapelfexec(nvp, ehdrp, nphdrs, phdrbase, NULL, &junk,
8109acbbeafSnn 		    &junk, &dtrphdr, NULL, NULL, NULL, &voffset, NULL, len,
8119acbbeafSnn 		    execsz, NULL);
8124e18e297SPatrick Mooney 
8137c478bd9Sstevel@tonic-gate 		if (error || junk != NULL) {
8147c478bd9Sstevel@tonic-gate 			VN_RELE(nvp);
8157c478bd9Sstevel@tonic-gate 			uprintf("%s: Cannot map %s\n", exec_file, dlnp);
8167c478bd9Sstevel@tonic-gate 			goto bad;
8177c478bd9Sstevel@tonic-gate 		}
8187c478bd9Sstevel@tonic-gate 
8197c478bd9Sstevel@tonic-gate 		/*
8207c478bd9Sstevel@tonic-gate 		 * We use the DTrace program header to initialize the
8217c478bd9Sstevel@tonic-gate 		 * architecture-specific user per-LWP location. The dtrace
8227c478bd9Sstevel@tonic-gate 		 * fasttrap provider requires ready access to per-LWP scratch
8237c478bd9Sstevel@tonic-gate 		 * space. We assume that there is only one such program header
8247c478bd9Sstevel@tonic-gate 		 * in the interpreter.
8257c478bd9Sstevel@tonic-gate 		 */
8267c478bd9Sstevel@tonic-gate 		if (dtrphdr != NULL &&
8277c478bd9Sstevel@tonic-gate 		    dtrace_safe_phdr(dtrphdr, args, voffset) != 0) {
8287c478bd9Sstevel@tonic-gate 			VN_RELE(nvp);
8297c478bd9Sstevel@tonic-gate 			uprintf("%s: Bad DTrace phdr in %s\n", exec_file, dlnp);
8307c478bd9Sstevel@tonic-gate 			goto bad;
8317c478bd9Sstevel@tonic-gate 		}
8327c478bd9Sstevel@tonic-gate 
8337c478bd9Sstevel@tonic-gate 		VN_RELE(nvp);
8347c478bd9Sstevel@tonic-gate 		ADDAUX(aux, AT_SUN_LDDATA, voffset + lddata)
8357c478bd9Sstevel@tonic-gate 	}
8367c478bd9Sstevel@tonic-gate 
8377c478bd9Sstevel@tonic-gate 	if (hasauxv) {
8387c478bd9Sstevel@tonic-gate 		int auxf = AF_SUN_HWCAPVERIFY;
839bc0adaffSPeter Tribble #if defined(__amd64)
840d0158222SRobert Mustacchi 		size_t fpsize;
841d0158222SRobert Mustacchi 		int fptype;
842bc0adaffSPeter Tribble #endif /* defined(__amd64) */
8432428aad8SPatrick Mooney 
8447c478bd9Sstevel@tonic-gate 		/*
845386e9c9eSJerry Jelinek 		 * Note: AT_SUN_PLATFORM and AT_SUN_EXECNAME were filled in via
846386e9c9eSJerry Jelinek 		 * exec_args()
8477c478bd9Sstevel@tonic-gate 		 */
8487c478bd9Sstevel@tonic-gate 		ADDAUX(aux, AT_BASE, voffset)
8497c478bd9Sstevel@tonic-gate 		ADDAUX(aux, AT_FLAGS, at_flags)
8507c478bd9Sstevel@tonic-gate 		ADDAUX(aux, AT_PAGESZ, PAGESIZE)
8517c478bd9Sstevel@tonic-gate 		/*
8527c478bd9Sstevel@tonic-gate 		 * Linker flags. (security)
8537c478bd9Sstevel@tonic-gate 		 * p_flag not yet set at this time.
8547c478bd9Sstevel@tonic-gate 		 * We rely on gexec() to provide us with the information.
855cc4b03b5Scasper 		 * If the application is set-uid but this is not reflected
856cc4b03b5Scasper 		 * in a mismatch between real/effective uids/gids, then
857cc4b03b5Scasper 		 * don't treat this as a set-uid exec.  So we care about
858cc4b03b5Scasper 		 * the EXECSETID_UGIDS flag but not the ...SETID flag.
8597c478bd9Sstevel@tonic-gate 		 */
860b71d513aSedp 		if ((setid &= ~EXECSETID_SETID) != 0)
861b71d513aSedp 			auxf |= AF_SUN_SETUGID;
8621022fd2aS 
8631022fd2aS 		/*
8641022fd2aS 		 * If we're running a native process from within a branded
8651022fd2aS 		 * zone under pfexec then we clear the AF_SUN_SETUGID flag so
8661022fd2aS 		 * that the native ld.so.1 is able to link with the native
8671022fd2aS 		 * libraries instead of using the brand libraries that are
8681022fd2aS 		 * installed in the zone.  We only do this for processes
8691022fd2aS 		 * which we trust because we see they are already running
8701022fd2aS 		 * under pfexec (where uid != euid).  This prevents a
8711022fd2aS 		 * malicious user within the zone from crafting a wrapper to
8721022fd2aS 		 * run native suid commands with unsecure libraries interposed.
8731022fd2aS 		 */
8741022fd2aS 		if ((brand_action == EBA_NATIVE) && (PROC_IS_BRANDED(p) &&
8751022fd2aS 		    (setid &= ~EXECSETID_SETID) != 0))
8761022fd2aS 			auxf &= ~AF_SUN_SETUGID;
8771022fd2aS 
878b71d513aSedp 		/*
879b71d513aSedp 		 * Record the user addr of the auxflags aux vector entry
880b71d513aSedp 		 * since brands may optionally want to manipulate this field.
881b71d513aSedp 		 */
882b71d513aSedp 		args->auxp_auxflags =
883b71d513aSedp 		    (char *)((char *)args->stackend +
884b71d513aSedp 		    ((char *)&aux->a_type -
885b71d513aSedp 		    (char *)bigwad->elfargs));
886b71d513aSedp 		ADDAUX(aux, AT_SUN_AUXFLAGS, auxf);
887d2a70789SRichard Lowe 
8887c478bd9Sstevel@tonic-gate 		/*
8897c478bd9Sstevel@tonic-gate 		 * Hardware capability flag word (performance hints)
8907c478bd9Sstevel@tonic-gate 		 * Used for choosing faster library routines.
8917c478bd9Sstevel@tonic-gate 		 * (Potentially different between 32-bit and 64-bit ABIs)
8927c478bd9Sstevel@tonic-gate 		 */
893ebb8ac07SRobert Mustacchi 		if (args->to_model == DATAMODEL_NATIVE) {
8947c478bd9Sstevel@tonic-gate 			ADDAUX(aux, AT_SUN_HWCAP, auxv_hwcap)
895ebb8ac07SRobert Mustacchi 			ADDAUX(aux, AT_SUN_HWCAP2, auxv_hwcap_2)
89656726c7eSRobert Mustacchi 			ADDAUX(aux, AT_SUN_HWCAP3, auxv_hwcap_3)
897ebb8ac07SRobert Mustacchi 		} else {
8987c478bd9Sstevel@tonic-gate 			ADDAUX(aux, AT_SUN_HWCAP, auxv_hwcap32)
899ebb8ac07SRobert Mustacchi 			ADDAUX(aux, AT_SUN_HWCAP2, auxv_hwcap32_2)
90056726c7eSRobert Mustacchi 			ADDAUX(aux, AT_SUN_HWCAP3, auxv_hwcap32_3)
901ebb8ac07SRobert Mustacchi 		}
90256726c7eSRobert Mustacchi 
9039acbbeafSnn 		if (branded) {
9049acbbeafSnn 			/*
90507678296Ssl 			 * Reserve space for the brand-private aux vectors,
9069acbbeafSnn 			 * and record the user addr of that space.
9079acbbeafSnn 			 */
90807678296Ssl 			args->auxp_brand =
909396a100bSedp 			    (char *)((char *)args->stackend +
910396a100bSedp 			    ((char *)&aux->a_type -
911396a100bSedp 			    (char *)bigwad->elfargs));
91207678296Ssl 			ADDAUX(aux, AT_SUN_BRAND_AUX1, 0)
91307678296Ssl 			ADDAUX(aux, AT_SUN_BRAND_AUX2, 0)
91407678296Ssl 			ADDAUX(aux, AT_SUN_BRAND_AUX3, 0)
9159acbbeafSnn 		}
9169acbbeafSnn 
9172428aad8SPatrick Mooney 		/*
918d0158222SRobert Mustacchi 		 * Add the comm page auxv entry, mapping it in if needed. Also
919d0158222SRobert Mustacchi 		 * take care of the FPU entries.
9202428aad8SPatrick Mooney 		 */
9212428aad8SPatrick Mooney #if defined(__amd64)
922995a963fSToomas Soome 		if (args->commpage != (uintptr_t)NULL ||
923995a963fSToomas Soome 		    (args->commpage = (uintptr_t)comm_page_mapin()) !=
924995a963fSToomas Soome 		    (uintptr_t)NULL) {
9252428aad8SPatrick Mooney 			ADDAUX(aux, AT_SUN_COMMPAGE, args->commpage)
9262428aad8SPatrick Mooney 		} else {
9272428aad8SPatrick Mooney 			/*
9282428aad8SPatrick Mooney 			 * If the comm page cannot be mapped, pad out the auxv
9292428aad8SPatrick Mooney 			 * to satisfy later size checks.
9302428aad8SPatrick Mooney 			 */
9312428aad8SPatrick Mooney 			ADDAUX(aux, AT_NULL, 0)
9322428aad8SPatrick Mooney 		}
933d0158222SRobert Mustacchi 
934d0158222SRobert Mustacchi 		fptype = AT_386_FPINFO_NONE;
935d0158222SRobert Mustacchi 		fpu_auxv_info(&fptype, &fpsize);
936d0158222SRobert Mustacchi 		if (fptype != AT_386_FPINFO_NONE) {
937d0158222SRobert Mustacchi 			ADDAUX(aux, AT_SUN_FPTYPE, fptype)
938d0158222SRobert Mustacchi 			ADDAUX(aux, AT_SUN_FPSIZE, fpsize)
939d0158222SRobert Mustacchi 		} else {
940d0158222SRobert Mustacchi 			ADDAUX(aux, AT_NULL, 0)
941d0158222SRobert Mustacchi 			ADDAUX(aux, AT_NULL, 0)
942d0158222SRobert Mustacchi 		}
9432428aad8SPatrick Mooney #endif /* defined(__amd64) */
9442428aad8SPatrick Mooney 
9457c478bd9Sstevel@tonic-gate 		ADDAUX(aux, AT_NULL, 0)
9464e18e297SPatrick Mooney 		postfixsize = (uintptr_t)aux - (uintptr_t)bigwad->elfargs;
947386e9c9eSJerry Jelinek 
948386e9c9eSJerry Jelinek 		/*
949386e9c9eSJerry Jelinek 		 * We make assumptions above when we determine how many aux
950386e9c9eSJerry Jelinek 		 * vector entries we will be adding. However, if we have an
951386e9c9eSJerry Jelinek 		 * invalid elf file, it is possible that mapelfexec might
952386e9c9eSJerry Jelinek 		 * behave differently (but not return an error), in which case
953386e9c9eSJerry Jelinek 		 * the number of aux entries we actually add will be different.
954386e9c9eSJerry Jelinek 		 * We detect that now and error out.
955386e9c9eSJerry Jelinek 		 */
956386e9c9eSJerry Jelinek 		if (postfixsize != args->auxsize) {
9574e18e297SPatrick Mooney 			DTRACE_PROBE2(elfexec_badaux, size_t, postfixsize,
9584e18e297SPatrick Mooney 			    size_t, args->auxsize);
959386e9c9eSJerry Jelinek 			goto bad;
960386e9c9eSJerry Jelinek 		}
9617c478bd9Sstevel@tonic-gate 		ASSERT(postfixsize <= __KERN_NAUXV_IMPL * sizeof (aux_entry_t));
9627c478bd9Sstevel@tonic-gate 	}
9637c478bd9Sstevel@tonic-gate 
9647c478bd9Sstevel@tonic-gate 	/*
9657c478bd9Sstevel@tonic-gate 	 * For the 64-bit kernel, the limit is big enough that rounding it up
9667c478bd9Sstevel@tonic-gate 	 * to a page can overflow the 64-bit limit, so we check for btopr()
9677c478bd9Sstevel@tonic-gate 	 * overflowing here by comparing it with the unrounded limit in pages.
9687c478bd9Sstevel@tonic-gate 	 * If it hasn't overflowed, compare the exec size with the rounded up
9697c478bd9Sstevel@tonic-gate 	 * limit in pages.  Otherwise, just compare with the unrounded limit.
9707c478bd9Sstevel@tonic-gate 	 */
9717c478bd9Sstevel@tonic-gate 	limit = btop(p->p_vmem_ctl);
9727c478bd9Sstevel@tonic-gate 	roundlimit = btopr(p->p_vmem_ctl);
9737c478bd9Sstevel@tonic-gate 	if ((roundlimit > limit && *execsz > roundlimit) ||
9747c478bd9Sstevel@tonic-gate 	    (roundlimit < limit && *execsz > limit)) {
9757c478bd9Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
9767c478bd9Sstevel@tonic-gate 		(void) rctl_action(rctlproc_legacy[RLIMIT_VMEM], p->p_rctls, p,
9777c478bd9Sstevel@tonic-gate 		    RCA_SAFE);
9787c478bd9Sstevel@tonic-gate 		mutex_exit(&p->p_lock);
9797c478bd9Sstevel@tonic-gate 		error = ENOMEM;
9807c478bd9Sstevel@tonic-gate 		goto bad;
9817c478bd9Sstevel@tonic-gate 	}
9827c478bd9Sstevel@tonic-gate 
9837c478bd9Sstevel@tonic-gate 	bzero(up->u_auxv, sizeof (up->u_auxv));
9842428aad8SPatrick Mooney 	up->u_commpagep = args->commpage;
9857c478bd9Sstevel@tonic-gate 	if (postfixsize) {
9864e18e297SPatrick Mooney 		size_t num_auxv;
9877c478bd9Sstevel@tonic-gate 
9887c478bd9Sstevel@tonic-gate 		/*
9897c478bd9Sstevel@tonic-gate 		 * Copy the aux vector to the user stack.
9907c478bd9Sstevel@tonic-gate 		 */
9917c478bd9Sstevel@tonic-gate 		error = execpoststack(args, bigwad->elfargs, postfixsize);
9927c478bd9Sstevel@tonic-gate 		if (error)
9937c478bd9Sstevel@tonic-gate 			goto bad;
9947c478bd9Sstevel@tonic-gate 
9957c478bd9Sstevel@tonic-gate 		/*
9967c478bd9Sstevel@tonic-gate 		 * Copy auxv to the process's user structure for use by /proc.
9979acbbeafSnn 		 * If this is a branded process, the brand's exec routine will
9989acbbeafSnn 		 * copy it's private entries to the user structure later. It
9999acbbeafSnn 		 * relies on the fact that the blank entries are at the end.
10007c478bd9Sstevel@tonic-gate 		 */
10017c478bd9Sstevel@tonic-gate 		num_auxv = postfixsize / sizeof (aux_entry_t);
10027c478bd9Sstevel@tonic-gate 		ASSERT(num_auxv <= sizeof (up->u_auxv) / sizeof (auxv_t));
10037c478bd9Sstevel@tonic-gate 		aux = bigwad->elfargs;
10047c478bd9Sstevel@tonic-gate 		for (i = 0; i < num_auxv; i++) {
10057c478bd9Sstevel@tonic-gate 			up->u_auxv[i].a_type = aux[i].a_type;
10067c478bd9Sstevel@tonic-gate 			up->u_auxv[i].a_un.a_val = (aux_val_t)aux[i].a_un.a_val;
10077c478bd9Sstevel@tonic-gate 		}
10087c478bd9Sstevel@tonic-gate 	}
10097c478bd9Sstevel@tonic-gate 
10107c478bd9Sstevel@tonic-gate 	/*
10117c478bd9Sstevel@tonic-gate 	 * Pass back the starting address so we can set the program counter.
10127c478bd9Sstevel@tonic-gate 	 */
10137c478bd9Sstevel@tonic-gate 	args->entry = (uintptr_t)(ehdrp->e_entry + voffset);
10147c478bd9Sstevel@tonic-gate 
10157c478bd9Sstevel@tonic-gate 	if (!uphdr) {
10167c478bd9Sstevel@tonic-gate 		if (ehdrp->e_type == ET_DYN) {
10177c478bd9Sstevel@tonic-gate 			/*
10187c478bd9Sstevel@tonic-gate 			 * If we are executing a shared library which doesn't
10197c478bd9Sstevel@tonic-gate 			 * have a interpreter (probably ld.so.1) then
10207c478bd9Sstevel@tonic-gate 			 * we don't set the brkbase now.  Instead we
10217c478bd9Sstevel@tonic-gate 			 * delay it's setting until the first call
10227c478bd9Sstevel@tonic-gate 			 * via grow.c::brk().  This permits ld.so.1 to
10237c478bd9Sstevel@tonic-gate 			 * initialize brkbase to the tail of the executable it
10247c478bd9Sstevel@tonic-gate 			 * loads (which is where it needs to be).
10257c478bd9Sstevel@tonic-gate 			 */
10267c478bd9Sstevel@tonic-gate 			bigwad->exenv.ex_brkbase = (caddr_t)0;
10277c478bd9Sstevel@tonic-gate 			bigwad->exenv.ex_bssbase = (caddr_t)0;
10287c478bd9Sstevel@tonic-gate 			bigwad->exenv.ex_brksize = 0;
10297c478bd9Sstevel@tonic-gate 		} else {
10307c478bd9Sstevel@tonic-gate 			bigwad->exenv.ex_brkbase = brkbase;
10317c478bd9Sstevel@tonic-gate 			bigwad->exenv.ex_bssbase = bssbase;
10327c478bd9Sstevel@tonic-gate 			bigwad->exenv.ex_brksize = brksize;
10337c478bd9Sstevel@tonic-gate 		}
10347c478bd9Sstevel@tonic-gate 		bigwad->exenv.ex_magic = elfmagic;
10357c478bd9Sstevel@tonic-gate 		bigwad->exenv.ex_vp = vp;
10367c478bd9Sstevel@tonic-gate 		setexecenv(&bigwad->exenv);
10377c478bd9Sstevel@tonic-gate 	}
10387c478bd9Sstevel@tonic-gate 
10397c478bd9Sstevel@tonic-gate 	ASSERT(error == 0);
10407c478bd9Sstevel@tonic-gate 	goto out;
10417c478bd9Sstevel@tonic-gate 
10427c478bd9Sstevel@tonic-gate bad:
10437c478bd9Sstevel@tonic-gate 	if (fd != -1)		/* did we open the a.out yet */
10447c478bd9Sstevel@tonic-gate 		(void) execclose(fd);
10457c478bd9Sstevel@tonic-gate 
10467c478bd9Sstevel@tonic-gate 	psignal(p, SIGKILL);
10477c478bd9Sstevel@tonic-gate 
10487c478bd9Sstevel@tonic-gate 	if (error == 0)
10497c478bd9Sstevel@tonic-gate 		error = ENOEXEC;
10507c478bd9Sstevel@tonic-gate out:
10514e18e297SPatrick Mooney 	if (dynuphdr)
10524e18e297SPatrick Mooney 		kmem_free(uphdr, sizeof (Phdr));
10537c478bd9Sstevel@tonic-gate 	if (phdrbase != NULL)
10547c478bd9Sstevel@tonic-gate 		kmem_free(phdrbase, phdrsize);
1055a0de58d6SRoger A. Faulkner 	if (cap != NULL)
1056a0de58d6SRoger A. Faulkner 		kmem_free(cap, capsize);
10577c478bd9Sstevel@tonic-gate 	kmem_free(bigwad, sizeof (struct bigwad));
10587c478bd9Sstevel@tonic-gate 	return (error);
10597c478bd9Sstevel@tonic-gate }
10607c478bd9Sstevel@tonic-gate 
10617c478bd9Sstevel@tonic-gate /*
10627c478bd9Sstevel@tonic-gate  * Compute the memory size requirement for the ELF file.
10637c478bd9Sstevel@tonic-gate  */
10647c478bd9Sstevel@tonic-gate static size_t
elfsize(const Ehdr * ehdrp,uint_t nphdrs,const caddr_t phdrbase,uintptr_t * lddata)10654e18e297SPatrick Mooney elfsize(const Ehdr *ehdrp, uint_t nphdrs, const caddr_t phdrbase,
10664e18e297SPatrick Mooney     uintptr_t *lddata)
10677c478bd9Sstevel@tonic-gate {
10684e18e297SPatrick Mooney 	const Phdr *phdrp = (Phdr *)phdrbase;
10694e18e297SPatrick Mooney 	const uint_t hsize = ehdrp->e_phentsize;
10704e18e297SPatrick Mooney 	boolean_t dfirst = B_TRUE;
10714e18e297SPatrick Mooney 	uintptr_t loaddr = UINTPTR_MAX;
10727c478bd9Sstevel@tonic-gate 	uintptr_t hiaddr = 0;
10734e18e297SPatrick Mooney 	uint_t i;
10747c478bd9Sstevel@tonic-gate 
107530da1432Sahl 	for (i = nphdrs; i > 0; i--) {
10767c478bd9Sstevel@tonic-gate 		if (phdrp->p_type == PT_LOAD) {
10774e18e297SPatrick Mooney 			const uintptr_t lo = phdrp->p_vaddr;
10784e18e297SPatrick Mooney 			const uintptr_t hi = lo + phdrp->p_memsz;
10794e18e297SPatrick Mooney 
10804e18e297SPatrick Mooney 			loaddr = MIN(lo, loaddr);
10814e18e297SPatrick Mooney 			hiaddr = MAX(hi, hiaddr);
10827c478bd9Sstevel@tonic-gate 
10837c478bd9Sstevel@tonic-gate 			/*
10847c478bd9Sstevel@tonic-gate 			 * save the address of the first data segment
10857c478bd9Sstevel@tonic-gate 			 * of a object - used for the AT_SUNW_LDDATA
10867c478bd9Sstevel@tonic-gate 			 * aux entry.
10877c478bd9Sstevel@tonic-gate 			 */
10887c478bd9Sstevel@tonic-gate 			if ((lddata != NULL) && dfirst &&
10897c478bd9Sstevel@tonic-gate 			    (phdrp->p_flags & PF_W)) {
10907c478bd9Sstevel@tonic-gate 				*lddata = lo;
10914e18e297SPatrick Mooney 				dfirst = B_FALSE;
10927c478bd9Sstevel@tonic-gate 			}
10937c478bd9Sstevel@tonic-gate 		}
10947c478bd9Sstevel@tonic-gate 		phdrp = (Phdr *)((caddr_t)phdrp + hsize);
10957c478bd9Sstevel@tonic-gate 	}
10967c478bd9Sstevel@tonic-gate 
10974e18e297SPatrick Mooney 	if (hiaddr <= loaddr) {
10984e18e297SPatrick Mooney 		/* No non-zero PT_LOAD segment found */
10994e18e297SPatrick Mooney 		return (0);
11004e18e297SPatrick Mooney 	}
11017c478bd9Sstevel@tonic-gate 
11024e18e297SPatrick Mooney 	return (roundup(hiaddr - (loaddr & PAGEMASK), PAGESIZE));
11037c478bd9Sstevel@tonic-gate }
11047c478bd9Sstevel@tonic-gate 
11057c478bd9Sstevel@tonic-gate /*
11067c478bd9Sstevel@tonic-gate  * Read in the ELF header and program header table.
11077c478bd9Sstevel@tonic-gate  * SUSV3 requires:
11087c478bd9Sstevel@tonic-gate  *	ENOEXEC	File format is not recognized
11097c478bd9Sstevel@tonic-gate  *	EINVAL	Format recognized but execution not supported
11107c478bd9Sstevel@tonic-gate  */
11117c478bd9Sstevel@tonic-gate static int
getelfhead(vnode_t * vp,cred_t * credp,Ehdr * ehdr,uint_t * nshdrs,uint_t * shstrndx,uint_t * nphdrs)11124e18e297SPatrick Mooney getelfhead(vnode_t *vp, cred_t *credp, Ehdr *ehdr, uint_t *nshdrs,
11134e18e297SPatrick Mooney     uint_t *shstrndx, uint_t *nphdrs)
11147c478bd9Sstevel@tonic-gate {
11157c478bd9Sstevel@tonic-gate 	int error;
11167c478bd9Sstevel@tonic-gate 	ssize_t resid;
11177c478bd9Sstevel@tonic-gate 
11187c478bd9Sstevel@tonic-gate 	/*
11197c478bd9Sstevel@tonic-gate 	 * We got here by the first two bytes in ident,
11207c478bd9Sstevel@tonic-gate 	 * now read the entire ELF header.
11217c478bd9Sstevel@tonic-gate 	 */
11227c478bd9Sstevel@tonic-gate 	if ((error = vn_rdwr(UIO_READ, vp, (caddr_t)ehdr,
11237c478bd9Sstevel@tonic-gate 	    sizeof (Ehdr), (offset_t)0, UIO_SYSSPACE, 0,
11247c478bd9Sstevel@tonic-gate 	    (rlim64_t)0, credp, &resid)) != 0)
11257c478bd9Sstevel@tonic-gate 		return (error);
11267c478bd9Sstevel@tonic-gate 
11277c478bd9Sstevel@tonic-gate 	/*
11287c478bd9Sstevel@tonic-gate 	 * Since a separate version is compiled for handling 32-bit and
11297c478bd9Sstevel@tonic-gate 	 * 64-bit ELF executables on a 64-bit kernel, the 64-bit version
11307c478bd9Sstevel@tonic-gate 	 * doesn't need to be able to deal with 32-bit ELF files.
11317c478bd9Sstevel@tonic-gate 	 */
11327c478bd9Sstevel@tonic-gate 	if (resid != 0 ||
11337c478bd9Sstevel@tonic-gate 	    ehdr->e_ident[EI_MAG2] != ELFMAG2 ||
11347c478bd9Sstevel@tonic-gate 	    ehdr->e_ident[EI_MAG3] != ELFMAG3)
11357c478bd9Sstevel@tonic-gate 		return (ENOEXEC);
113630da1432Sahl 
11377c478bd9Sstevel@tonic-gate 	if ((ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN) ||
11387c478bd9Sstevel@tonic-gate #if defined(_ILP32) || defined(_ELF32_COMPAT)
11397c478bd9Sstevel@tonic-gate 	    ehdr->e_ident[EI_CLASS] != ELFCLASS32 ||
11407c478bd9Sstevel@tonic-gate #else
11417c478bd9Sstevel@tonic-gate 	    ehdr->e_ident[EI_CLASS] != ELFCLASS64 ||
11427c478bd9Sstevel@tonic-gate #endif
11437c478bd9Sstevel@tonic-gate 	    !elfheadcheck(ehdr->e_ident[EI_DATA], ehdr->e_machine,
114430da1432Sahl 	    ehdr->e_flags))
11457c478bd9Sstevel@tonic-gate 		return (EINVAL);
11467c478bd9Sstevel@tonic-gate 
114730da1432Sahl 	*nshdrs = ehdr->e_shnum;
114830da1432Sahl 	*shstrndx = ehdr->e_shstrndx;
114930da1432Sahl 	*nphdrs = ehdr->e_phnum;
115030da1432Sahl 
115130da1432Sahl 	/*
115230da1432Sahl 	 * If e_shnum, e_shstrndx, or e_phnum is its sentinel value, we need
11534e18e297SPatrick Mooney 	 * to read in the section header at index zero to access the true
115430da1432Sahl 	 * values for those fields.
115530da1432Sahl 	 */
115630da1432Sahl 	if ((*nshdrs == 0 && ehdr->e_shoff != 0) ||
115730da1432Sahl 	    *shstrndx == SHN_XINDEX || *nphdrs == PN_XNUM) {
115830da1432Sahl 		Shdr shdr;
115930da1432Sahl 
116030da1432Sahl 		if (ehdr->e_shoff == 0)
116130da1432Sahl 			return (EINVAL);
116230da1432Sahl 
116330da1432Sahl 		if ((error = vn_rdwr(UIO_READ, vp, (caddr_t)&shdr,
116430da1432Sahl 		    sizeof (shdr), (offset_t)ehdr->e_shoff, UIO_SYSSPACE, 0,
11654e18e297SPatrick Mooney 		    (rlim64_t)0, credp, NULL)) != 0) {
116630da1432Sahl 			return (error);
11674e18e297SPatrick Mooney 		}
116830da1432Sahl 
116930da1432Sahl 		if (*nshdrs == 0)
117030da1432Sahl 			*nshdrs = shdr.sh_size;
117130da1432Sahl 		if (*shstrndx == SHN_XINDEX)
117230da1432Sahl 			*shstrndx = shdr.sh_link;
117330da1432Sahl 		if (*nphdrs == PN_XNUM && shdr.sh_info != 0)
117430da1432Sahl 			*nphdrs = shdr.sh_info;
117530da1432Sahl 	}
117630da1432Sahl 
11777c478bd9Sstevel@tonic-gate 	return (0);
11787c478bd9Sstevel@tonic-gate }
11797c478bd9Sstevel@tonic-gate 
11804e18e297SPatrick Mooney /*
11814e18e297SPatrick Mooney  * We use members through p_flags on 32-bit files and p_memsz on 64-bit files,
11824e18e297SPatrick Mooney  * so e_phentsize must be at least large enough to include those members.
11834e18e297SPatrick Mooney  */
11844e18e297SPatrick Mooney #if !defined(_LP64) || defined(_ELF32_COMPAT)
11854e18e297SPatrick Mooney #define	MINPHENTSZ	(offsetof(Phdr, p_flags) + \
11864e18e297SPatrick Mooney 			sizeof (((Phdr *)NULL)->p_flags))
11877c478bd9Sstevel@tonic-gate #else
11884e18e297SPatrick Mooney #define	MINPHENTSZ	(offsetof(Phdr, p_memsz) + \
11894e18e297SPatrick Mooney 			sizeof (((Phdr *)NULL)->p_memsz))
11907c478bd9Sstevel@tonic-gate #endif
11917c478bd9Sstevel@tonic-gate 
11927c478bd9Sstevel@tonic-gate static int
getelfphdr(vnode_t * vp,cred_t * credp,const Ehdr * ehdr,uint_t nphdrs,caddr_t * phbasep,size_t * phsizep)11934e18e297SPatrick Mooney getelfphdr(vnode_t *vp, cred_t *credp, const Ehdr *ehdr, uint_t nphdrs,
11944e18e297SPatrick Mooney     caddr_t *phbasep, size_t *phsizep)
11957c478bd9Sstevel@tonic-gate {
11967c478bd9Sstevel@tonic-gate 	int err;
11977c478bd9Sstevel@tonic-gate 
11987c478bd9Sstevel@tonic-gate 	/*
11994e18e297SPatrick Mooney 	 * Ensure that e_phentsize is large enough for required fields to be
12004e18e297SPatrick Mooney 	 * accessible and will maintain 8-byte alignment.
12017c478bd9Sstevel@tonic-gate 	 */
12024e18e297SPatrick Mooney 	if (ehdr->e_phentsize < MINPHENTSZ || (ehdr->e_phentsize & 3))
12037c478bd9Sstevel@tonic-gate 		return (EINVAL);
12047c478bd9Sstevel@tonic-gate 
120530da1432Sahl 	*phsizep = nphdrs * ehdr->e_phentsize;
12067c478bd9Sstevel@tonic-gate 
12077c478bd9Sstevel@tonic-gate 	if (*phsizep > sizeof (Phdr) * elf_nphdr_max) {
12087c478bd9Sstevel@tonic-gate 		if ((*phbasep = kmem_alloc(*phsizep, KM_NOSLEEP)) == NULL)
12097c478bd9Sstevel@tonic-gate 			return (ENOMEM);
12107c478bd9Sstevel@tonic-gate 	} else {
12117c478bd9Sstevel@tonic-gate 		*phbasep = kmem_alloc(*phsizep, KM_SLEEP);
12127c478bd9Sstevel@tonic-gate 	}
12137c478bd9Sstevel@tonic-gate 
12144e18e297SPatrick Mooney 	if ((err = vn_rdwr(UIO_READ, vp, *phbasep, (ssize_t)*phsizep,
12157c478bd9Sstevel@tonic-gate 	    (offset_t)ehdr->e_phoff, UIO_SYSSPACE, 0, (rlim64_t)0,
12164e18e297SPatrick Mooney 	    credp, NULL)) != 0) {
12177c478bd9Sstevel@tonic-gate 		kmem_free(*phbasep, *phsizep);
12187c478bd9Sstevel@tonic-gate 		*phbasep = NULL;
12197c478bd9Sstevel@tonic-gate 		return (err);
12207c478bd9Sstevel@tonic-gate 	}
12217c478bd9Sstevel@tonic-gate 
12227c478bd9Sstevel@tonic-gate 	return (0);
12237c478bd9Sstevel@tonic-gate }
12247c478bd9Sstevel@tonic-gate 
12254e18e297SPatrick Mooney #define	MINSHDRSZ	(offsetof(Shdr, sh_entsize) + \
12264e18e297SPatrick Mooney 			sizeof (((Shdr *)NULL)->sh_entsize))
12277c478bd9Sstevel@tonic-gate 
12287c478bd9Sstevel@tonic-gate static int
getelfshdr(vnode_t * vp,cred_t * credp,const Ehdr * ehdr,uint_t nshdrs,uint_t shstrndx,caddr_t * shbasep,size_t * shsizep,char ** shstrbasep,size_t * shstrsizep)12294e18e297SPatrick Mooney getelfshdr(vnode_t *vp, cred_t *credp, const Ehdr *ehdr, uint_t nshdrs,
12304e18e297SPatrick Mooney     uint_t shstrndx, caddr_t *shbasep, size_t *shsizep, char **shstrbasep,
12314e18e297SPatrick Mooney     size_t *shstrsizep)
12327c478bd9Sstevel@tonic-gate {
12337c478bd9Sstevel@tonic-gate 	int err;
12347c478bd9Sstevel@tonic-gate 	Shdr *shdr;
12357c478bd9Sstevel@tonic-gate 
12367c478bd9Sstevel@tonic-gate 	/*
12377c478bd9Sstevel@tonic-gate 	 * Since we're going to be using e_shentsize to iterate down the
12387c478bd9Sstevel@tonic-gate 	 * array of section headers, it must be 8-byte aligned or else
12397c478bd9Sstevel@tonic-gate 	 * a we might cause a misaligned access. We use all members through
12407c478bd9Sstevel@tonic-gate 	 * sh_entsize (on both 32- and 64-bit ELF files) so e_shentsize
124130da1432Sahl 	 * must be at least large enough to include that member. The index
124230da1432Sahl 	 * of the string table section must also be valid.
12437c478bd9Sstevel@tonic-gate 	 */
12444e18e297SPatrick Mooney 	if (ehdr->e_shentsize < MINSHDRSZ || (ehdr->e_shentsize & 3) ||
12454e18e297SPatrick Mooney 	    nshdrs == 0 || shstrndx >= nshdrs) {
12467c478bd9Sstevel@tonic-gate 		return (EINVAL);
12474e18e297SPatrick Mooney 	}
12487c478bd9Sstevel@tonic-gate 
124930da1432Sahl 	*shsizep = nshdrs * ehdr->e_shentsize;
12507c478bd9Sstevel@tonic-gate 
12517c478bd9Sstevel@tonic-gate 	if (*shsizep > sizeof (Shdr) * elf_nshdr_max) {
12527c478bd9Sstevel@tonic-gate 		if ((*shbasep = kmem_alloc(*shsizep, KM_NOSLEEP)) == NULL)
12537c478bd9Sstevel@tonic-gate 			return (ENOMEM);
12547c478bd9Sstevel@tonic-gate 	} else {
12557c478bd9Sstevel@tonic-gate 		*shbasep = kmem_alloc(*shsizep, KM_SLEEP);
12567c478bd9Sstevel@tonic-gate 	}
12577c478bd9Sstevel@tonic-gate 
12584e18e297SPatrick Mooney 	if ((err = vn_rdwr(UIO_READ, vp, *shbasep, (ssize_t)*shsizep,
12597c478bd9Sstevel@tonic-gate 	    (offset_t)ehdr->e_shoff, UIO_SYSSPACE, 0, (rlim64_t)0,
12604e18e297SPatrick Mooney 	    credp, NULL)) != 0) {
12617c478bd9Sstevel@tonic-gate 		kmem_free(*shbasep, *shsizep);
12627c478bd9Sstevel@tonic-gate 		return (err);
12637c478bd9Sstevel@tonic-gate 	}
12647c478bd9Sstevel@tonic-gate 
12657c478bd9Sstevel@tonic-gate 	/*
12664e18e297SPatrick Mooney 	 * Grab the section string table.  Walking through the shdrs is
12674e18e297SPatrick Mooney 	 * pointless if their names cannot be interrogated.
12687c478bd9Sstevel@tonic-gate 	 */
126930da1432Sahl 	shdr = (Shdr *)(*shbasep + shstrndx * ehdr->e_shentsize);
12707c478bd9Sstevel@tonic-gate 	if ((*shstrsizep = shdr->sh_size) == 0) {
12717c478bd9Sstevel@tonic-gate 		kmem_free(*shbasep, *shsizep);
12727c478bd9Sstevel@tonic-gate 		return (EINVAL);
12737c478bd9Sstevel@tonic-gate 	}
12747c478bd9Sstevel@tonic-gate 
12757c478bd9Sstevel@tonic-gate 	if (*shstrsizep > elf_shstrtab_max) {
12767c478bd9Sstevel@tonic-gate 		if ((*shstrbasep = kmem_alloc(*shstrsizep,
12777c478bd9Sstevel@tonic-gate 		    KM_NOSLEEP)) == NULL) {
12787c478bd9Sstevel@tonic-gate 			kmem_free(*shbasep, *shsizep);
12797c478bd9Sstevel@tonic-gate 			return (ENOMEM);
12807c478bd9Sstevel@tonic-gate 		}
12817c478bd9Sstevel@tonic-gate 	} else {
12827c478bd9Sstevel@tonic-gate 		*shstrbasep = kmem_alloc(*shstrsizep, KM_SLEEP);
12837c478bd9Sstevel@tonic-gate 	}
12847c478bd9Sstevel@tonic-gate 
12854e18e297SPatrick Mooney 	if ((err = vn_rdwr(UIO_READ, vp, *shstrbasep, (ssize_t)*shstrsizep,
12867c478bd9Sstevel@tonic-gate 	    (offset_t)shdr->sh_offset, UIO_SYSSPACE, 0, (rlim64_t)0,
12874e18e297SPatrick Mooney 	    credp, NULL)) != 0) {
12887c478bd9Sstevel@tonic-gate 		kmem_free(*shbasep, *shsizep);
12897c478bd9Sstevel@tonic-gate 		kmem_free(*shstrbasep, *shstrsizep);
12907c478bd9Sstevel@tonic-gate 		return (err);
12917c478bd9Sstevel@tonic-gate 	}
12927c478bd9Sstevel@tonic-gate 
12937c478bd9Sstevel@tonic-gate 	/*
12947c478bd9Sstevel@tonic-gate 	 * Make sure the strtab is null-terminated to make sure we
12957c478bd9Sstevel@tonic-gate 	 * don't run off the end of the table.
12967c478bd9Sstevel@tonic-gate 	 */
12977c478bd9Sstevel@tonic-gate 	(*shstrbasep)[*shstrsizep - 1] = '\0';
12987c478bd9Sstevel@tonic-gate 
12997c478bd9Sstevel@tonic-gate 	return (0);
13007c478bd9Sstevel@tonic-gate }
13017c478bd9Sstevel@tonic-gate 
13024e18e297SPatrick Mooney int
elfreadhdr(vnode_t * vp,cred_t * credp,Ehdr * ehdrp,uint_t * nphdrs,caddr_t * phbasep,size_t * phsizep)13034e18e297SPatrick Mooney elfreadhdr(vnode_t *vp, cred_t *credp, Ehdr *ehdrp, uint_t *nphdrs,
13044e18e297SPatrick Mooney     caddr_t *phbasep, size_t *phsizep)
13054e18e297SPatrick Mooney {
13064e18e297SPatrick Mooney 	int error;
13074e18e297SPatrick Mooney 	uint_t nshdrs, shstrndx;
13084e18e297SPatrick Mooney 
13094e18e297SPatrick Mooney 	if ((error = getelfhead(vp, credp, ehdrp, &nshdrs, &shstrndx,
13104e18e297SPatrick Mooney 	    nphdrs)) != 0 ||
13114e18e297SPatrick Mooney 	    (error = getelfphdr(vp, credp, ehdrp, *nphdrs, phbasep,
13124e18e297SPatrick Mooney 	    phsizep)) != 0) {
13134e18e297SPatrick Mooney 		return (error);
13144e18e297SPatrick Mooney 	}
13154e18e297SPatrick Mooney 	return (0);
13164e18e297SPatrick Mooney }
13174e18e297SPatrick Mooney 
13187c478bd9Sstevel@tonic-gate static int
mapelfexec(vnode_t * vp,Ehdr * ehdr,uint_t nphdrs,caddr_t phdrbase,Phdr ** uphdr,Phdr ** intphdr,Phdr ** stphdr,Phdr ** dtphdr,Phdr * dataphdrp,caddr_t * bssbase,caddr_t * brkbase,intptr_t * voffset,uintptr_t * minaddrp,size_t len,size_t * execsz,size_t * brksize)13197c478bd9Sstevel@tonic-gate mapelfexec(
13207c478bd9Sstevel@tonic-gate 	vnode_t *vp,
13217c478bd9Sstevel@tonic-gate 	Ehdr *ehdr,
13224e18e297SPatrick Mooney 	uint_t nphdrs,
13237c478bd9Sstevel@tonic-gate 	caddr_t phdrbase,
13247c478bd9Sstevel@tonic-gate 	Phdr **uphdr,
1325d2a70789SRichard Lowe 	Phdr **intphdr,
13267c478bd9Sstevel@tonic-gate 	Phdr **stphdr,
13277c478bd9Sstevel@tonic-gate 	Phdr **dtphdr,
13287c478bd9Sstevel@tonic-gate 	Phdr *dataphdrp,
13297c478bd9Sstevel@tonic-gate 	caddr_t *bssbase,
13307c478bd9Sstevel@tonic-gate 	caddr_t *brkbase,
13317c478bd9Sstevel@tonic-gate 	intptr_t *voffset,
13324e18e297SPatrick Mooney 	uintptr_t *minaddrp,
13337c478bd9Sstevel@tonic-gate 	size_t len,
13344e18e297SPatrick Mooney 	size_t *execsz,
13357c478bd9Sstevel@tonic-gate 	size_t *brksize)
13367c478bd9Sstevel@tonic-gate {
13377c478bd9Sstevel@tonic-gate 	Phdr *phdr;
13384e18e297SPatrick Mooney 	int error, page, prot;
133960946fe0Smec 	caddr_t addr = NULL;
13404e18e297SPatrick Mooney 	caddr_t minaddr = (caddr_t)UINTPTR_MAX;
13414e18e297SPatrick Mooney 	uint_t i;
13424e18e297SPatrick Mooney 	size_t zfodsz, memsz;
13434e18e297SPatrick Mooney 	boolean_t ptload = B_FALSE;
13447c478bd9Sstevel@tonic-gate 	off_t offset;
13454e18e297SPatrick Mooney 	const uint_t hsize = ehdr->e_phentsize;
1346ec25b48fSsusans 	extern int use_brk_lpg;
13477c478bd9Sstevel@tonic-gate 
13487c478bd9Sstevel@tonic-gate 	if (ehdr->e_type == ET_DYN) {
1349d2a70789SRichard Lowe 		secflagset_t flags = 0;
13507c478bd9Sstevel@tonic-gate 		/*
13517c478bd9Sstevel@tonic-gate 		 * Obtain the virtual address of a hole in the
13527c478bd9Sstevel@tonic-gate 		 * address space to map the "interpreter".
13537c478bd9Sstevel@tonic-gate 		 */
1354d2a70789SRichard Lowe 		if (secflag_enabled(curproc, PROC_SEC_ASLR))
1355d2a70789SRichard Lowe 			flags |= _MAP_RANDOMIZE;
1356d2a70789SRichard Lowe 
1357d2a70789SRichard Lowe 		map_addr(&addr, len, (offset_t)0, 1, flags);
13587c478bd9Sstevel@tonic-gate 		if (addr == NULL)
13597c478bd9Sstevel@tonic-gate 			return (ENOMEM);
13607c478bd9Sstevel@tonic-gate 		*voffset = (intptr_t)addr;
136182e77048Seh 
136282e77048Seh 		/*
136382e77048Seh 		 * Calculate the minimum vaddr so it can be subtracted out.
136482e77048Seh 		 * According to the ELF specification, since PT_LOAD sections
136582e77048Seh 		 * must be sorted by increasing p_vaddr values, this is
136682e77048Seh 		 * guaranteed to be the first PT_LOAD section.
136782e77048Seh 		 */
136882e77048Seh 		phdr = (Phdr *)phdrbase;
136982e77048Seh 		for (i = nphdrs; i > 0; i--) {
137082e77048Seh 			if (phdr->p_type == PT_LOAD) {
137182e77048Seh 				*voffset -= (uintptr_t)phdr->p_vaddr;
137282e77048Seh 				break;
137382e77048Seh 			}
137482e77048Seh 			phdr = (Phdr *)((caddr_t)phdr + hsize);
137582e77048Seh 		}
137682e77048Seh 
13777c478bd9Sstevel@tonic-gate 	} else {
13787c478bd9Sstevel@tonic-gate 		*voffset = 0;
13797c478bd9Sstevel@tonic-gate 	}
13804e18e297SPatrick Mooney 
13817c478bd9Sstevel@tonic-gate 	phdr = (Phdr *)phdrbase;
138230da1432Sahl 	for (i = nphdrs; i > 0; i--) {
13837c478bd9Sstevel@tonic-gate 		switch (phdr->p_type) {
13847c478bd9Sstevel@tonic-gate 		case PT_LOAD:
13854e18e297SPatrick Mooney 			ptload = B_TRUE;
13867c478bd9Sstevel@tonic-gate 			prot = PROT_USER;
13877c478bd9Sstevel@tonic-gate 			if (phdr->p_flags & PF_R)
13887c478bd9Sstevel@tonic-gate 				prot |= PROT_READ;
13897c478bd9Sstevel@tonic-gate 			if (phdr->p_flags & PF_W)
13907c478bd9Sstevel@tonic-gate 				prot |= PROT_WRITE;
13917c478bd9Sstevel@tonic-gate 			if (phdr->p_flags & PF_X)
13927c478bd9Sstevel@tonic-gate 				prot |= PROT_EXEC;
13937c478bd9Sstevel@tonic-gate 
13947c478bd9Sstevel@tonic-gate 			addr = (caddr_t)((uintptr_t)phdr->p_vaddr + *voffset);
13959acbbeafSnn 
13964e18e297SPatrick Mooney 			if (*intphdr != NULL && uphdr != NULL &&
13974e18e297SPatrick Mooney 			    *uphdr == NULL) {
13984e18e297SPatrick Mooney 				/*
13994e18e297SPatrick Mooney 				 * The PT_PHDR program header is, strictly
14004e18e297SPatrick Mooney 				 * speaking, optional.  If we find that this
14014e18e297SPatrick Mooney 				 * is missing, we will determine the location
14024e18e297SPatrick Mooney 				 * of the program headers based on the address
14034e18e297SPatrick Mooney 				 * of the lowest PT_LOAD segment (namely, this
14044e18e297SPatrick Mooney 				 * one):  we subtract the p_offset to get to
14054e18e297SPatrick Mooney 				 * the ELF header and then add back the program
14064e18e297SPatrick Mooney 				 * header offset to get to the program headers.
14074e18e297SPatrick Mooney 				 * We then cons up a Phdr that corresponds to
14084e18e297SPatrick Mooney 				 * the (missing) PT_PHDR, setting the flags
14094e18e297SPatrick Mooney 				 * to 0 to denote that this is artificial and
14104e18e297SPatrick Mooney 				 * should (must) be freed by the caller.
14114e18e297SPatrick Mooney 				 */
14124e18e297SPatrick Mooney 				Phdr *cons;
14134e18e297SPatrick Mooney 
14144e18e297SPatrick Mooney 				cons = kmem_zalloc(sizeof (Phdr), KM_SLEEP);
14154e18e297SPatrick Mooney 
14164e18e297SPatrick Mooney 				cons->p_flags = 0;
14174e18e297SPatrick Mooney 				cons->p_type = PT_PHDR;
14184e18e297SPatrick Mooney 				cons->p_vaddr = ((uintptr_t)addr -
14194e18e297SPatrick Mooney 				    phdr->p_offset) + ehdr->e_phoff;
14204e18e297SPatrick Mooney 
14214e18e297SPatrick Mooney 				*uphdr = cons;
14224e18e297SPatrick Mooney 			}
14234e18e297SPatrick Mooney 
14244e18e297SPatrick Mooney 			/*
14254e18e297SPatrick Mooney 			 * The ELF spec dictates that p_filesz may not be
14264e18e297SPatrick Mooney 			 * larger than p_memsz in PT_LOAD segments.
14274e18e297SPatrick Mooney 			 */
14284e18e297SPatrick Mooney 			if (phdr->p_filesz > phdr->p_memsz) {
14294e18e297SPatrick Mooney 				error = EINVAL;
14304e18e297SPatrick Mooney 				goto bad;
14314e18e297SPatrick Mooney 			}
14324e18e297SPatrick Mooney 
14339acbbeafSnn 			/*
14349acbbeafSnn 			 * Keep track of the segment with the lowest starting
14359acbbeafSnn 			 * address.
14369acbbeafSnn 			 */
14374e18e297SPatrick Mooney 			if (addr < minaddr)
14384e18e297SPatrick Mooney 				minaddr = addr;
14399acbbeafSnn 
14407c478bd9Sstevel@tonic-gate 			zfodsz = (size_t)phdr->p_memsz - phdr->p_filesz;
14417c478bd9Sstevel@tonic-gate 
14427c478bd9Sstevel@tonic-gate 			offset = phdr->p_offset;
14437c478bd9Sstevel@tonic-gate 			if (((uintptr_t)offset & PAGEOFFSET) ==
14447c478bd9Sstevel@tonic-gate 			    ((uintptr_t)addr & PAGEOFFSET) &&
144507678296Ssl 			    (!(vp->v_flag & VNOMAP))) {
14467c478bd9Sstevel@tonic-gate 				page = 1;
14477c478bd9Sstevel@tonic-gate 			} else {
14487c478bd9Sstevel@tonic-gate 				page = 0;
14497c478bd9Sstevel@tonic-gate 			}
14507c478bd9Sstevel@tonic-gate 
1451ec25b48fSsusans 			/*
1452ec25b48fSsusans 			 * Set the heap pagesize for OOB when the bss size
1453ec25b48fSsusans 			 * is known and use_brk_lpg is not 0.
1454ec25b48fSsusans 			 */
1455ec25b48fSsusans 			if (brksize != NULL && use_brk_lpg &&
1456ec25b48fSsusans 			    zfodsz != 0 && phdr == dataphdrp &&
1457ec25b48fSsusans 			    (prot & PROT_WRITE)) {
14584e18e297SPatrick Mooney 				const size_t tlen = P2NPHASE((uintptr_t)addr +
1459ec25b48fSsusans 				    phdr->p_filesz, PAGESIZE);
1460ec25b48fSsusans 
1461ec25b48fSsusans 				if (zfodsz > tlen) {
14624e18e297SPatrick Mooney 					const caddr_t taddr = addr +
14634e18e297SPatrick Mooney 					    phdr->p_filesz + tlen;
14644e18e297SPatrick Mooney 
14654e18e297SPatrick Mooney 					/*
14664e18e297SPatrick Mooney 					 * Since a hole in the AS large enough
14674e18e297SPatrick Mooney 					 * for this object as calculated by
14684e18e297SPatrick Mooney 					 * elfsize() is available, we do not
14694e18e297SPatrick Mooney 					 * need to fear overflow for 'taddr'.
14704e18e297SPatrick Mooney 					 */
1471ec25b48fSsusans 					curproc->p_brkpageszc =
1472ec25b48fSsusans 					    page_szc(map_pgsz(MAPPGSZ_HEAP,
14734e18e297SPatrick Mooney 					    curproc, taddr, zfodsz - tlen, 0));
1474ec25b48fSsusans 				}
1475ec25b48fSsusans 			}
1476ec25b48fSsusans 
14773486346cSdavemq 			if (curproc->p_brkpageszc != 0 && phdr == dataphdrp &&
14783486346cSdavemq 			    (prot & PROT_WRITE)) {
14797c478bd9Sstevel@tonic-gate 				uint_t	szc = curproc->p_brkpageszc;
14807c478bd9Sstevel@tonic-gate 				size_t pgsz = page_get_pagesize(szc);
1481ec25b48fSsusans 				caddr_t ebss = addr + phdr->p_memsz;
1482d2a70789SRichard Lowe 				/*
1483d2a70789SRichard Lowe 				 * If we need extra space to keep the BSS an
1484d2a70789SRichard Lowe 				 * integral number of pages in size, some of
1485d2a70789SRichard Lowe 				 * that space may fall beyond p_brkbase, so we
1486d2a70789SRichard Lowe 				 * need to set p_brksize to account for it
1487d2a70789SRichard Lowe 				 * being (logically) part of the brk.
1488d2a70789SRichard Lowe 				 */
1489ec25b48fSsusans 				size_t extra_zfodsz;
14907c478bd9Sstevel@tonic-gate 
14917c478bd9Sstevel@tonic-gate 				ASSERT(pgsz > PAGESIZE);
14927c478bd9Sstevel@tonic-gate 
1493ec25b48fSsusans 				extra_zfodsz = P2NPHASE((uintptr_t)ebss, pgsz);
1494ec25b48fSsusans 
14957c478bd9Sstevel@tonic-gate 				if (error = execmap(vp, addr, phdr->p_filesz,
1496ec25b48fSsusans 				    zfodsz + extra_zfodsz, phdr->p_offset,
1497ec25b48fSsusans 				    prot, page, szc))
14987c478bd9Sstevel@tonic-gate 					goto bad;
14997c478bd9Sstevel@tonic-gate 				if (brksize != NULL)
1500ec25b48fSsusans 					*brksize = extra_zfodsz;
15017c478bd9Sstevel@tonic-gate 			} else {
15027c478bd9Sstevel@tonic-gate 				if (error = execmap(vp, addr, phdr->p_filesz,
15037c478bd9Sstevel@tonic-gate 				    zfodsz, phdr->p_offset, prot, page, 0))
15047c478bd9Sstevel@tonic-gate 					goto bad;
15057c478bd9Sstevel@tonic-gate 			}
15067c478bd9Sstevel@tonic-gate 
15077c478bd9Sstevel@tonic-gate 			if (bssbase != NULL && addr >= *bssbase &&
15087c478bd9Sstevel@tonic-gate 			    phdr == dataphdrp) {
15097c478bd9Sstevel@tonic-gate 				*bssbase = addr + phdr->p_filesz;
15107c478bd9Sstevel@tonic-gate 			}
15117c478bd9Sstevel@tonic-gate 			if (brkbase != NULL && addr >= *brkbase) {
15127c478bd9Sstevel@tonic-gate 				*brkbase = addr + phdr->p_memsz;
15137c478bd9Sstevel@tonic-gate 			}
15147c478bd9Sstevel@tonic-gate 
15154e18e297SPatrick Mooney 			memsz = btopr(phdr->p_memsz);
15164e18e297SPatrick Mooney 			if ((*execsz + memsz) < *execsz) {
15174e18e297SPatrick Mooney 				error = ENOMEM;
15184e18e297SPatrick Mooney 				goto bad;
15194e18e297SPatrick Mooney 			}
15204e18e297SPatrick Mooney 			*execsz += memsz;
15217c478bd9Sstevel@tonic-gate 			break;
15227c478bd9Sstevel@tonic-gate 
15237c478bd9Sstevel@tonic-gate 		case PT_INTERP:
15247c478bd9Sstevel@tonic-gate 			if (ptload)
15257c478bd9Sstevel@tonic-gate 				goto bad;
1526d2a70789SRichard Lowe 			*intphdr = phdr;
15277c478bd9Sstevel@tonic-gate 			break;
15287c478bd9Sstevel@tonic-gate 
15297c478bd9Sstevel@tonic-gate 		case PT_SHLIB:
15307c478bd9Sstevel@tonic-gate 			*stphdr = phdr;
15317c478bd9Sstevel@tonic-gate 			break;
15327c478bd9Sstevel@tonic-gate 
15337c478bd9Sstevel@tonic-gate 		case PT_PHDR:
15344e18e297SPatrick Mooney 			if (ptload || phdr->p_flags == 0)
15357c478bd9Sstevel@tonic-gate 				goto bad;
15364e18e297SPatrick Mooney 
15374e18e297SPatrick Mooney 			if (uphdr != NULL)
15384e18e297SPatrick Mooney 				*uphdr = phdr;
15394e18e297SPatrick Mooney 
15407c478bd9Sstevel@tonic-gate 			break;
15417c478bd9Sstevel@tonic-gate 
15427c478bd9Sstevel@tonic-gate 		case PT_NULL:
15437c478bd9Sstevel@tonic-gate 		case PT_DYNAMIC:
15447c478bd9Sstevel@tonic-gate 		case PT_NOTE:
15457c478bd9Sstevel@tonic-gate 			break;
15467c478bd9Sstevel@tonic-gate 
15477c478bd9Sstevel@tonic-gate 		case PT_SUNWDTRACE:
15487c478bd9Sstevel@tonic-gate 			if (dtphdr != NULL)
15497c478bd9Sstevel@tonic-gate 				*dtphdr = phdr;
15507c478bd9Sstevel@tonic-gate 			break;
15517c478bd9Sstevel@tonic-gate 
15527c478bd9Sstevel@tonic-gate 		default:
15537c478bd9Sstevel@tonic-gate 			break;
15547c478bd9Sstevel@tonic-gate 		}
15557c478bd9Sstevel@tonic-gate 		phdr = (Phdr *)((caddr_t)phdr + hsize);
15567c478bd9Sstevel@tonic-gate 	}
15579acbbeafSnn 
15584e18e297SPatrick Mooney 	if (minaddrp != NULL) {
15594e18e297SPatrick Mooney 		ASSERT(minaddr != (caddr_t)UINTPTR_MAX);
15604e18e297SPatrick Mooney 		*minaddrp = (uintptr_t)minaddr;
15619acbbeafSnn 	}
15629acbbeafSnn 
1563d2a70789SRichard Lowe 	if (brkbase != NULL && secflag_enabled(curproc, PROC_SEC_ASLR)) {
1564d2a70789SRichard Lowe 		size_t off;
1565d2a70789SRichard Lowe 		uintptr_t base = (uintptr_t)*brkbase;
1566d2a70789SRichard Lowe 		uintptr_t oend = base + *brksize;
1567d2a70789SRichard Lowe 
1568d2a70789SRichard Lowe 		ASSERT(ISP2(aslr_max_brk_skew));
1569d2a70789SRichard Lowe 
1570d2a70789SRichard Lowe 		(void) random_get_pseudo_bytes((uint8_t *)&off, sizeof (off));
1571d2a70789SRichard Lowe 		base += P2PHASE(off, aslr_max_brk_skew);
1572d2a70789SRichard Lowe 		base = P2ROUNDUP(base, PAGESIZE);
1573d2a70789SRichard Lowe 		*brkbase = (caddr_t)base;
1574d2a70789SRichard Lowe 		/*
1575d2a70789SRichard Lowe 		 * Above, we set *brksize to account for the possibility we
1576d2a70789SRichard Lowe 		 * had to grow the 'brk' in padding out the BSS to a page
1577d2a70789SRichard Lowe 		 * boundary.
1578d2a70789SRichard Lowe 		 *
1579d2a70789SRichard Lowe 		 * We now need to adjust that based on where we now are
1580d2a70789SRichard Lowe 		 * actually putting the brk.
1581d2a70789SRichard Lowe 		 */
1582d2a70789SRichard Lowe 		if (oend > base)
1583d2a70789SRichard Lowe 			*brksize = oend - base;
1584d2a70789SRichard Lowe 		else
1585d2a70789SRichard Lowe 			*brksize = 0;
1586d2a70789SRichard Lowe 	}
1587d2a70789SRichard Lowe 
15887c478bd9Sstevel@tonic-gate 	return (0);
15897c478bd9Sstevel@tonic-gate bad:
15907c478bd9Sstevel@tonic-gate 	if (error == 0)
15917c478bd9Sstevel@tonic-gate 		error = EINVAL;
15927c478bd9Sstevel@tonic-gate 	return (error);
15937c478bd9Sstevel@tonic-gate }
15947c478bd9Sstevel@tonic-gate 
15957c478bd9Sstevel@tonic-gate int
elfnote(vnode_t * vp,offset_t * offsetp,int type,int descsz,void * desc,rlim64_t rlimit,cred_t * credp)15967c478bd9Sstevel@tonic-gate elfnote(vnode_t *vp, offset_t *offsetp, int type, int descsz, void *desc,
15977c478bd9Sstevel@tonic-gate     rlim64_t rlimit, cred_t *credp)
15987c478bd9Sstevel@tonic-gate {
15997c478bd9Sstevel@tonic-gate 	Note note;
16007c478bd9Sstevel@tonic-gate 	int error;
16017c478bd9Sstevel@tonic-gate 
16027c478bd9Sstevel@tonic-gate 	bzero(&note, sizeof (note));
16037c478bd9Sstevel@tonic-gate 	bcopy("CORE", note.name, 4);
16047c478bd9Sstevel@tonic-gate 	note.nhdr.n_type = type;
16057c478bd9Sstevel@tonic-gate 	/*
16067c478bd9Sstevel@tonic-gate 	 * The System V ABI states that n_namesz must be the length of the
16077c478bd9Sstevel@tonic-gate 	 * string that follows the Nhdr structure including the terminating
16087c478bd9Sstevel@tonic-gate 	 * null. The ABI also specifies that sufficient padding should be
16097c478bd9Sstevel@tonic-gate 	 * included so that the description that follows the name string
16107c478bd9Sstevel@tonic-gate 	 * begins on a 4- or 8-byte boundary for 32- and 64-bit binaries
16117c478bd9Sstevel@tonic-gate 	 * respectively. However, since this change was not made correctly
16127c478bd9Sstevel@tonic-gate 	 * at the time of the 64-bit port, both 32- and 64-bit binaries
16137c478bd9Sstevel@tonic-gate 	 * descriptions are only guaranteed to begin on a 4-byte boundary.
16147c478bd9Sstevel@tonic-gate 	 */
16157c478bd9Sstevel@tonic-gate 	note.nhdr.n_namesz = 5;
16167c478bd9Sstevel@tonic-gate 	note.nhdr.n_descsz = roundup(descsz, sizeof (Word));
16177c478bd9Sstevel@tonic-gate 
16187c478bd9Sstevel@tonic-gate 	if (error = core_write(vp, UIO_SYSSPACE, *offsetp, &note,
16197c478bd9Sstevel@tonic-gate 	    sizeof (note), rlimit, credp))
16207c478bd9Sstevel@tonic-gate 		return (error);
16217c478bd9Sstevel@tonic-gate 
16227c478bd9Sstevel@tonic-gate 	*offsetp += sizeof (note);
16237c478bd9Sstevel@tonic-gate 
16247c478bd9Sstevel@tonic-gate 	if (error = core_write(vp, UIO_SYSSPACE, *offsetp, desc,
16257c478bd9Sstevel@tonic-gate 	    note.nhdr.n_descsz, rlimit, credp))
16267c478bd9Sstevel@tonic-gate 		return (error);
16277c478bd9Sstevel@tonic-gate 
16287c478bd9Sstevel@tonic-gate 	*offsetp += note.nhdr.n_descsz;
16297c478bd9Sstevel@tonic-gate 	return (0);
16307c478bd9Sstevel@tonic-gate }
16317c478bd9Sstevel@tonic-gate 
16327c478bd9Sstevel@tonic-gate /*
16337c478bd9Sstevel@tonic-gate  * Copy the section data from one vnode to the section of another vnode.
16347c478bd9Sstevel@tonic-gate  */
16357c478bd9Sstevel@tonic-gate static void
elf_copy_scn(elf_core_ctx_t * ctx,const Shdr * src,vnode_t * src_vp,Shdr * dst)16364e18e297SPatrick Mooney elf_copy_scn(elf_core_ctx_t *ctx, const Shdr *src, vnode_t *src_vp, Shdr *dst)
16377c478bd9Sstevel@tonic-gate {
16384e18e297SPatrick Mooney 	size_t n = src->sh_size;
16394e18e297SPatrick Mooney 	u_offset_t off = 0;
16404e18e297SPatrick Mooney 	const u_offset_t soff = src->sh_offset;
16414e18e297SPatrick Mooney 	const u_offset_t doff = ctx->ecc_doffset;
16424e18e297SPatrick Mooney 	void *buf = ctx->ecc_buf;
16434e18e297SPatrick Mooney 	vnode_t *dst_vp = ctx->ecc_vp;
16444e18e297SPatrick Mooney 	cred_t *credp = ctx->ecc_credp;
16454e18e297SPatrick Mooney 
16464e18e297SPatrick Mooney 	/* Protect the copy loop below from overflow on the offsets */
16474e18e297SPatrick Mooney 	if (n > OFF_MAX || (n + soff) > OFF_MAX || (n + doff) > OFF_MAX ||
16484e18e297SPatrick Mooney 	    (n + soff) < n || (n + doff) < n) {
16494e18e297SPatrick Mooney 		dst->sh_size = 0;
16504e18e297SPatrick Mooney 		dst->sh_offset = 0;
16514e18e297SPatrick Mooney 		return;
16524e18e297SPatrick Mooney 	}
16537c478bd9Sstevel@tonic-gate 
16547c478bd9Sstevel@tonic-gate 	while (n != 0) {
16554e18e297SPatrick Mooney 		const size_t len = MIN(ctx->ecc_bufsz, n);
16564e18e297SPatrick Mooney 		ssize_t resid;
16574e18e297SPatrick Mooney 
16584e18e297SPatrick Mooney 		if (vn_rdwr(UIO_READ, src_vp, buf, (ssize_t)len,
16594e18e297SPatrick Mooney 		    (offset_t)(soff + off),
16607c478bd9Sstevel@tonic-gate 		    UIO_SYSSPACE, 0, (rlim64_t)0, credp, &resid) != 0 ||
16614e18e297SPatrick Mooney 		    resid >= len || resid < 0 ||
16624e18e297SPatrick Mooney 		    core_write(dst_vp, UIO_SYSSPACE, (offset_t)(doff + off),
16634e18e297SPatrick Mooney 		    buf, len - resid, ctx->ecc_rlimit, credp) != 0) {
16647c478bd9Sstevel@tonic-gate 			dst->sh_size = 0;
16657c478bd9Sstevel@tonic-gate 			dst->sh_offset = 0;
16667c478bd9Sstevel@tonic-gate 			return;
16677c478bd9Sstevel@tonic-gate 		}
16687c478bd9Sstevel@tonic-gate 
16697c478bd9Sstevel@tonic-gate 		ASSERT(n >= len - resid);
16707c478bd9Sstevel@tonic-gate 
16717c478bd9Sstevel@tonic-gate 		n -= len - resid;
16727c478bd9Sstevel@tonic-gate 		off += len - resid;
16737c478bd9Sstevel@tonic-gate 	}
16747c478bd9Sstevel@tonic-gate 
16754e18e297SPatrick Mooney 	ctx->ecc_doffset += src->sh_size;
16767c478bd9Sstevel@tonic-gate }
16777c478bd9Sstevel@tonic-gate 
16784e18e297SPatrick Mooney /*
16794e18e297SPatrick Mooney  * Walk sections for a given ELF object, counting (or copying) those of
16804e18e297SPatrick Mooney  * interest (CTF, symtab, strtab, .debug_*).
16814e18e297SPatrick Mooney  */
16824e18e297SPatrick Mooney static int
elf_process_obj_scns(elf_core_ctx_t * ctx,vnode_t * mvp,caddr_t saddr,Shdr * v,uint_t idx,const uint_t remain,shstrtab_t * shstrtab,uint_t * countp)16834e18e297SPatrick Mooney elf_process_obj_scns(elf_core_ctx_t *ctx, vnode_t *mvp, caddr_t saddr,
1684*6233c8a8SAndy Fiddaman     Shdr *v, uint_t idx, const uint_t remain, shstrtab_t *shstrtab,
1685*6233c8a8SAndy Fiddaman     uint_t *countp)
16864e18e297SPatrick Mooney {
16874e18e297SPatrick Mooney 	Ehdr ehdr;
16884e18e297SPatrick Mooney 	const core_content_t content = ctx->ecc_content;
16894e18e297SPatrick Mooney 	cred_t *credp = ctx->ecc_credp;
16904e18e297SPatrick Mooney 	Shdr *ctf = NULL, *symtab = NULL, *strtab = NULL;
16914e18e297SPatrick Mooney 	uintptr_t off = 0;
1692*6233c8a8SAndy Fiddaman 	uint_t nshdrs, shstrndx, nphdrs, count, extra;
16934e18e297SPatrick Mooney 	u_offset_t *doffp = &ctx->ecc_doffset;
16944e18e297SPatrick Mooney 	boolean_t ctf_link = B_FALSE;
16954e18e297SPatrick Mooney 	caddr_t shbase;
16964e18e297SPatrick Mooney 	size_t shsize, shstrsize;
16974e18e297SPatrick Mooney 	char *shstrbase;
16984e18e297SPatrick Mooney 	int error = 0;
1699*6233c8a8SAndy Fiddaman 	const boolean_t justcounting = (v == NULL);
17004e18e297SPatrick Mooney 
1701*6233c8a8SAndy Fiddaman 	/*
1702*6233c8a8SAndy Fiddaman 	 * remain must be less than UINT_MAX so we can check for count
1703*6233c8a8SAndy Fiddaman 	 * exceeding it.
1704*6233c8a8SAndy Fiddaman 	 */
1705*6233c8a8SAndy Fiddaman 	ASSERT3U(remain, <, UINT_MAX);
1706*6233c8a8SAndy Fiddaman 
1707*6233c8a8SAndy Fiddaman 	*countp = count = 0;
17084e18e297SPatrick Mooney 
17094e18e297SPatrick Mooney 	if ((content &
17104e18e297SPatrick Mooney 	    (CC_CONTENT_CTF | CC_CONTENT_SYMTAB | CC_CONTENT_DEBUG)) == 0) {
17114e18e297SPatrick Mooney 		return (0);
17124e18e297SPatrick Mooney 	}
17134e18e297SPatrick Mooney 
17144e18e297SPatrick Mooney 	if (getelfhead(mvp, credp, &ehdr, &nshdrs, &shstrndx, &nphdrs) != 0 ||
17154e18e297SPatrick Mooney 	    getelfshdr(mvp, credp, &ehdr, nshdrs, shstrndx, &shbase, &shsize,
17164e18e297SPatrick Mooney 	    &shstrbase, &shstrsize) != 0) {
17174e18e297SPatrick Mooney 		return (0);
17184e18e297SPatrick Mooney 	}
17194e18e297SPatrick Mooney 
17204e18e297SPatrick Mooney 	/* Starting at index 1 skips SHT_NULL which is expected at index 0 */
17214e18e297SPatrick Mooney 	off = ehdr.e_shentsize;
17224e18e297SPatrick Mooney 	for (uint_t i = 1; i < nshdrs; i++, off += ehdr.e_shentsize) {
17234e18e297SPatrick Mooney 		Shdr *shdr, *symchk = NULL, *strchk;
17244e18e297SPatrick Mooney 		const char *name;
17254e18e297SPatrick Mooney 
17264e18e297SPatrick Mooney 		shdr = (Shdr *)(shbase + off);
17274e18e297SPatrick Mooney 		if (shdr->sh_name >= shstrsize || shdr->sh_type == SHT_NULL)
17284e18e297SPatrick Mooney 			continue;
17294e18e297SPatrick Mooney 
17304e18e297SPatrick Mooney 		name = shstrbase + shdr->sh_name;
17314e18e297SPatrick Mooney 
1732*6233c8a8SAndy Fiddaman 		if (ctf == NULL && (content & CC_CONTENT_CTF) != 0 &&
17334e18e297SPatrick Mooney 		    strcmp(name, shstrtab_data[STR_CTF]) == 0) {
17344e18e297SPatrick Mooney 			ctf = shdr;
17354e18e297SPatrick Mooney 			if (ctf->sh_link != 0 && ctf->sh_link < nshdrs) {
17364e18e297SPatrick Mooney 				/* check linked symtab below */
17374e18e297SPatrick Mooney 				symchk = (Shdr *)(shbase +
17384e18e297SPatrick Mooney 				    shdr->sh_link * ehdr.e_shentsize);
17394e18e297SPatrick Mooney 				ctf_link = B_TRUE;
17404e18e297SPatrick Mooney 			} else {
17414e18e297SPatrick Mooney 				continue;
17424e18e297SPatrick Mooney 			}
17434e18e297SPatrick Mooney 		} else if (symtab == NULL &&
17444e18e297SPatrick Mooney 		    (content & CC_CONTENT_SYMTAB) != 0 &&
17454e18e297SPatrick Mooney 		    strcmp(name, shstrtab_data[STR_SYMTAB]) == 0) {
17464e18e297SPatrick Mooney 			symchk = shdr;
17474e18e297SPatrick Mooney 		} else if ((content & CC_CONTENT_DEBUG) != 0 &&
17484e18e297SPatrick Mooney 		    strncmp(name, ".debug_", strlen(".debug_")) == 0) {
17494e18e297SPatrick Mooney 			/*
17504e18e297SPatrick Mooney 			 * The design of the above check is intentional. In
17514e18e297SPatrick Mooney 			 * particular, we want to capture any sections that
17524e18e297SPatrick Mooney 			 * begin with '.debug_' for a few reasons:
17534e18e297SPatrick Mooney 			 *
17544e18e297SPatrick Mooney 			 * 1) Various revisions to the DWARF spec end up
17554e18e297SPatrick Mooney 			 * changing the set of section headers that exist. This
17564e18e297SPatrick Mooney 			 * ensures that we don't need to change the kernel to
17574e18e297SPatrick Mooney 			 * get a new version.
17584e18e297SPatrick Mooney 			 *
17594e18e297SPatrick Mooney 			 * 2) Other software uses .debug_ sections for things
17604e18e297SPatrick Mooney 			 * which aren't DWARF. This allows them to be captured
17614e18e297SPatrick Mooney 			 * as well.
17624e18e297SPatrick Mooney 			 */
17634e18e297SPatrick Mooney 			count++;
17644e18e297SPatrick Mooney 
1765*6233c8a8SAndy Fiddaman 			if (count > remain) {
1766*6233c8a8SAndy Fiddaman 				error = ENOMEM;
1767*6233c8a8SAndy Fiddaman 				goto done;
1768*6233c8a8SAndy Fiddaman 			}
17694e18e297SPatrick Mooney 
1770*6233c8a8SAndy Fiddaman 			if (justcounting)
1771*6233c8a8SAndy Fiddaman 				continue;
17724e18e297SPatrick Mooney 
1773*6233c8a8SAndy Fiddaman 			elf_ctx_resize_scratch(ctx, shdr->sh_size);
17744e18e297SPatrick Mooney 
1775*6233c8a8SAndy Fiddaman 			if (!shstrtab_ndx(shstrtab, name, &v[idx].sh_name)) {
1776*6233c8a8SAndy Fiddaman 				error = ENOMEM;
1777*6233c8a8SAndy Fiddaman 				goto done;
17784e18e297SPatrick Mooney 			}
17794e18e297SPatrick Mooney 
1780*6233c8a8SAndy Fiddaman 			v[idx].sh_addr = (Addr)(uintptr_t)saddr;
1781*6233c8a8SAndy Fiddaman 			v[idx].sh_type = shdr->sh_type;
1782*6233c8a8SAndy Fiddaman 			v[idx].sh_addralign = shdr->sh_addralign;
1783*6233c8a8SAndy Fiddaman 			*doffp = roundup(*doffp, v[idx].sh_addralign);
1784*6233c8a8SAndy Fiddaman 			v[idx].sh_offset = *doffp;
1785*6233c8a8SAndy Fiddaman 			v[idx].sh_size = shdr->sh_size;
1786*6233c8a8SAndy Fiddaman 			v[idx].sh_link = 0;
1787*6233c8a8SAndy Fiddaman 			v[idx].sh_entsize = shdr->sh_entsize;
1788*6233c8a8SAndy Fiddaman 			v[idx].sh_info = shdr->sh_info;
1789*6233c8a8SAndy Fiddaman 
1790*6233c8a8SAndy Fiddaman 			elf_copy_scn(ctx, shdr, mvp, &v[idx]);
1791*6233c8a8SAndy Fiddaman 			idx++;
1792*6233c8a8SAndy Fiddaman 
17934e18e297SPatrick Mooney 			continue;
17944e18e297SPatrick Mooney 		} else {
17954e18e297SPatrick Mooney 			continue;
17964e18e297SPatrick Mooney 		}
17974e18e297SPatrick Mooney 
17984e18e297SPatrick Mooney 		ASSERT(symchk != NULL);
17994e18e297SPatrick Mooney 		if ((symchk->sh_type != SHT_DYNSYM &&
18004e18e297SPatrick Mooney 		    symchk->sh_type != SHT_SYMTAB) ||
18014e18e297SPatrick Mooney 		    symchk->sh_link == 0 || symchk->sh_link >= nshdrs) {
18024e18e297SPatrick Mooney 			ctf_link = B_FALSE;
18034e18e297SPatrick Mooney 			continue;
18044e18e297SPatrick Mooney 		}
18054e18e297SPatrick Mooney 		strchk = (Shdr *)(shbase + symchk->sh_link * ehdr.e_shentsize);
18064e18e297SPatrick Mooney 		if (strchk->sh_type != SHT_STRTAB) {
18074e18e297SPatrick Mooney 			ctf_link = B_FALSE;
18084e18e297SPatrick Mooney 			continue;
18094e18e297SPatrick Mooney 		}
18104e18e297SPatrick Mooney 		symtab = symchk;
18114e18e297SPatrick Mooney 		strtab = strchk;
18124e18e297SPatrick Mooney 
18134e18e297SPatrick Mooney 		if (symtab != NULL && ctf != NULL &&
18144e18e297SPatrick Mooney 		    (content & CC_CONTENT_DEBUG) == 0) {
18154e18e297SPatrick Mooney 			/* No other shdrs are of interest at this point */
18164e18e297SPatrick Mooney 			break;
18174e18e297SPatrick Mooney 		}
18184e18e297SPatrick Mooney 	}
18194e18e297SPatrick Mooney 
1820*6233c8a8SAndy Fiddaman 	extra = 0;
18214e18e297SPatrick Mooney 	if (ctf != NULL)
1822*6233c8a8SAndy Fiddaman 		extra += 1;
18234e18e297SPatrick Mooney 	if (symtab != NULL)
1824*6233c8a8SAndy Fiddaman 		extra += 2;
18254e18e297SPatrick Mooney 
1826*6233c8a8SAndy Fiddaman 	if (remain < extra || count > remain - extra) {
1827*6233c8a8SAndy Fiddaman 		error = ENOMEM;
18284e18e297SPatrick Mooney 		goto done;
18294e18e297SPatrick Mooney 	}
18304e18e297SPatrick Mooney 
1831*6233c8a8SAndy Fiddaman 	count += extra;
1832*6233c8a8SAndy Fiddaman 
18334e18e297SPatrick Mooney 	if (justcounting)
18344e18e297SPatrick Mooney 		goto done;
18354e18e297SPatrick Mooney 
18364e18e297SPatrick Mooney 	/* output CTF section */
18374e18e297SPatrick Mooney 	if (ctf != NULL) {
18384e18e297SPatrick Mooney 		elf_ctx_resize_scratch(ctx, ctf->sh_size);
18394e18e297SPatrick Mooney 
18404e18e297SPatrick Mooney 		if (!shstrtab_ndx(shstrtab,
18414e18e297SPatrick Mooney 		    shstrtab_data[STR_CTF], &v[idx].sh_name)) {
18424e18e297SPatrick Mooney 			error = ENOMEM;
18434e18e297SPatrick Mooney 			goto done;
18444e18e297SPatrick Mooney 		}
18454e18e297SPatrick Mooney 		v[idx].sh_addr = (Addr)(uintptr_t)saddr;
18464e18e297SPatrick Mooney 		v[idx].sh_type = SHT_PROGBITS;
18474e18e297SPatrick Mooney 		v[idx].sh_addralign = 4;
18484e18e297SPatrick Mooney 		*doffp = roundup(*doffp, v[idx].sh_addralign);
18494e18e297SPatrick Mooney 		v[idx].sh_offset = *doffp;
18504e18e297SPatrick Mooney 		v[idx].sh_size = ctf->sh_size;
18514e18e297SPatrick Mooney 
18524e18e297SPatrick Mooney 		if (ctf_link) {
18534e18e297SPatrick Mooney 			/*
18544e18e297SPatrick Mooney 			 * The linked symtab (and strtab) will be output
18554e18e297SPatrick Mooney 			 * immediately after this CTF section.  Its shdr index
18564e18e297SPatrick Mooney 			 * directly follows this one.
18574e18e297SPatrick Mooney 			 */
18584e18e297SPatrick Mooney 			v[idx].sh_link = idx + 1;
18594e18e297SPatrick Mooney 			ASSERT(symtab != NULL);
18604e18e297SPatrick Mooney 		} else {
18614e18e297SPatrick Mooney 			v[idx].sh_link = 0;
18624e18e297SPatrick Mooney 		}
18634e18e297SPatrick Mooney 		elf_copy_scn(ctx, ctf, mvp, &v[idx]);
18644e18e297SPatrick Mooney 		idx++;
18654e18e297SPatrick Mooney 	}
18664e18e297SPatrick Mooney 
18674e18e297SPatrick Mooney 	/* output SYMTAB/STRTAB sections */
18684e18e297SPatrick Mooney 	if (symtab != NULL) {
18694e18e297SPatrick Mooney 		shstrtype_t symtab_type, strtab_type;
18704e18e297SPatrick Mooney 		uint_t symtab_name, strtab_name;
18714e18e297SPatrick Mooney 
18724e18e297SPatrick Mooney 		elf_ctx_resize_scratch(ctx,
18734e18e297SPatrick Mooney 		    MAX(symtab->sh_size, strtab->sh_size));
18744e18e297SPatrick Mooney 
18754e18e297SPatrick Mooney 		if (symtab->sh_type == SHT_DYNSYM) {
18764e18e297SPatrick Mooney 			symtab_type = STR_DYNSYM;
18774e18e297SPatrick Mooney 			strtab_type = STR_DYNSTR;
18784e18e297SPatrick Mooney 		} else {
18794e18e297SPatrick Mooney 			symtab_type = STR_SYMTAB;
18804e18e297SPatrick Mooney 			strtab_type = STR_STRTAB;
18814e18e297SPatrick Mooney 		}
18824e18e297SPatrick Mooney 
18834e18e297SPatrick Mooney 		if (!shstrtab_ndx(shstrtab,
18844e18e297SPatrick Mooney 		    shstrtab_data[symtab_type], &symtab_name)) {
18854e18e297SPatrick Mooney 			error = ENOMEM;
18864e18e297SPatrick Mooney 			goto done;
18874e18e297SPatrick Mooney 		}
18884e18e297SPatrick Mooney 		if (!shstrtab_ndx(shstrtab,
18894e18e297SPatrick Mooney 		    shstrtab_data[strtab_type], &strtab_name)) {
18904e18e297SPatrick Mooney 			error = ENOMEM;
18914e18e297SPatrick Mooney 			goto done;
18924e18e297SPatrick Mooney 		}
18934e18e297SPatrick Mooney 
18944e18e297SPatrick Mooney 		v[idx].sh_name = symtab_name;
18954e18e297SPatrick Mooney 		v[idx].sh_type = symtab->sh_type;
18964e18e297SPatrick Mooney 		v[idx].sh_addr = symtab->sh_addr;
18974e18e297SPatrick Mooney 		if (ehdr.e_type == ET_DYN || v[idx].sh_addr == 0)
18984e18e297SPatrick Mooney 			v[idx].sh_addr += (Addr)(uintptr_t)saddr;
18994e18e297SPatrick Mooney 		v[idx].sh_addralign = symtab->sh_addralign;
19004e18e297SPatrick Mooney 		*doffp = roundup(*doffp, v[idx].sh_addralign);
19014e18e297SPatrick Mooney 		v[idx].sh_offset = *doffp;
19024e18e297SPatrick Mooney 		v[idx].sh_size = symtab->sh_size;
19034e18e297SPatrick Mooney 		v[idx].sh_link = idx + 1;
19044e18e297SPatrick Mooney 		v[idx].sh_entsize = symtab->sh_entsize;
19054e18e297SPatrick Mooney 		v[idx].sh_info = symtab->sh_info;
19064e18e297SPatrick Mooney 
19074e18e297SPatrick Mooney 		elf_copy_scn(ctx, symtab, mvp, &v[idx]);
19084e18e297SPatrick Mooney 		idx++;
19094e18e297SPatrick Mooney 
19104e18e297SPatrick Mooney 		v[idx].sh_name = strtab_name;
19114e18e297SPatrick Mooney 		v[idx].sh_type = SHT_STRTAB;
19124e18e297SPatrick Mooney 		v[idx].sh_flags = SHF_STRINGS;
19134e18e297SPatrick Mooney 		v[idx].sh_addr = strtab->sh_addr;
19144e18e297SPatrick Mooney 		if (ehdr.e_type == ET_DYN || v[idx].sh_addr == 0)
19154e18e297SPatrick Mooney 			v[idx].sh_addr += (Addr)(uintptr_t)saddr;
19164e18e297SPatrick Mooney 		v[idx].sh_addralign = strtab->sh_addralign;
19174e18e297SPatrick Mooney 		*doffp = roundup(*doffp, v[idx].sh_addralign);
19184e18e297SPatrick Mooney 		v[idx].sh_offset = *doffp;
19194e18e297SPatrick Mooney 		v[idx].sh_size = strtab->sh_size;
19204e18e297SPatrick Mooney 
19214e18e297SPatrick Mooney 		elf_copy_scn(ctx, strtab, mvp, &v[idx]);
19224e18e297SPatrick Mooney 		idx++;
19234e18e297SPatrick Mooney 	}
19244e18e297SPatrick Mooney 
19254e18e297SPatrick Mooney done:
19264e18e297SPatrick Mooney 	kmem_free(shstrbase, shstrsize);
19274e18e297SPatrick Mooney 	kmem_free(shbase, shsize);
19284e18e297SPatrick Mooney 
19294e18e297SPatrick Mooney 	if (error == 0)
19304e18e297SPatrick Mooney 		*countp = count;
19314e18e297SPatrick Mooney 
19324e18e297SPatrick Mooney 	return (error);
19334e18e297SPatrick Mooney }
19347c478bd9Sstevel@tonic-gate 
19357c478bd9Sstevel@tonic-gate /*
19364e18e297SPatrick Mooney  * Walk mappings in process address space, examining those which correspond to
19374e18e297SPatrick Mooney  * loaded objects.  It is called twice from elfcore: Once to simply count
19384e18e297SPatrick Mooney  * relevant sections, and again later to copy those sections once an adequate
19394e18e297SPatrick Mooney  * buffer has been allocated for the shdr details.
19407c478bd9Sstevel@tonic-gate  */
19417c478bd9Sstevel@tonic-gate static int
elf_process_scns(elf_core_ctx_t * ctx,Shdr * v,const uint_t nv,uint_t * nshdrsp)1942*6233c8a8SAndy Fiddaman elf_process_scns(elf_core_ctx_t *ctx, Shdr *v, const uint_t nv, uint_t *nshdrsp)
19437c478bd9Sstevel@tonic-gate {
19447c478bd9Sstevel@tonic-gate 	vnode_t *lastvp = NULL;
19457c478bd9Sstevel@tonic-gate 	struct seg *seg;
1946*6233c8a8SAndy Fiddaman 	uint_t remain, idx;
19477c478bd9Sstevel@tonic-gate 	shstrtab_t shstrtab;
19484e18e297SPatrick Mooney 	struct as *as = ctx->ecc_p->p_as;
19497c478bd9Sstevel@tonic-gate 	int error = 0;
1950*6233c8a8SAndy Fiddaman 	const boolean_t justcounting = (v == NULL);
19517c478bd9Sstevel@tonic-gate 
19524e18e297SPatrick Mooney 	ASSERT(AS_WRITE_HELD(as));
19534e18e297SPatrick Mooney 
1954*6233c8a8SAndy Fiddaman 	if (justcounting) {
1955*6233c8a8SAndy Fiddaman 		ASSERT(nv == 0);
1956*6233c8a8SAndy Fiddaman 		/*
1957*6233c8a8SAndy Fiddaman 		 * In the counting case, set remain to UINT_MAX so that we
1958*6233c8a8SAndy Fiddaman 		 * allow up to that many sections. Note that remain is
1959*6233c8a8SAndy Fiddaman 		 * decremented immediately below to account for the SHT_NULL
1960*6233c8a8SAndy Fiddaman 		 * section at index zero and so we do not end up passing
1961*6233c8a8SAndy Fiddaman 		 * UINT_MAX as the 'remain' value to elf_process_obj_scns().
1962*6233c8a8SAndy Fiddaman 		 * Once we've finished counting, we further check that there
1963*6233c8a8SAndy Fiddaman 		 * is at least one array slot available for shstrtab.
1964*6233c8a8SAndy Fiddaman 		 */
1965*6233c8a8SAndy Fiddaman 		remain = UINT_MAX;
1966*6233c8a8SAndy Fiddaman 	} else {
19674e18e297SPatrick Mooney 		ASSERT(nv != 0);
1968*6233c8a8SAndy Fiddaman 		remain = nv;
19694e18e297SPatrick Mooney 
19704e18e297SPatrick Mooney 		if (!shstrtab_init(&shstrtab))
19714e18e297SPatrick Mooney 			return (ENOMEM);
19728e458de0SRobert Mustacchi 	}
19737c478bd9Sstevel@tonic-gate 
19744e18e297SPatrick Mooney 	/* Per the ELF spec, shdr index 0 is reserved. */
19754e18e297SPatrick Mooney 	idx = 1;
1976*6233c8a8SAndy Fiddaman 	remain--;
19777c478bd9Sstevel@tonic-gate 	for (seg = AS_SEGFIRST(as); seg != NULL; seg = AS_SEGNEXT(as, seg)) {
19787c478bd9Sstevel@tonic-gate 		vnode_t *mvp;
19797c478bd9Sstevel@tonic-gate 		void *tmp = NULL;
19804e18e297SPatrick Mooney 		caddr_t saddr = seg->s_base, naddr, eaddr;
19817c478bd9Sstevel@tonic-gate 		size_t segsize;
19824e18e297SPatrick Mooney 		uint_t count, prot;
19837c478bd9Sstevel@tonic-gate 
19847c478bd9Sstevel@tonic-gate 		/*
19857c478bd9Sstevel@tonic-gate 		 * Since we're just looking for text segments of load
19867c478bd9Sstevel@tonic-gate 		 * objects, we only care about the protection bits; we don't
19877c478bd9Sstevel@tonic-gate 		 * care about the actual size of the segment so we use the
19887c478bd9Sstevel@tonic-gate 		 * reserved size. If the segment's size is zero, there's
19897c478bd9Sstevel@tonic-gate 		 * something fishy going on so we ignore this segment.
19907c478bd9Sstevel@tonic-gate 		 */
19917c478bd9Sstevel@tonic-gate 		if (seg->s_ops != &segvn_ops ||
19927c478bd9Sstevel@tonic-gate 		    SEGOP_GETVP(seg, seg->s_base, &mvp) != 0 ||
19937c478bd9Sstevel@tonic-gate 		    mvp == lastvp || mvp == NULL || mvp->v_type != VREG ||
1994*6233c8a8SAndy Fiddaman 		    (segsize = pr_getsegsize(seg, 1)) == 0) {
19957c478bd9Sstevel@tonic-gate 			continue;
1996*6233c8a8SAndy Fiddaman 		}
19977c478bd9Sstevel@tonic-gate 
19987c478bd9Sstevel@tonic-gate 		eaddr = saddr + segsize;
19997c478bd9Sstevel@tonic-gate 		prot = pr_getprot(seg, 1, &tmp, &saddr, &naddr, eaddr);
20007c478bd9Sstevel@tonic-gate 		pr_getprot_done(&tmp);
20017c478bd9Sstevel@tonic-gate 
20027c478bd9Sstevel@tonic-gate 		/*
20037c478bd9Sstevel@tonic-gate 		 * Skip this segment unless the protection bits look like
20047c478bd9Sstevel@tonic-gate 		 * what we'd expect for a text segment.
20057c478bd9Sstevel@tonic-gate 		 */
20067c478bd9Sstevel@tonic-gate 		if ((prot & (PROT_WRITE | PROT_EXEC)) != PROT_EXEC)
20077c478bd9Sstevel@tonic-gate 			continue;
20087c478bd9Sstevel@tonic-gate 
20094e18e297SPatrick Mooney 		error = elf_process_obj_scns(ctx, mvp, saddr, v, idx, remain,
20104e18e297SPatrick Mooney 		    &shstrtab, &count);
20114e18e297SPatrick Mooney 		if (error != 0)
20124e18e297SPatrick Mooney 			goto done;
20137c478bd9Sstevel@tonic-gate 
2014*6233c8a8SAndy Fiddaman 		VERIFY3U(count, <=, remain);
2015*6233c8a8SAndy Fiddaman 		if (!justcounting) {
2016*6233c8a8SAndy Fiddaman 			VERIFY3U(idx + count, <=, nv);
2017*6233c8a8SAndy Fiddaman 		}
20187c478bd9Sstevel@tonic-gate 
20194e18e297SPatrick Mooney 		remain -= count;
20204e18e297SPatrick Mooney 		idx += count;
20217c478bd9Sstevel@tonic-gate 		lastvp = mvp;
20227c478bd9Sstevel@tonic-gate 	}
20237c478bd9Sstevel@tonic-gate 
2024*6233c8a8SAndy Fiddaman 	if (justcounting) {
20254e18e297SPatrick Mooney 		if (idx == 1) {
2026*6233c8a8SAndy Fiddaman 			/* No sections found */
20277c478bd9Sstevel@tonic-gate 			*nshdrsp = 0;
2028*6233c8a8SAndy Fiddaman 		} else if (remain < 1) {
2029*6233c8a8SAndy Fiddaman 			/* No space for the shrstrtab at the end */
2030*6233c8a8SAndy Fiddaman 			*nshdrsp = 0;
2031*6233c8a8SAndy Fiddaman 			return (ENOMEM);
20324e18e297SPatrick Mooney 		} else {
20334e18e297SPatrick Mooney 			/* Include room for the shrstrtab at the end */
20344e18e297SPatrick Mooney 			*nshdrsp = idx + 1;
20354e18e297SPatrick Mooney 		}
20364e18e297SPatrick Mooney 		return (0);
20377c478bd9Sstevel@tonic-gate 	}
20387c478bd9Sstevel@tonic-gate 
2039*6233c8a8SAndy Fiddaman 	if (remain != 1) {
20407c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "elfcore: core dump failed for "
20414e18e297SPatrick Mooney 		    "process %d; address space is changing",
20424e18e297SPatrick Mooney 		    ctx->ecc_p->p_pid);
20437c478bd9Sstevel@tonic-gate 		error = EIO;
20447c478bd9Sstevel@tonic-gate 		goto done;
20457c478bd9Sstevel@tonic-gate 	}
20467c478bd9Sstevel@tonic-gate 
20478e458de0SRobert Mustacchi 	if (!shstrtab_ndx(&shstrtab, shstrtab_data[STR_SHSTRTAB],
20484e18e297SPatrick Mooney 	    &v[idx].sh_name)) {
20498e458de0SRobert Mustacchi 		error = ENOMEM;
20508e458de0SRobert Mustacchi 		goto done;
20518e458de0SRobert Mustacchi 	}
20524e18e297SPatrick Mooney 	v[idx].sh_size = shstrtab_size(&shstrtab);
20534e18e297SPatrick Mooney 	v[idx].sh_addralign = 1;
20544e18e297SPatrick Mooney 	v[idx].sh_offset = ctx->ecc_doffset;
20554e18e297SPatrick Mooney 	v[idx].sh_flags = SHF_STRINGS;
20564e18e297SPatrick Mooney 	v[idx].sh_type = SHT_STRTAB;
20574e18e297SPatrick Mooney 
20584e18e297SPatrick Mooney 	elf_ctx_resize_scratch(ctx, v[idx].sh_size);
20594e18e297SPatrick Mooney 	VERIFY3U(ctx->ecc_bufsz, >=, v[idx].sh_size);
20604e18e297SPatrick Mooney 	shstrtab_dump(&shstrtab, ctx->ecc_buf);
20614e18e297SPatrick Mooney 
20624e18e297SPatrick Mooney 	error = core_write(ctx->ecc_vp, UIO_SYSSPACE, ctx->ecc_doffset,
20634e18e297SPatrick Mooney 	    ctx->ecc_buf, v[idx].sh_size, ctx->ecc_rlimit, ctx->ecc_credp);
2064*6233c8a8SAndy Fiddaman 	if (error == 0)
20654e18e297SPatrick Mooney 		ctx->ecc_doffset += v[idx].sh_size;
20667c478bd9Sstevel@tonic-gate 
20677c478bd9Sstevel@tonic-gate done:
2068*6233c8a8SAndy Fiddaman 	if (!justcounting)
20694e18e297SPatrick Mooney 		shstrtab_fini(&shstrtab);
20708e458de0SRobert Mustacchi 
20717c478bd9Sstevel@tonic-gate 	return (error);
20727c478bd9Sstevel@tonic-gate }
20737c478bd9Sstevel@tonic-gate 
20747c478bd9Sstevel@tonic-gate int
elfcore(vnode_t * vp,proc_t * p,cred_t * credp,rlim64_t rlimit,int sig,core_content_t content)20757c478bd9Sstevel@tonic-gate elfcore(vnode_t *vp, proc_t *p, cred_t *credp, rlim64_t rlimit, int sig,
20767c478bd9Sstevel@tonic-gate     core_content_t content)
20777c478bd9Sstevel@tonic-gate {
20784e18e297SPatrick Mooney 	u_offset_t poffset, soffset, doffset;
20794e18e297SPatrick Mooney 	int error;
20804e18e297SPatrick Mooney 	uint_t i, nphdrs, nshdrs;
20817c478bd9Sstevel@tonic-gate 	struct seg *seg;
20827c478bd9Sstevel@tonic-gate 	struct as *as = p->p_as;
20834e18e297SPatrick Mooney 	void *bigwad, *zeropg = NULL;
20844e18e297SPatrick Mooney 	size_t bigsize, phdrsz, shdrsz;
20857c478bd9Sstevel@tonic-gate 	Ehdr *ehdr;
20864e18e297SPatrick Mooney 	Phdr *phdr;
20874e18e297SPatrick Mooney 	Shdr shdr0;
20884e18e297SPatrick Mooney 	caddr_t brkbase, stkbase;
20894e18e297SPatrick Mooney 	size_t brksize, stksize;
20904e18e297SPatrick Mooney 	boolean_t overflowed = B_FALSE, retried = B_FALSE;
2091f971a346SBryan Cantrill 	klwp_t *lwp = ttolwp(curthread);
20924e18e297SPatrick Mooney 	elf_core_ctx_t ctx = {
20934e18e297SPatrick Mooney 		.ecc_vp = vp,
20944e18e297SPatrick Mooney 		.ecc_p = p,
20954e18e297SPatrick Mooney 		.ecc_credp = credp,
20964e18e297SPatrick Mooney 		.ecc_rlimit = rlimit,
20974e18e297SPatrick Mooney 		.ecc_content = content,
20984e18e297SPatrick Mooney 		.ecc_doffset = 0,
20994e18e297SPatrick Mooney 		.ecc_buf = NULL,
21004e18e297SPatrick Mooney 		.ecc_bufsz = 0
21014e18e297SPatrick Mooney 	};
21027c478bd9Sstevel@tonic-gate 
21037c478bd9Sstevel@tonic-gate top:
21047c478bd9Sstevel@tonic-gate 	/*
21057c478bd9Sstevel@tonic-gate 	 * Make sure we have everything we need (registers, etc.).
21067c478bd9Sstevel@tonic-gate 	 * All other lwps have already stopped and are in an orderly state.
21077c478bd9Sstevel@tonic-gate 	 */
21087c478bd9Sstevel@tonic-gate 	ASSERT(p == ttoproc(curthread));
21097c478bd9Sstevel@tonic-gate 	prstop(0, 0);
21107c478bd9Sstevel@tonic-gate 
2111dc32d872SJosef 'Jeff' Sipek 	AS_LOCK_ENTER(as, RW_WRITER);
21127c478bd9Sstevel@tonic-gate 	nphdrs = prnsegs(as, 0) + 2;		/* two CORE note sections */
21137c478bd9Sstevel@tonic-gate 
21147c478bd9Sstevel@tonic-gate 	/*
21157c478bd9Sstevel@tonic-gate 	 * Count the number of section headers we're going to need.
21167c478bd9Sstevel@tonic-gate 	 */
2117*6233c8a8SAndy Fiddaman 	nshdrs = error = 0;
2118*6233c8a8SAndy Fiddaman 	if (content & (CC_CONTENT_CTF | CC_CONTENT_SYMTAB | CC_CONTENT_DEBUG))
2119*6233c8a8SAndy Fiddaman 		error = elf_process_scns(&ctx, NULL, 0, &nshdrs);
2120dc32d872SJosef 'Jeff' Sipek 	AS_LOCK_EXIT(as);
21217c478bd9Sstevel@tonic-gate 
2122*6233c8a8SAndy Fiddaman 	if (error != 0)
2123*6233c8a8SAndy Fiddaman 		return (error);
2124*6233c8a8SAndy Fiddaman 
212530da1432Sahl 	/*
21264e18e297SPatrick Mooney 	 * The core file contents may require zero section headers, but if
212730da1432Sahl 	 * we overflow the 16 bits allotted to the program header count in
212830da1432Sahl 	 * the ELF header, we'll need that program header at index zero.
212930da1432Sahl 	 */
213030da1432Sahl 	if (nshdrs == 0 && nphdrs >= PN_XNUM)
213130da1432Sahl 		nshdrs = 1;
213230da1432Sahl 
21334e18e297SPatrick Mooney 	/*
21344e18e297SPatrick Mooney 	 * Allocate a buffer which is sized adequately to hold the ehdr, phdrs
21354e18e297SPatrick Mooney 	 * or shdrs needed to produce the core file.  It is used for the three
21364e18e297SPatrick Mooney 	 * tasks sequentially, not simultaneously, so it does not need space
21374e18e297SPatrick Mooney 	 * for all three data at once, only the largest one.
21384e18e297SPatrick Mooney 	 */
2139*6233c8a8SAndy Fiddaman 	VERIFY3U(nphdrs, >=, 2);
21407c478bd9Sstevel@tonic-gate 	phdrsz = nphdrs * sizeof (Phdr);
21417c478bd9Sstevel@tonic-gate 	shdrsz = nshdrs * sizeof (Shdr);
21424e18e297SPatrick Mooney 	bigsize = MAX(sizeof (Ehdr), MAX(phdrsz, shdrsz));
21437c478bd9Sstevel@tonic-gate 	bigwad = kmem_alloc(bigsize, KM_SLEEP);
21447c478bd9Sstevel@tonic-gate 
21454e18e297SPatrick Mooney 	ehdr = (Ehdr *)bigwad;
21467c478bd9Sstevel@tonic-gate 	bzero(ehdr, sizeof (*ehdr));
21477c478bd9Sstevel@tonic-gate 
21487c478bd9Sstevel@tonic-gate 	ehdr->e_ident[EI_MAG0] = ELFMAG0;
21497c478bd9Sstevel@tonic-gate 	ehdr->e_ident[EI_MAG1] = ELFMAG1;
21507c478bd9Sstevel@tonic-gate 	ehdr->e_ident[EI_MAG2] = ELFMAG2;
21517c478bd9Sstevel@tonic-gate 	ehdr->e_ident[EI_MAG3] = ELFMAG3;
21527c478bd9Sstevel@tonic-gate 	ehdr->e_ident[EI_CLASS] = ELFCLASS;
21537c478bd9Sstevel@tonic-gate 	ehdr->e_type = ET_CORE;
21547c478bd9Sstevel@tonic-gate 
21557c478bd9Sstevel@tonic-gate #if !defined(_LP64) || defined(_ELF32_COMPAT)
21567c478bd9Sstevel@tonic-gate 
21577c478bd9Sstevel@tonic-gate #if defined(__sparc)
21587c478bd9Sstevel@tonic-gate 	ehdr->e_ident[EI_DATA] = ELFDATA2MSB;
21597c478bd9Sstevel@tonic-gate 	ehdr->e_machine = EM_SPARC;
216086ef0a63SRichard Lowe #elif defined(__i386_COMPAT)
21617c478bd9Sstevel@tonic-gate 	ehdr->e_ident[EI_DATA] = ELFDATA2LSB;
21627c478bd9Sstevel@tonic-gate 	ehdr->e_machine = EM_386;
21637c478bd9Sstevel@tonic-gate #else
21647c478bd9Sstevel@tonic-gate #error "no recognized machine type is defined"
21657c478bd9Sstevel@tonic-gate #endif
21667c478bd9Sstevel@tonic-gate 
21677c478bd9Sstevel@tonic-gate #else	/* !defined(_LP64) || defined(_ELF32_COMPAT) */
21687c478bd9Sstevel@tonic-gate 
21697c478bd9Sstevel@tonic-gate #if defined(__sparc)
21707c478bd9Sstevel@tonic-gate 	ehdr->e_ident[EI_DATA] = ELFDATA2MSB;
21717c478bd9Sstevel@tonic-gate 	ehdr->e_machine = EM_SPARCV9;
21727c478bd9Sstevel@tonic-gate #elif defined(__amd64)
21737c478bd9Sstevel@tonic-gate 	ehdr->e_ident[EI_DATA] = ELFDATA2LSB;
21747c478bd9Sstevel@tonic-gate 	ehdr->e_machine = EM_AMD64;
21757c478bd9Sstevel@tonic-gate #else
21767c478bd9Sstevel@tonic-gate #error "no recognized 64-bit machine type is defined"
21777c478bd9Sstevel@tonic-gate #endif
21787c478bd9Sstevel@tonic-gate 
21797c478bd9Sstevel@tonic-gate #endif	/* !defined(_LP64) || defined(_ELF32_COMPAT) */
21807c478bd9Sstevel@tonic-gate 
21814e18e297SPatrick Mooney 	poffset = sizeof (Ehdr);
21824e18e297SPatrick Mooney 	soffset = sizeof (Ehdr) + phdrsz;
21834e18e297SPatrick Mooney 	doffset = sizeof (Ehdr) + phdrsz + shdrsz;
21844e18e297SPatrick Mooney 	bzero(&shdr0, sizeof (shdr0));
21854e18e297SPatrick Mooney 
218630da1432Sahl 	/*
218730da1432Sahl 	 * If the count of program headers or section headers or the index
218830da1432Sahl 	 * of the section string table can't fit in the mere 16 bits
218930da1432Sahl 	 * shortsightedly allotted to them in the ELF header, we use the
219030da1432Sahl 	 * extended formats and put the real values in the section header
219130da1432Sahl 	 * as index 0.
219230da1432Sahl 	 */
21934e18e297SPatrick Mooney 	if (nphdrs >= PN_XNUM) {
219430da1432Sahl 		ehdr->e_phnum = PN_XNUM;
21954e18e297SPatrick Mooney 		shdr0.sh_info = nphdrs;
21964e18e297SPatrick Mooney 	} else {
219730da1432Sahl 		ehdr->e_phnum = (unsigned short)nphdrs;
21984e18e297SPatrick Mooney 	}
21997c478bd9Sstevel@tonic-gate 
22007c478bd9Sstevel@tonic-gate 	if (nshdrs > 0) {
22014e18e297SPatrick Mooney 		if (nshdrs >= SHN_LORESERVE) {
220230da1432Sahl 			ehdr->e_shnum = 0;
22034e18e297SPatrick Mooney 			shdr0.sh_size = nshdrs;
22044e18e297SPatrick Mooney 		} else {
220530da1432Sahl 			ehdr->e_shnum = (unsigned short)nshdrs;
22064e18e297SPatrick Mooney 		}
220730da1432Sahl 
22084e18e297SPatrick Mooney 		if (nshdrs - 1 >= SHN_LORESERVE) {
220930da1432Sahl 			ehdr->e_shstrndx = SHN_XINDEX;
22104e18e297SPatrick Mooney 			shdr0.sh_link = nshdrs - 1;
22114e18e297SPatrick Mooney 		} else {
221230da1432Sahl 			ehdr->e_shstrndx = (unsigned short)(nshdrs - 1);
22134e18e297SPatrick Mooney 		}
221430da1432Sahl 
22154e18e297SPatrick Mooney 		ehdr->e_shoff = soffset;
22167c478bd9Sstevel@tonic-gate 		ehdr->e_shentsize = sizeof (Shdr);
22177c478bd9Sstevel@tonic-gate 	}
22187c478bd9Sstevel@tonic-gate 
22194e18e297SPatrick Mooney 	ehdr->e_ident[EI_VERSION] = EV_CURRENT;
22204e18e297SPatrick Mooney 	ehdr->e_version = EV_CURRENT;
22214e18e297SPatrick Mooney 	ehdr->e_ehsize = sizeof (Ehdr);
22224e18e297SPatrick Mooney 	ehdr->e_phoff = poffset;
22234e18e297SPatrick Mooney 	ehdr->e_phentsize = sizeof (Phdr);
22244e18e297SPatrick Mooney 
22257c478bd9Sstevel@tonic-gate 	if (error = core_write(vp, UIO_SYSSPACE, (offset_t)0, ehdr,
22264e18e297SPatrick Mooney 	    sizeof (Ehdr), rlimit, credp)) {
22277c478bd9Sstevel@tonic-gate 		goto done;
22284e18e297SPatrick Mooney 	}
22297c478bd9Sstevel@tonic-gate 
22304e18e297SPatrick Mooney 	phdr = (Phdr *)bigwad;
22314e18e297SPatrick Mooney 	bzero(phdr, phdrsz);
22327c478bd9Sstevel@tonic-gate 
22334e18e297SPatrick Mooney 	setup_old_note_header(&phdr[0], p);
22344e18e297SPatrick Mooney 	phdr[0].p_offset = doffset = roundup(doffset, sizeof (Word));
22354e18e297SPatrick Mooney 	doffset += phdr[0].p_filesz;
22367c478bd9Sstevel@tonic-gate 
22374e18e297SPatrick Mooney 	setup_note_header(&phdr[1], p);
22384e18e297SPatrick Mooney 	phdr[1].p_offset = doffset = roundup(doffset, sizeof (Word));
22394e18e297SPatrick Mooney 	doffset += phdr[1].p_filesz;
22407c478bd9Sstevel@tonic-gate 
22417c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
22427c478bd9Sstevel@tonic-gate 
22437c478bd9Sstevel@tonic-gate 	brkbase = p->p_brkbase;
22447c478bd9Sstevel@tonic-gate 	brksize = p->p_brksize;
22457c478bd9Sstevel@tonic-gate 
22467c478bd9Sstevel@tonic-gate 	stkbase = p->p_usrstack - p->p_stksize;
22477c478bd9Sstevel@tonic-gate 	stksize = p->p_stksize;
22487c478bd9Sstevel@tonic-gate 
22497c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
22507c478bd9Sstevel@tonic-gate 
2251dc32d872SJosef 'Jeff' Sipek 	AS_LOCK_ENTER(as, RW_WRITER);
22527c478bd9Sstevel@tonic-gate 	i = 2;
22537c478bd9Sstevel@tonic-gate 	for (seg = AS_SEGFIRST(as); seg != NULL; seg = AS_SEGNEXT(as, seg)) {
22547c478bd9Sstevel@tonic-gate 		caddr_t eaddr = seg->s_base + pr_getsegsize(seg, 0);
22557c478bd9Sstevel@tonic-gate 		caddr_t saddr, naddr;
22567c478bd9Sstevel@tonic-gate 		void *tmp = NULL;
22577c478bd9Sstevel@tonic-gate 		extern struct seg_ops segspt_shmops;
22587c478bd9Sstevel@tonic-gate 
2259284ce987SPatrick Mooney 		if ((seg->s_flags & S_HOLE) != 0) {
2260284ce987SPatrick Mooney 			continue;
2261284ce987SPatrick Mooney 		}
2262284ce987SPatrick Mooney 
22637c478bd9Sstevel@tonic-gate 		for (saddr = seg->s_base; saddr < eaddr; saddr = naddr) {
22647c478bd9Sstevel@tonic-gate 			uint_t prot;
22657c478bd9Sstevel@tonic-gate 			size_t size;
22667c478bd9Sstevel@tonic-gate 			int type;
22677c478bd9Sstevel@tonic-gate 			vnode_t *mvp;
22687c478bd9Sstevel@tonic-gate 
22697c478bd9Sstevel@tonic-gate 			prot = pr_getprot(seg, 0, &tmp, &saddr, &naddr, eaddr);
22707c478bd9Sstevel@tonic-gate 			prot &= PROT_READ | PROT_WRITE | PROT_EXEC;
22714e18e297SPatrick Mooney 			if ((size = (size_t)(naddr - saddr)) == 0) {
22724e18e297SPatrick Mooney 				ASSERT(tmp == NULL);
22737c478bd9Sstevel@tonic-gate 				continue;
22744e18e297SPatrick Mooney 			} else if (i == nphdrs) {
22754e18e297SPatrick Mooney 				pr_getprot_done(&tmp);
22764e18e297SPatrick Mooney 				overflowed = B_TRUE;
22774e18e297SPatrick Mooney 				break;
22787c478bd9Sstevel@tonic-gate 			}
22794e18e297SPatrick Mooney 			phdr[i].p_type = PT_LOAD;
22804e18e297SPatrick Mooney 			phdr[i].p_vaddr = (Addr)(uintptr_t)saddr;
22814e18e297SPatrick Mooney 			phdr[i].p_memsz = size;
22827c478bd9Sstevel@tonic-gate 			if (prot & PROT_READ)
22834e18e297SPatrick Mooney 				phdr[i].p_flags |= PF_R;
22847c478bd9Sstevel@tonic-gate 			if (prot & PROT_WRITE)
22854e18e297SPatrick Mooney 				phdr[i].p_flags |= PF_W;
22867c478bd9Sstevel@tonic-gate 			if (prot & PROT_EXEC)
22874e18e297SPatrick Mooney 				phdr[i].p_flags |= PF_X;
22887c478bd9Sstevel@tonic-gate 
22897c478bd9Sstevel@tonic-gate 			/*
22907c478bd9Sstevel@tonic-gate 			 * Figure out which mappings to include in the core.
22917c478bd9Sstevel@tonic-gate 			 */
22927c478bd9Sstevel@tonic-gate 			type = SEGOP_GETTYPE(seg, saddr);
22937c478bd9Sstevel@tonic-gate 
22947c478bd9Sstevel@tonic-gate 			if (saddr == stkbase && size == stksize) {
22957c478bd9Sstevel@tonic-gate 				if (!(content & CC_CONTENT_STACK))
22967c478bd9Sstevel@tonic-gate 					goto exclude;
22977c478bd9Sstevel@tonic-gate 
22987c478bd9Sstevel@tonic-gate 			} else if (saddr == brkbase && size == brksize) {
22997c478bd9Sstevel@tonic-gate 				if (!(content & CC_CONTENT_HEAP))
23007c478bd9Sstevel@tonic-gate 					goto exclude;
23017c478bd9Sstevel@tonic-gate 
23027c478bd9Sstevel@tonic-gate 			} else if (seg->s_ops == &segspt_shmops) {
23037c478bd9Sstevel@tonic-gate 				if (type & MAP_NORESERVE) {
23047c478bd9Sstevel@tonic-gate 					if (!(content & CC_CONTENT_DISM))
23057c478bd9Sstevel@tonic-gate 						goto exclude;
23067c478bd9Sstevel@tonic-gate 				} else {
23077c478bd9Sstevel@tonic-gate 					if (!(content & CC_CONTENT_ISM))
23087c478bd9Sstevel@tonic-gate 						goto exclude;
23097c478bd9Sstevel@tonic-gate 				}
23107c478bd9Sstevel@tonic-gate 
23117c478bd9Sstevel@tonic-gate 			} else if (seg->s_ops != &segvn_ops) {
23127c478bd9Sstevel@tonic-gate 				goto exclude;
23137c478bd9Sstevel@tonic-gate 
23147c478bd9Sstevel@tonic-gate 			} else if (type & MAP_SHARED) {
23157c478bd9Sstevel@tonic-gate 				if (shmgetid(p, saddr) != SHMID_NONE) {
23167c478bd9Sstevel@tonic-gate 					if (!(content & CC_CONTENT_SHM))
23177c478bd9Sstevel@tonic-gate 						goto exclude;
23187c478bd9Sstevel@tonic-gate 
23197c478bd9Sstevel@tonic-gate 				} else if (SEGOP_GETVP(seg, seg->s_base,
23207c478bd9Sstevel@tonic-gate 				    &mvp) != 0 || mvp == NULL ||
23217c478bd9Sstevel@tonic-gate 				    mvp->v_type != VREG) {
23227c478bd9Sstevel@tonic-gate 					if (!(content & CC_CONTENT_SHANON))
23237c478bd9Sstevel@tonic-gate 						goto exclude;
23247c478bd9Sstevel@tonic-gate 
23257c478bd9Sstevel@tonic-gate 				} else {
23267c478bd9Sstevel@tonic-gate 					if (!(content & CC_CONTENT_SHFILE))
23277c478bd9Sstevel@tonic-gate 						goto exclude;
23287c478bd9Sstevel@tonic-gate 				}
23297c478bd9Sstevel@tonic-gate 
23307c478bd9Sstevel@tonic-gate 			} else if (SEGOP_GETVP(seg, seg->s_base, &mvp) != 0 ||
23317c478bd9Sstevel@tonic-gate 			    mvp == NULL || mvp->v_type != VREG) {
23327c478bd9Sstevel@tonic-gate 				if (!(content & CC_CONTENT_ANON))
23337c478bd9Sstevel@tonic-gate 					goto exclude;
23347c478bd9Sstevel@tonic-gate 
23357c478bd9Sstevel@tonic-gate 			} else if (prot == (PROT_READ | PROT_EXEC)) {
23367c478bd9Sstevel@tonic-gate 				if (!(content & CC_CONTENT_TEXT))
23377c478bd9Sstevel@tonic-gate 					goto exclude;
23387c478bd9Sstevel@tonic-gate 
23397c478bd9Sstevel@tonic-gate 			} else if (prot == PROT_READ) {
23407c478bd9Sstevel@tonic-gate 				if (!(content & CC_CONTENT_RODATA))
23417c478bd9Sstevel@tonic-gate 					goto exclude;
23427c478bd9Sstevel@tonic-gate 
23437c478bd9Sstevel@tonic-gate 			} else {
23447c478bd9Sstevel@tonic-gate 				if (!(content & CC_CONTENT_DATA))
23457c478bd9Sstevel@tonic-gate 					goto exclude;
23467c478bd9Sstevel@tonic-gate 			}
23477c478bd9Sstevel@tonic-gate 
23487c478bd9Sstevel@tonic-gate 			doffset = roundup(doffset, sizeof (Word));
23494e18e297SPatrick Mooney 			phdr[i].p_offset = doffset;
23504e18e297SPatrick Mooney 			phdr[i].p_filesz = size;
23517c478bd9Sstevel@tonic-gate 			doffset += size;
23527c478bd9Sstevel@tonic-gate exclude:
23537c478bd9Sstevel@tonic-gate 			i++;
23547c478bd9Sstevel@tonic-gate 		}
23554e18e297SPatrick Mooney 		VERIFY(tmp == NULL);
23564e18e297SPatrick Mooney 		if (overflowed)
23574e18e297SPatrick Mooney 			break;
23587c478bd9Sstevel@tonic-gate 	}
2359dc32d872SJosef 'Jeff' Sipek 	AS_LOCK_EXIT(as);
23607c478bd9Sstevel@tonic-gate 
23614e18e297SPatrick Mooney 	if (overflowed || i != nphdrs) {
23624e18e297SPatrick Mooney 		if (!retried) {
23634e18e297SPatrick Mooney 			retried = B_TRUE;
23644e18e297SPatrick Mooney 			overflowed = B_FALSE;
23657c478bd9Sstevel@tonic-gate 			kmem_free(bigwad, bigsize);
23667c478bd9Sstevel@tonic-gate 			goto top;
23677c478bd9Sstevel@tonic-gate 		}
23687c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "elfcore: core dump failed for "
23697c478bd9Sstevel@tonic-gate 		    "process %d; address space is changing", p->p_pid);
23707c478bd9Sstevel@tonic-gate 		error = EIO;
23717c478bd9Sstevel@tonic-gate 		goto done;
23727c478bd9Sstevel@tonic-gate 	}
23737c478bd9Sstevel@tonic-gate 
23747c478bd9Sstevel@tonic-gate 	if ((error = core_write(vp, UIO_SYSSPACE, poffset,
23754e18e297SPatrick Mooney 	    phdr, phdrsz, rlimit, credp)) != 0) {
23767c478bd9Sstevel@tonic-gate 		goto done;
23774e18e297SPatrick Mooney 	}
23787c478bd9Sstevel@tonic-gate 
23794e18e297SPatrick Mooney 	if ((error = write_old_elfnotes(p, sig, vp, phdr[0].p_offset, rlimit,
23804e18e297SPatrick Mooney 	    credp)) != 0) {
23817c478bd9Sstevel@tonic-gate 		goto done;
23824e18e297SPatrick Mooney 	}
23834e18e297SPatrick Mooney 	if ((error = write_elfnotes(p, sig, vp, phdr[1].p_offset, rlimit,
23844e18e297SPatrick Mooney 	    credp, content)) != 0) {
23857c478bd9Sstevel@tonic-gate 		goto done;
23864e18e297SPatrick Mooney 	}
23877c478bd9Sstevel@tonic-gate 
23887c478bd9Sstevel@tonic-gate 	for (i = 2; i < nphdrs; i++) {
2389f971a346SBryan Cantrill 		prkillinfo_t killinfo;
2390f971a346SBryan Cantrill 		sigqueue_t *sq;
2391f971a346SBryan Cantrill 		int sig, j;
2392f971a346SBryan Cantrill 
23934e18e297SPatrick Mooney 		if (phdr[i].p_filesz == 0)
23947c478bd9Sstevel@tonic-gate 			continue;
23957c478bd9Sstevel@tonic-gate 
23967c478bd9Sstevel@tonic-gate 		/*
23975d228828SRobert Mustacchi 		 * If we hit a region that was mapped PROT_NONE then we cannot
23985d228828SRobert Mustacchi 		 * continue dumping this normally as the kernel would be unable
23995d228828SRobert Mustacchi 		 * to read from the page and that would result in us failing to
24005d228828SRobert Mustacchi 		 * dump the page. As such, any region mapped PROT_NONE, we dump
24015d228828SRobert Mustacchi 		 * as a zero-filled page such that this is still represented in
24025d228828SRobert Mustacchi 		 * the map.
24035d228828SRobert Mustacchi 		 *
24047c478bd9Sstevel@tonic-gate 		 * If dumping out this segment fails, rather than failing
24057c478bd9Sstevel@tonic-gate 		 * the core dump entirely, we reset the size of the mapping
24067c478bd9Sstevel@tonic-gate 		 * to zero to indicate that the data is absent from the core
24077c478bd9Sstevel@tonic-gate 		 * file and or in the PF_SUNW_FAILURE flag to differentiate
24087c478bd9Sstevel@tonic-gate 		 * this from mappings that were excluded due to the core file
24097c478bd9Sstevel@tonic-gate 		 * content settings.
24107c478bd9Sstevel@tonic-gate 		 */
24114e18e297SPatrick Mooney 		if ((phdr[i].p_flags & (PF_R | PF_W | PF_X)) == 0) {
24124e18e297SPatrick Mooney 			size_t towrite = phdr[i].p_filesz;
24135d228828SRobert Mustacchi 			size_t curoff = 0;
24145d228828SRobert Mustacchi 
24155d228828SRobert Mustacchi 			if (zeropg == NULL) {
24165d228828SRobert Mustacchi 				zeropg = kmem_zalloc(elf_zeropg_sz, KM_SLEEP);
24175d228828SRobert Mustacchi 			}
24185d228828SRobert Mustacchi 
24195d228828SRobert Mustacchi 			error = 0;
24205d228828SRobert Mustacchi 			while (towrite != 0) {
24215d228828SRobert Mustacchi 				size_t len = MIN(towrite, elf_zeropg_sz);
24225d228828SRobert Mustacchi 
24235d228828SRobert Mustacchi 				error = core_write(vp, UIO_SYSSPACE,
24244e18e297SPatrick Mooney 				    phdr[i].p_offset + curoff, zeropg, len,
24254e18e297SPatrick Mooney 				    rlimit, credp);
24265d228828SRobert Mustacchi 				if (error != 0)
24275d228828SRobert Mustacchi 					break;
24285d228828SRobert Mustacchi 
24295d228828SRobert Mustacchi 				towrite -= len;
24305d228828SRobert Mustacchi 				curoff += len;
24315d228828SRobert Mustacchi 			}
24325d228828SRobert Mustacchi 		} else {
24334e18e297SPatrick Mooney 			error = core_seg(p, vp, phdr[i].p_offset,
24344e18e297SPatrick Mooney 			    (caddr_t)(uintptr_t)phdr[i].p_vaddr,
24354e18e297SPatrick Mooney 			    phdr[i].p_filesz, rlimit, credp);
2436f971a346SBryan Cantrill 		}
24374e18e297SPatrick Mooney 		if (error == 0)
24384e18e297SPatrick Mooney 			continue;
24397c478bd9Sstevel@tonic-gate 
2440f971a346SBryan Cantrill 		if ((sig = lwp->lwp_cursig) == 0) {
24417c478bd9Sstevel@tonic-gate 			/*
2442f971a346SBryan Cantrill 			 * We failed due to something other than a signal.
24437c478bd9Sstevel@tonic-gate 			 * Since the space reserved for the segment is now
24447c478bd9Sstevel@tonic-gate 			 * unused, we stash the errno in the first four
24457c478bd9Sstevel@tonic-gate 			 * bytes. This undocumented interface will let us
24467c478bd9Sstevel@tonic-gate 			 * understand the nature of the failure.
24477c478bd9Sstevel@tonic-gate 			 */
24484e18e297SPatrick Mooney 			(void) core_write(vp, UIO_SYSSPACE, phdr[i].p_offset,
24497c478bd9Sstevel@tonic-gate 			    &error, sizeof (error), rlimit, credp);
24507c478bd9Sstevel@tonic-gate 
24514e18e297SPatrick Mooney 			phdr[i].p_filesz = 0;
24524e18e297SPatrick Mooney 			phdr[i].p_flags |= PF_SUNW_FAILURE;
24537c478bd9Sstevel@tonic-gate 			if ((error = core_write(vp, UIO_SYSSPACE,
24544e18e297SPatrick Mooney 			    poffset + sizeof (Phdr) * i, &phdr[i],
24554e18e297SPatrick Mooney 			    sizeof (Phdr), rlimit, credp)) != 0)
24567c478bd9Sstevel@tonic-gate 				goto done;
2457f971a346SBryan Cantrill 
2458f971a346SBryan Cantrill 			continue;
2459f971a346SBryan Cantrill 		}
2460f971a346SBryan Cantrill 
2461f971a346SBryan Cantrill 		/*
2462f971a346SBryan Cantrill 		 * We took a signal.  We want to abort the dump entirely, but
2463f971a346SBryan Cantrill 		 * we also want to indicate what failed and why.  We therefore
2464f971a346SBryan Cantrill 		 * use the space reserved for the first failing segment to
2465f971a346SBryan Cantrill 		 * write our error (which, for purposes of compatability with
2466f971a346SBryan Cantrill 		 * older core dump readers, we set to EINTR) followed by any
2467f971a346SBryan Cantrill 		 * siginfo associated with the signal.
2468f971a346SBryan Cantrill 		 */
2469f971a346SBryan Cantrill 		bzero(&killinfo, sizeof (killinfo));
2470f971a346SBryan Cantrill 		killinfo.prk_error = EINTR;
2471f971a346SBryan Cantrill 
2472f971a346SBryan Cantrill 		sq = sig == SIGKILL ? curproc->p_killsqp : lwp->lwp_curinfo;
2473f971a346SBryan Cantrill 
2474f971a346SBryan Cantrill 		if (sq != NULL) {
2475f971a346SBryan Cantrill 			bcopy(&sq->sq_info, &killinfo.prk_info,
2476ea260350SBryan Cantrill 			    sizeof (sq->sq_info));
2477f971a346SBryan Cantrill 		} else {
2478f971a346SBryan Cantrill 			killinfo.prk_info.si_signo = lwp->lwp_cursig;
2479f971a346SBryan Cantrill 			killinfo.prk_info.si_code = SI_NOINFO;
24807c478bd9Sstevel@tonic-gate 		}
2481f971a346SBryan Cantrill 
2482f971a346SBryan Cantrill #if (defined(_SYSCALL32_IMPL) || defined(_LP64))
2483f971a346SBryan Cantrill 		/*
2484f971a346SBryan Cantrill 		 * If this is a 32-bit process, we need to translate from the
2485f971a346SBryan Cantrill 		 * native siginfo to the 32-bit variant.  (Core readers must
2486f971a346SBryan Cantrill 		 * always have the same data model as their target or must
2487f971a346SBryan Cantrill 		 * be aware of -- and compensate for -- data model differences.)
2488f971a346SBryan Cantrill 		 */
2489f971a346SBryan Cantrill 		if (curproc->p_model == DATAMODEL_ILP32) {
2490f971a346SBryan Cantrill 			siginfo32_t si32;
2491f971a346SBryan Cantrill 
2492f971a346SBryan Cantrill 			siginfo_kto32((k_siginfo_t *)&killinfo.prk_info, &si32);
2493f971a346SBryan Cantrill 			bcopy(&si32, &killinfo.prk_info, sizeof (si32));
2494f971a346SBryan Cantrill 		}
2495f971a346SBryan Cantrill #endif
2496f971a346SBryan Cantrill 
24974e18e297SPatrick Mooney 		(void) core_write(vp, UIO_SYSSPACE, phdr[i].p_offset,
2498f971a346SBryan Cantrill 		    &killinfo, sizeof (killinfo), rlimit, credp);
2499f971a346SBryan Cantrill 
2500f971a346SBryan Cantrill 		/*
2501f971a346SBryan Cantrill 		 * For the segment on which we took the signal, indicate that
2502f971a346SBryan Cantrill 		 * its data now refers to a siginfo.
2503f971a346SBryan Cantrill 		 */
25044e18e297SPatrick Mooney 		phdr[i].p_filesz = 0;
25054e18e297SPatrick Mooney 		phdr[i].p_flags |= PF_SUNW_FAILURE | PF_SUNW_KILLED |
2506f971a346SBryan Cantrill 		    PF_SUNW_SIGINFO;
2507f971a346SBryan Cantrill 
2508f971a346SBryan Cantrill 		/*
2509f971a346SBryan Cantrill 		 * And for every other segment, indicate that its absence
2510f971a346SBryan Cantrill 		 * is due to a signal.
2511f971a346SBryan Cantrill 		 */
2512f971a346SBryan Cantrill 		for (j = i + 1; j < nphdrs; j++) {
25134e18e297SPatrick Mooney 			phdr[j].p_filesz = 0;
25144e18e297SPatrick Mooney 			phdr[j].p_flags |= PF_SUNW_FAILURE | PF_SUNW_KILLED;
2515f971a346SBryan Cantrill 		}
2516f971a346SBryan Cantrill 
2517f971a346SBryan Cantrill 		/*
2518f971a346SBryan Cantrill 		 * Finally, write out our modified program headers.
2519f971a346SBryan Cantrill 		 */
2520f971a346SBryan Cantrill 		if ((error = core_write(vp, UIO_SYSSPACE,
25214e18e297SPatrick Mooney 		    poffset + sizeof (Phdr) * i, &phdr[i],
25224e18e297SPatrick Mooney 		    sizeof (Phdr) * (nphdrs - i), rlimit, credp)) != 0) {
2523f971a346SBryan Cantrill 			goto done;
25244e18e297SPatrick Mooney 		}
2525f971a346SBryan Cantrill 
2526f971a346SBryan Cantrill 		break;
25277c478bd9Sstevel@tonic-gate 	}
25287c478bd9Sstevel@tonic-gate 
25297c478bd9Sstevel@tonic-gate 	if (nshdrs > 0) {
25304e18e297SPatrick Mooney 		Shdr *shdr = (Shdr *)bigwad;
253130da1432Sahl 
25324e18e297SPatrick Mooney 		bzero(shdr, shdrsz);
253330da1432Sahl 		if (nshdrs > 1) {
25344e18e297SPatrick Mooney 			ctx.ecc_doffset = doffset;
2535dc32d872SJosef 'Jeff' Sipek 			AS_LOCK_ENTER(as, RW_WRITER);
25364e18e297SPatrick Mooney 			error = elf_process_scns(&ctx, shdr, nshdrs, NULL);
25374e18e297SPatrick Mooney 			AS_LOCK_EXIT(as);
2538*6233c8a8SAndy Fiddaman 			if (error != 0)
253930da1432Sahl 				goto done;
25407c478bd9Sstevel@tonic-gate 		}
25414e18e297SPatrick Mooney 		/* Copy any extended format data destined for the first shdr */
25424e18e297SPatrick Mooney 		bcopy(&shdr0, shdr, sizeof (shdr0));
25437c478bd9Sstevel@tonic-gate 
25444e18e297SPatrick Mooney 		error = core_write(vp, UIO_SYSSPACE, soffset, shdr, shdrsz,
25454e18e297SPatrick Mooney 		    rlimit, credp);
25467c478bd9Sstevel@tonic-gate 	}
25477c478bd9Sstevel@tonic-gate 
25487c478bd9Sstevel@tonic-gate done:
25494e18e297SPatrick Mooney 	if (zeropg != NULL)
25505d228828SRobert Mustacchi 		kmem_free(zeropg, elf_zeropg_sz);
25514e18e297SPatrick Mooney 	if (ctx.ecc_bufsz != 0)
25524e18e297SPatrick Mooney 		kmem_free(ctx.ecc_buf, ctx.ecc_bufsz);
25537c478bd9Sstevel@tonic-gate 	kmem_free(bigwad, bigsize);
25547c478bd9Sstevel@tonic-gate 	return (error);
25557c478bd9Sstevel@tonic-gate }
25567c478bd9Sstevel@tonic-gate 
25577c478bd9Sstevel@tonic-gate #ifndef	_ELF32_COMPAT
25587c478bd9Sstevel@tonic-gate 
25597c478bd9Sstevel@tonic-gate static struct execsw esw = {
25607c478bd9Sstevel@tonic-gate #ifdef	_LP64
25617c478bd9Sstevel@tonic-gate 	elf64magicstr,
25627c478bd9Sstevel@tonic-gate #else	/* _LP64 */
25637c478bd9Sstevel@tonic-gate 	elf32magicstr,
25647c478bd9Sstevel@tonic-gate #endif	/* _LP64 */
25657c478bd9Sstevel@tonic-gate 	0,
25667c478bd9Sstevel@tonic-gate 	5,
25677c478bd9Sstevel@tonic-gate 	elfexec,
25687c478bd9Sstevel@tonic-gate 	elfcore
25697c478bd9Sstevel@tonic-gate };
25707c478bd9Sstevel@tonic-gate 
25717c478bd9Sstevel@tonic-gate static struct modlexec modlexec = {
2572a0de58d6SRoger A. Faulkner 	&mod_execops, "exec module for elf", &esw
25737c478bd9Sstevel@tonic-gate };
25747c478bd9Sstevel@tonic-gate 
25757c478bd9Sstevel@tonic-gate #ifdef	_LP64
25767c478bd9Sstevel@tonic-gate extern int elf32exec(vnode_t *vp, execa_t *uap, uarg_t *args,
25774e18e297SPatrick Mooney 			intpdata_t *idatap, int level, size_t *execsz,
25789acbbeafSnn 			int setid, caddr_t exec_file, cred_t *cred,
25799acbbeafSnn 			int brand_action);
25807c478bd9Sstevel@tonic-gate extern int elf32core(vnode_t *vp, proc_t *p, cred_t *credp,
25817c478bd9Sstevel@tonic-gate 			rlim64_t rlimit, int sig, core_content_t content);
25827c478bd9Sstevel@tonic-gate 
25837c478bd9Sstevel@tonic-gate static struct execsw esw32 = {
25847c478bd9Sstevel@tonic-gate 	elf32magicstr,
25857c478bd9Sstevel@tonic-gate 	0,
25867c478bd9Sstevel@tonic-gate 	5,
25877c478bd9Sstevel@tonic-gate 	elf32exec,
25887c478bd9Sstevel@tonic-gate 	elf32core
25897c478bd9Sstevel@tonic-gate };
25907c478bd9Sstevel@tonic-gate 
25917c478bd9Sstevel@tonic-gate static struct modlexec modlexec32 = {
25927c478bd9Sstevel@tonic-gate 	&mod_execops, "32-bit exec module for elf", &esw32
25937c478bd9Sstevel@tonic-gate };
25947c478bd9Sstevel@tonic-gate #endif	/* _LP64 */
25957c478bd9Sstevel@tonic-gate 
25967c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = {
25977c478bd9Sstevel@tonic-gate 	MODREV_1,
25987c478bd9Sstevel@tonic-gate 	(void *)&modlexec,
25997c478bd9Sstevel@tonic-gate #ifdef	_LP64
26007c478bd9Sstevel@tonic-gate 	(void *)&modlexec32,
26017c478bd9Sstevel@tonic-gate #endif	/* _LP64 */
26027c478bd9Sstevel@tonic-gate 	NULL
26037c478bd9Sstevel@tonic-gate };
26047c478bd9Sstevel@tonic-gate 
26057c478bd9Sstevel@tonic-gate int
_init(void)26067c478bd9Sstevel@tonic-gate _init(void)
26077c478bd9Sstevel@tonic-gate {
26087c478bd9Sstevel@tonic-gate 	return (mod_install(&modlinkage));
26097c478bd9Sstevel@tonic-gate }
26107c478bd9Sstevel@tonic-gate 
26117c478bd9Sstevel@tonic-gate int
_fini(void)26127c478bd9Sstevel@tonic-gate _fini(void)
26137c478bd9Sstevel@tonic-gate {
26147c478bd9Sstevel@tonic-gate 	return (mod_remove(&modlinkage));
26157c478bd9Sstevel@tonic-gate }
26167c478bd9Sstevel@tonic-gate 
26177c478bd9Sstevel@tonic-gate int
_info(struct modinfo * modinfop)26187c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
26197c478bd9Sstevel@tonic-gate {
26207c478bd9Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
26217c478bd9Sstevel@tonic-gate }
26227c478bd9Sstevel@tonic-gate 
26237c478bd9Sstevel@tonic-gate #endif	/* !_ELF32_COMPAT */
2624