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(¬e, 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, ¬e,
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