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 */ 277c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 28ebb8ac07SRobert Mustacchi /* 29*263f549eSPatrick Mooney * Copyright 2016 Joyent, Inc. 30ebb8ac07SRobert Mustacchi */ 317c478bd9Sstevel@tonic-gate 327c478bd9Sstevel@tonic-gate #include <sys/types.h> 337c478bd9Sstevel@tonic-gate #include <sys/param.h> 347c478bd9Sstevel@tonic-gate #include <sys/thread.h> 357c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 367c478bd9Sstevel@tonic-gate #include <sys/signal.h> 377c478bd9Sstevel@tonic-gate #include <sys/cred.h> 387c478bd9Sstevel@tonic-gate #include <sys/user.h> 397c478bd9Sstevel@tonic-gate #include <sys/errno.h> 407c478bd9Sstevel@tonic-gate #include <sys/vnode.h> 417c478bd9Sstevel@tonic-gate #include <sys/mman.h> 427c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 437c478bd9Sstevel@tonic-gate #include <sys/proc.h> 447c478bd9Sstevel@tonic-gate #include <sys/pathname.h> 457c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 467c478bd9Sstevel@tonic-gate #include <sys/systm.h> 477c478bd9Sstevel@tonic-gate #include <sys/elf.h> 487c478bd9Sstevel@tonic-gate #include <sys/vmsystm.h> 497c478bd9Sstevel@tonic-gate #include <sys/debug.h> 507c478bd9Sstevel@tonic-gate #include <sys/auxv.h> 517c478bd9Sstevel@tonic-gate #include <sys/exec.h> 527c478bd9Sstevel@tonic-gate #include <sys/prsystm.h> 537c478bd9Sstevel@tonic-gate #include <vm/as.h> 547c478bd9Sstevel@tonic-gate #include <vm/rm.h> 557c478bd9Sstevel@tonic-gate #include <vm/seg.h> 567c478bd9Sstevel@tonic-gate #include <vm/seg_vn.h> 577c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 587c478bd9Sstevel@tonic-gate #include <sys/systeminfo.h> 597c478bd9Sstevel@tonic-gate #include <sys/vmparam.h> 607c478bd9Sstevel@tonic-gate #include <sys/machelf.h> 617c478bd9Sstevel@tonic-gate #include <sys/shm_impl.h> 627c478bd9Sstevel@tonic-gate #include <sys/archsystm.h> 637c478bd9Sstevel@tonic-gate #include <sys/fasttrap.h> 649acbbeafSnn35248 #include <sys/brand.h> 657c478bd9Sstevel@tonic-gate #include "elf_impl.h" 669acbbeafSnn35248 #include <sys/sdt.h> 67f971a346SBryan Cantrill #include <sys/siginfo.h> 689acbbeafSnn35248 69*263f549eSPatrick Mooney #if defined(__x86) 70*263f549eSPatrick Mooney #include <sys/comm_page_util.h> 71*263f549eSPatrick Mooney #endif /* defined(__x86) */ 72*263f549eSPatrick Mooney 73*263f549eSPatrick Mooney 747c478bd9Sstevel@tonic-gate extern int at_flags; 757c478bd9Sstevel@tonic-gate 767c478bd9Sstevel@tonic-gate #define ORIGIN_STR "ORIGIN" 777c478bd9Sstevel@tonic-gate #define ORIGIN_STR_SIZE 6 787c478bd9Sstevel@tonic-gate 7930da1432Sahl static int getelfhead(vnode_t *, cred_t *, Ehdr *, int *, int *, int *); 8030da1432Sahl static int getelfphdr(vnode_t *, cred_t *, const Ehdr *, int, caddr_t *, 8130da1432Sahl ssize_t *); 8230da1432Sahl static int getelfshdr(vnode_t *, cred_t *, const Ehdr *, int, int, caddr_t *, 8330da1432Sahl ssize_t *, caddr_t *, ssize_t *); 8430da1432Sahl static size_t elfsize(Ehdr *, int, caddr_t, uintptr_t *); 8530da1432Sahl static int mapelfexec(vnode_t *, Ehdr *, int, caddr_t, 867c478bd9Sstevel@tonic-gate Phdr **, Phdr **, Phdr **, Phdr **, Phdr *, 879acbbeafSnn35248 caddr_t *, caddr_t *, intptr_t *, intptr_t *, size_t, long *, size_t *); 887c478bd9Sstevel@tonic-gate 897c478bd9Sstevel@tonic-gate typedef enum { 907c478bd9Sstevel@tonic-gate STR_CTF, 917c478bd9Sstevel@tonic-gate STR_SYMTAB, 927c478bd9Sstevel@tonic-gate STR_DYNSYM, 937c478bd9Sstevel@tonic-gate STR_STRTAB, 947c478bd9Sstevel@tonic-gate STR_DYNSTR, 957c478bd9Sstevel@tonic-gate STR_SHSTRTAB, 967c478bd9Sstevel@tonic-gate STR_NUM 977c478bd9Sstevel@tonic-gate } shstrtype_t; 987c478bd9Sstevel@tonic-gate 997c478bd9Sstevel@tonic-gate static const char *shstrtab_data[] = { 1007c478bd9Sstevel@tonic-gate ".SUNW_ctf", 1017c478bd9Sstevel@tonic-gate ".symtab", 1027c478bd9Sstevel@tonic-gate ".dynsym", 1037c478bd9Sstevel@tonic-gate ".strtab", 1047c478bd9Sstevel@tonic-gate ".dynstr", 1057c478bd9Sstevel@tonic-gate ".shstrtab" 1067c478bd9Sstevel@tonic-gate }; 1077c478bd9Sstevel@tonic-gate 1087c478bd9Sstevel@tonic-gate typedef struct shstrtab { 1097c478bd9Sstevel@tonic-gate int sst_ndx[STR_NUM]; 1107c478bd9Sstevel@tonic-gate int sst_cur; 1117c478bd9Sstevel@tonic-gate } shstrtab_t; 1127c478bd9Sstevel@tonic-gate 1137c478bd9Sstevel@tonic-gate static void 1147c478bd9Sstevel@tonic-gate shstrtab_init(shstrtab_t *s) 1157c478bd9Sstevel@tonic-gate { 1167c478bd9Sstevel@tonic-gate bzero(&s->sst_ndx, sizeof (s->sst_ndx)); 1177c478bd9Sstevel@tonic-gate s->sst_cur = 1; 1187c478bd9Sstevel@tonic-gate } 1197c478bd9Sstevel@tonic-gate 1207c478bd9Sstevel@tonic-gate static int 1217c478bd9Sstevel@tonic-gate shstrtab_ndx(shstrtab_t *s, shstrtype_t type) 1227c478bd9Sstevel@tonic-gate { 1237c478bd9Sstevel@tonic-gate int ret; 1247c478bd9Sstevel@tonic-gate 1257c478bd9Sstevel@tonic-gate if ((ret = s->sst_ndx[type]) != 0) 1267c478bd9Sstevel@tonic-gate return (ret); 1277c478bd9Sstevel@tonic-gate 1287c478bd9Sstevel@tonic-gate ret = s->sst_ndx[type] = s->sst_cur; 1297c478bd9Sstevel@tonic-gate s->sst_cur += strlen(shstrtab_data[type]) + 1; 1307c478bd9Sstevel@tonic-gate 1317c478bd9Sstevel@tonic-gate return (ret); 1327c478bd9Sstevel@tonic-gate } 1337c478bd9Sstevel@tonic-gate 1347c478bd9Sstevel@tonic-gate static size_t 1357c478bd9Sstevel@tonic-gate shstrtab_size(const shstrtab_t *s) 1367c478bd9Sstevel@tonic-gate { 1377c478bd9Sstevel@tonic-gate return (s->sst_cur); 1387c478bd9Sstevel@tonic-gate } 1397c478bd9Sstevel@tonic-gate 1407c478bd9Sstevel@tonic-gate static void 1417c478bd9Sstevel@tonic-gate shstrtab_dump(const shstrtab_t *s, char *buf) 1427c478bd9Sstevel@tonic-gate { 1437c478bd9Sstevel@tonic-gate int i, ndx; 1447c478bd9Sstevel@tonic-gate 1457c478bd9Sstevel@tonic-gate *buf = '\0'; 1467c478bd9Sstevel@tonic-gate for (i = 0; i < STR_NUM; i++) { 1477c478bd9Sstevel@tonic-gate if ((ndx = s->sst_ndx[i]) != 0) 1487c478bd9Sstevel@tonic-gate (void) strcpy(buf + ndx, shstrtab_data[i]); 1497c478bd9Sstevel@tonic-gate } 1507c478bd9Sstevel@tonic-gate } 1517c478bd9Sstevel@tonic-gate 1527c478bd9Sstevel@tonic-gate static int 1537c478bd9Sstevel@tonic-gate dtrace_safe_phdr(Phdr *phdrp, struct uarg *args, uintptr_t base) 1547c478bd9Sstevel@tonic-gate { 1557c478bd9Sstevel@tonic-gate ASSERT(phdrp->p_type == PT_SUNWDTRACE); 1567c478bd9Sstevel@tonic-gate 1577c478bd9Sstevel@tonic-gate /* 1587c478bd9Sstevel@tonic-gate * See the comment in fasttrap.h for information on how to safely 1597c478bd9Sstevel@tonic-gate * update this program header. 1607c478bd9Sstevel@tonic-gate */ 1617c478bd9Sstevel@tonic-gate if (phdrp->p_memsz < PT_SUNWDTRACE_SIZE || 1627c478bd9Sstevel@tonic-gate (phdrp->p_flags & (PF_R | PF_W | PF_X)) != (PF_R | PF_W | PF_X)) 1637c478bd9Sstevel@tonic-gate return (-1); 1647c478bd9Sstevel@tonic-gate 1657c478bd9Sstevel@tonic-gate args->thrptr = phdrp->p_vaddr + base; 1667c478bd9Sstevel@tonic-gate 1677c478bd9Sstevel@tonic-gate return (0); 1687c478bd9Sstevel@tonic-gate } 1697c478bd9Sstevel@tonic-gate 1709acbbeafSnn35248 /* 1719acbbeafSnn35248 * Map in the executable pointed to by vp. Returns 0 on success. 1729acbbeafSnn35248 */ 1739acbbeafSnn35248 int 174396a100bSedp mapexec_brand(vnode_t *vp, uarg_t *args, Ehdr *ehdr, Addr *uphdr_vaddr, 1759acbbeafSnn35248 intptr_t *voffset, caddr_t exec_file, int *interp, caddr_t *bssbase, 17607678296Ssl108498 caddr_t *brkbase, size_t *brksize, uintptr_t *lddatap) 1779acbbeafSnn35248 { 1789acbbeafSnn35248 size_t len; 1799acbbeafSnn35248 struct vattr vat; 1809acbbeafSnn35248 caddr_t phdrbase = NULL; 1819acbbeafSnn35248 ssize_t phdrsize; 1829acbbeafSnn35248 int nshdrs, shstrndx, nphdrs; 1839acbbeafSnn35248 int error = 0; 1849acbbeafSnn35248 Phdr *uphdr = NULL; 1859acbbeafSnn35248 Phdr *junk = NULL; 1869acbbeafSnn35248 Phdr *dynphdr = NULL; 1879acbbeafSnn35248 Phdr *dtrphdr = NULL; 1889acbbeafSnn35248 uintptr_t lddata; 1899acbbeafSnn35248 long execsz; 1909acbbeafSnn35248 intptr_t minaddr; 1919acbbeafSnn35248 19207678296Ssl108498 if (lddatap != NULL) 19307678296Ssl108498 *lddatap = NULL; 19407678296Ssl108498 1959acbbeafSnn35248 if (error = execpermissions(vp, &vat, args)) { 1969acbbeafSnn35248 uprintf("%s: Cannot execute %s\n", exec_file, args->pathname); 1979acbbeafSnn35248 return (error); 1989acbbeafSnn35248 } 1999acbbeafSnn35248 2009acbbeafSnn35248 if ((error = getelfhead(vp, CRED(), ehdr, &nshdrs, &shstrndx, 2019acbbeafSnn35248 &nphdrs)) != 0 || 2029acbbeafSnn35248 (error = getelfphdr(vp, CRED(), ehdr, nphdrs, &phdrbase, 2039acbbeafSnn35248 &phdrsize)) != 0) { 2049acbbeafSnn35248 uprintf("%s: Cannot read %s\n", exec_file, args->pathname); 2059acbbeafSnn35248 return (error); 2069acbbeafSnn35248 } 2079acbbeafSnn35248 2089acbbeafSnn35248 if ((len = elfsize(ehdr, nphdrs, phdrbase, &lddata)) == 0) { 2099acbbeafSnn35248 uprintf("%s: Nothing to load in %s", exec_file, args->pathname); 2109acbbeafSnn35248 kmem_free(phdrbase, phdrsize); 2119acbbeafSnn35248 return (ENOEXEC); 2129acbbeafSnn35248 } 21307678296Ssl108498 if (lddatap != NULL) 21407678296Ssl108498 *lddatap = lddata; 2159acbbeafSnn35248 2169acbbeafSnn35248 if (error = mapelfexec(vp, ehdr, nphdrs, phdrbase, &uphdr, &dynphdr, 2179acbbeafSnn35248 &junk, &dtrphdr, NULL, bssbase, brkbase, voffset, &minaddr, 2189acbbeafSnn35248 len, &execsz, brksize)) { 2199acbbeafSnn35248 uprintf("%s: Cannot map %s\n", exec_file, args->pathname); 2209acbbeafSnn35248 kmem_free(phdrbase, phdrsize); 2219acbbeafSnn35248 return (error); 2229acbbeafSnn35248 } 2239acbbeafSnn35248 2249acbbeafSnn35248 /* 2259acbbeafSnn35248 * Inform our caller if the executable needs an interpreter. 2269acbbeafSnn35248 */ 2279acbbeafSnn35248 *interp = (dynphdr == NULL) ? 0 : 1; 2289acbbeafSnn35248 2299acbbeafSnn35248 /* 2309acbbeafSnn35248 * If this is a statically linked executable, voffset should indicate 2319acbbeafSnn35248 * the address of the executable itself (it normally holds the address 2329acbbeafSnn35248 * of the interpreter). 2339acbbeafSnn35248 */ 2349acbbeafSnn35248 if (ehdr->e_type == ET_EXEC && *interp == 0) 2359acbbeafSnn35248 *voffset = minaddr; 2369acbbeafSnn35248 2379acbbeafSnn35248 if (uphdr != NULL) { 2389acbbeafSnn35248 *uphdr_vaddr = uphdr->p_vaddr; 2399acbbeafSnn35248 } else { 240396a100bSedp *uphdr_vaddr = (Addr)-1; 2419acbbeafSnn35248 } 2429acbbeafSnn35248 2439acbbeafSnn35248 kmem_free(phdrbase, phdrsize); 2449acbbeafSnn35248 return (error); 2459acbbeafSnn35248 } 2469acbbeafSnn35248 2477c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 2487c478bd9Sstevel@tonic-gate int 2497c478bd9Sstevel@tonic-gate elfexec(vnode_t *vp, execa_t *uap, uarg_t *args, intpdata_t *idatap, 2509acbbeafSnn35248 int level, long *execsz, int setid, caddr_t exec_file, cred_t *cred, 2519acbbeafSnn35248 int brand_action) 2527c478bd9Sstevel@tonic-gate { 2537c478bd9Sstevel@tonic-gate caddr_t phdrbase = NULL; 2547c478bd9Sstevel@tonic-gate caddr_t bssbase = 0; 2557c478bd9Sstevel@tonic-gate caddr_t brkbase = 0; 2567c478bd9Sstevel@tonic-gate size_t brksize = 0; 2577c478bd9Sstevel@tonic-gate ssize_t dlnsize; 2587c478bd9Sstevel@tonic-gate aux_entry_t *aux; 2597c478bd9Sstevel@tonic-gate int error; 2607c478bd9Sstevel@tonic-gate ssize_t resid; 2617c478bd9Sstevel@tonic-gate int fd = -1; 2627c478bd9Sstevel@tonic-gate intptr_t voffset; 2637c478bd9Sstevel@tonic-gate Phdr *dyphdr = NULL; 2647c478bd9Sstevel@tonic-gate Phdr *stphdr = NULL; 2657c478bd9Sstevel@tonic-gate Phdr *uphdr = NULL; 2667c478bd9Sstevel@tonic-gate Phdr *junk = NULL; 2677c478bd9Sstevel@tonic-gate size_t len; 2687c478bd9Sstevel@tonic-gate ssize_t phdrsize; 2697c478bd9Sstevel@tonic-gate int postfixsize = 0; 2707c478bd9Sstevel@tonic-gate int i, hsize; 2717c478bd9Sstevel@tonic-gate Phdr *phdrp; 2727c478bd9Sstevel@tonic-gate Phdr *dataphdrp = NULL; 2737c478bd9Sstevel@tonic-gate Phdr *dtrphdr; 274a0de58d6SRoger A. Faulkner Phdr *capphdr = NULL; 275a0de58d6SRoger A. Faulkner Cap *cap = NULL; 276a0de58d6SRoger A. Faulkner ssize_t capsize; 2777c478bd9Sstevel@tonic-gate int hasu = 0; 2787c478bd9Sstevel@tonic-gate int hasauxv = 0; 2797c478bd9Sstevel@tonic-gate int hasdy = 0; 2809acbbeafSnn35248 int branded = 0; 2817c478bd9Sstevel@tonic-gate 2827c478bd9Sstevel@tonic-gate struct proc *p = ttoproc(curthread); 2837c478bd9Sstevel@tonic-gate struct user *up = PTOU(p); 2847c478bd9Sstevel@tonic-gate struct bigwad { 2857c478bd9Sstevel@tonic-gate Ehdr ehdr; 2867c478bd9Sstevel@tonic-gate aux_entry_t elfargs[__KERN_NAUXV_IMPL]; 2877c478bd9Sstevel@tonic-gate char dl_name[MAXPATHLEN]; 2887c478bd9Sstevel@tonic-gate char pathbuf[MAXPATHLEN]; 2897c478bd9Sstevel@tonic-gate struct vattr vattr; 2907c478bd9Sstevel@tonic-gate struct execenv exenv; 2917c478bd9Sstevel@tonic-gate } *bigwad; /* kmem_alloc this behemoth so we don't blow stack */ 2927c478bd9Sstevel@tonic-gate Ehdr *ehdrp; 29330da1432Sahl int nshdrs, shstrndx, nphdrs; 2947c478bd9Sstevel@tonic-gate char *dlnp; 2957c478bd9Sstevel@tonic-gate char *pathbufp; 2967c478bd9Sstevel@tonic-gate rlim64_t limit; 2977c478bd9Sstevel@tonic-gate rlim64_t roundlimit; 2987c478bd9Sstevel@tonic-gate 2997c478bd9Sstevel@tonic-gate ASSERT(p->p_model == DATAMODEL_ILP32 || p->p_model == DATAMODEL_LP64); 3007c478bd9Sstevel@tonic-gate 3017c478bd9Sstevel@tonic-gate bigwad = kmem_alloc(sizeof (struct bigwad), KM_SLEEP); 3027c478bd9Sstevel@tonic-gate ehdrp = &bigwad->ehdr; 3037c478bd9Sstevel@tonic-gate dlnp = bigwad->dl_name; 3047c478bd9Sstevel@tonic-gate pathbufp = bigwad->pathbuf; 3057c478bd9Sstevel@tonic-gate 3067c478bd9Sstevel@tonic-gate /* 3077c478bd9Sstevel@tonic-gate * Obtain ELF and program header information. 3087c478bd9Sstevel@tonic-gate */ 30930da1432Sahl if ((error = getelfhead(vp, CRED(), ehdrp, &nshdrs, &shstrndx, 31030da1432Sahl &nphdrs)) != 0 || 31130da1432Sahl (error = getelfphdr(vp, CRED(), ehdrp, nphdrs, &phdrbase, 31230da1432Sahl &phdrsize)) != 0) 3137c478bd9Sstevel@tonic-gate goto out; 3147c478bd9Sstevel@tonic-gate 3157c478bd9Sstevel@tonic-gate /* 316161d9479Srie * Prevent executing an ELF file that has no entry point. 317161d9479Srie */ 318161d9479Srie if (ehdrp->e_entry == 0) { 319161d9479Srie uprintf("%s: Bad entry point\n", exec_file); 320161d9479Srie goto bad; 321161d9479Srie } 322161d9479Srie 323161d9479Srie /* 3247c478bd9Sstevel@tonic-gate * Put data model that we're exec-ing to into the args passed to 3257c478bd9Sstevel@tonic-gate * exec_args(), so it will know what it is copying to on new stack. 3267c478bd9Sstevel@tonic-gate * Now that we know whether we are exec-ing a 32-bit or 64-bit 3277c478bd9Sstevel@tonic-gate * executable, we can set execsz with the appropriate NCARGS. 3287c478bd9Sstevel@tonic-gate */ 3297c478bd9Sstevel@tonic-gate #ifdef _LP64 3307c478bd9Sstevel@tonic-gate if (ehdrp->e_ident[EI_CLASS] == ELFCLASS32) { 3317c478bd9Sstevel@tonic-gate args->to_model = DATAMODEL_ILP32; 3327c478bd9Sstevel@tonic-gate *execsz = btopr(SINCR) + btopr(SSIZE) + btopr(NCARGS32-1); 3337c478bd9Sstevel@tonic-gate } else { 3347c478bd9Sstevel@tonic-gate args->to_model = DATAMODEL_LP64; 3357c478bd9Sstevel@tonic-gate args->stk_prot &= ~PROT_EXEC; 3367c478bd9Sstevel@tonic-gate #if defined(__i386) || defined(__amd64) 3377c478bd9Sstevel@tonic-gate args->dat_prot &= ~PROT_EXEC; 3387c478bd9Sstevel@tonic-gate #endif 3397c478bd9Sstevel@tonic-gate *execsz = btopr(SINCR) + btopr(SSIZE) + btopr(NCARGS64-1); 3407c478bd9Sstevel@tonic-gate } 3417c478bd9Sstevel@tonic-gate #else /* _LP64 */ 3427c478bd9Sstevel@tonic-gate args->to_model = DATAMODEL_ILP32; 3437c478bd9Sstevel@tonic-gate *execsz = btopr(SINCR) + btopr(SSIZE) + btopr(NCARGS-1); 3447c478bd9Sstevel@tonic-gate #endif /* _LP64 */ 3457c478bd9Sstevel@tonic-gate 3467c478bd9Sstevel@tonic-gate /* 347396a100bSedp * We delay invoking the brand callback until we've figured out 348396a100bSedp * what kind of elf binary we're trying to run, 32-bit or 64-bit. 349396a100bSedp * We do this because now the brand library can just check 350396a100bSedp * args->to_model to see if the target is 32-bit or 64-bit without 351396a100bSedp * having do duplicate all the code above. 352396a100bSedp */ 353396a100bSedp if ((level < 2) && 354396a100bSedp (brand_action != EBA_NATIVE) && (PROC_IS_BRANDED(p))) { 355ec77975fSedp error = BROP(p)->b_elfexec(vp, uap, args, 356396a100bSedp idatap, level + 1, execsz, setid, exec_file, cred, 357ec77975fSedp brand_action); 358ec77975fSedp goto out; 359396a100bSedp } 360396a100bSedp 361396a100bSedp /* 3627c478bd9Sstevel@tonic-gate * Determine aux size now so that stack can be built 3637c478bd9Sstevel@tonic-gate * in one shot (except actual copyout of aux image), 3647c478bd9Sstevel@tonic-gate * determine any non-default stack protections, 3657c478bd9Sstevel@tonic-gate * and still have this code be machine independent. 3667c478bd9Sstevel@tonic-gate */ 3677c478bd9Sstevel@tonic-gate hsize = ehdrp->e_phentsize; 3687c478bd9Sstevel@tonic-gate phdrp = (Phdr *)phdrbase; 36930da1432Sahl for (i = nphdrs; i > 0; i--) { 3707c478bd9Sstevel@tonic-gate switch (phdrp->p_type) { 3717c478bd9Sstevel@tonic-gate case PT_INTERP: 3727c478bd9Sstevel@tonic-gate hasauxv = hasdy = 1; 3737c478bd9Sstevel@tonic-gate break; 3747c478bd9Sstevel@tonic-gate case PT_PHDR: 3757c478bd9Sstevel@tonic-gate hasu = 1; 3767c478bd9Sstevel@tonic-gate break; 3777c478bd9Sstevel@tonic-gate case PT_SUNWSTACK: 3787c478bd9Sstevel@tonic-gate args->stk_prot = PROT_USER; 3797c478bd9Sstevel@tonic-gate if (phdrp->p_flags & PF_R) 3807c478bd9Sstevel@tonic-gate args->stk_prot |= PROT_READ; 3817c478bd9Sstevel@tonic-gate if (phdrp->p_flags & PF_W) 3827c478bd9Sstevel@tonic-gate args->stk_prot |= PROT_WRITE; 3837c478bd9Sstevel@tonic-gate if (phdrp->p_flags & PF_X) 3847c478bd9Sstevel@tonic-gate args->stk_prot |= PROT_EXEC; 3857c478bd9Sstevel@tonic-gate break; 3867c478bd9Sstevel@tonic-gate case PT_LOAD: 3877c478bd9Sstevel@tonic-gate dataphdrp = phdrp; 3887c478bd9Sstevel@tonic-gate break; 389a0de58d6SRoger A. Faulkner case PT_SUNWCAP: 390a0de58d6SRoger A. Faulkner capphdr = phdrp; 391a0de58d6SRoger A. Faulkner break; 3927c478bd9Sstevel@tonic-gate } 3937c478bd9Sstevel@tonic-gate phdrp = (Phdr *)((caddr_t)phdrp + hsize); 3947c478bd9Sstevel@tonic-gate } 3957c478bd9Sstevel@tonic-gate 3967c478bd9Sstevel@tonic-gate if (ehdrp->e_type != ET_EXEC) { 3977c478bd9Sstevel@tonic-gate dataphdrp = NULL; 3987c478bd9Sstevel@tonic-gate hasauxv = 1; 3997c478bd9Sstevel@tonic-gate } 4007c478bd9Sstevel@tonic-gate 4017c478bd9Sstevel@tonic-gate /* Copy BSS permissions to args->dat_prot */ 4027c478bd9Sstevel@tonic-gate if (dataphdrp != NULL) { 4037c478bd9Sstevel@tonic-gate args->dat_prot = PROT_USER; 4047c478bd9Sstevel@tonic-gate if (dataphdrp->p_flags & PF_R) 4057c478bd9Sstevel@tonic-gate args->dat_prot |= PROT_READ; 4067c478bd9Sstevel@tonic-gate if (dataphdrp->p_flags & PF_W) 4077c478bd9Sstevel@tonic-gate args->dat_prot |= PROT_WRITE; 4087c478bd9Sstevel@tonic-gate if (dataphdrp->p_flags & PF_X) 4097c478bd9Sstevel@tonic-gate args->dat_prot |= PROT_EXEC; 4107c478bd9Sstevel@tonic-gate } 4117c478bd9Sstevel@tonic-gate 4127c478bd9Sstevel@tonic-gate /* 4137c478bd9Sstevel@tonic-gate * If a auxvector will be required - reserve the space for 4147c478bd9Sstevel@tonic-gate * it now. This may be increased by exec_args if there are 4157c478bd9Sstevel@tonic-gate * ISA-specific types (included in __KERN_NAUXV_IMPL). 4167c478bd9Sstevel@tonic-gate */ 4177c478bd9Sstevel@tonic-gate if (hasauxv) { 4187c478bd9Sstevel@tonic-gate /* 4197c478bd9Sstevel@tonic-gate * If a AUX vector is being built - the base AUX 4207c478bd9Sstevel@tonic-gate * entries are: 4217c478bd9Sstevel@tonic-gate * 4227c478bd9Sstevel@tonic-gate * AT_BASE 4237c478bd9Sstevel@tonic-gate * AT_FLAGS 4247c478bd9Sstevel@tonic-gate * AT_PAGESZ 425386e9c9eSJerry Jelinek * AT_SUN_AUXFLAGS 4267c478bd9Sstevel@tonic-gate * AT_SUN_HWCAP 427ebb8ac07SRobert Mustacchi * AT_SUN_HWCAP2 428386e9c9eSJerry Jelinek * AT_SUN_PLATFORM (added in stk_copyout) 429386e9c9eSJerry Jelinek * AT_SUN_EXECNAME (added in stk_copyout) 4307c478bd9Sstevel@tonic-gate * AT_NULL 4317c478bd9Sstevel@tonic-gate * 432ebb8ac07SRobert Mustacchi * total == 9 4337c478bd9Sstevel@tonic-gate */ 4347c478bd9Sstevel@tonic-gate if (hasdy && hasu) { 4357c478bd9Sstevel@tonic-gate /* 4367c478bd9Sstevel@tonic-gate * Has PT_INTERP & PT_PHDR - the auxvectors that 4377c478bd9Sstevel@tonic-gate * will be built are: 4387c478bd9Sstevel@tonic-gate * 4397c478bd9Sstevel@tonic-gate * AT_PHDR 4407c478bd9Sstevel@tonic-gate * AT_PHENT 4417c478bd9Sstevel@tonic-gate * AT_PHNUM 4427c478bd9Sstevel@tonic-gate * AT_ENTRY 4437c478bd9Sstevel@tonic-gate * AT_LDDATA 4447c478bd9Sstevel@tonic-gate * 4457c478bd9Sstevel@tonic-gate * total = 5 4467c478bd9Sstevel@tonic-gate */ 447ebb8ac07SRobert Mustacchi args->auxsize = (9 + 5) * sizeof (aux_entry_t); 4487c478bd9Sstevel@tonic-gate } else if (hasdy) { 4497c478bd9Sstevel@tonic-gate /* 4507c478bd9Sstevel@tonic-gate * Has PT_INTERP but no PT_PHDR 4517c478bd9Sstevel@tonic-gate * 4527c478bd9Sstevel@tonic-gate * AT_EXECFD 4537c478bd9Sstevel@tonic-gate * AT_LDDATA 4547c478bd9Sstevel@tonic-gate * 4557c478bd9Sstevel@tonic-gate * total = 2 4567c478bd9Sstevel@tonic-gate */ 457ebb8ac07SRobert Mustacchi args->auxsize = (9 + 2) * sizeof (aux_entry_t); 4587c478bd9Sstevel@tonic-gate } else { 459ebb8ac07SRobert Mustacchi args->auxsize = 9 * sizeof (aux_entry_t); 4607c478bd9Sstevel@tonic-gate } 461a0de58d6SRoger A. Faulkner } else { 4627c478bd9Sstevel@tonic-gate args->auxsize = 0; 463a0de58d6SRoger A. Faulkner } 4647c478bd9Sstevel@tonic-gate 4659acbbeafSnn35248 /* 4669acbbeafSnn35248 * If this binary is using an emulator, we need to add an 4679acbbeafSnn35248 * AT_SUN_EMULATOR aux entry. 4689acbbeafSnn35248 */ 4699acbbeafSnn35248 if (args->emulator != NULL) 4709acbbeafSnn35248 args->auxsize += sizeof (aux_entry_t); 4719acbbeafSnn35248 472*263f549eSPatrick Mooney /* 473*263f549eSPatrick Mooney * On supported kernels (x86_64) make room in the auxv for the 474*263f549eSPatrick Mooney * AT_SUN_COMMPAGE entry. This will go unpopulated on i86xpv systems 475*263f549eSPatrick Mooney * which do not provide such functionality. 476*263f549eSPatrick Mooney */ 477*263f549eSPatrick Mooney #if defined(__amd64) 478*263f549eSPatrick Mooney args->auxsize += sizeof (aux_entry_t); 479*263f549eSPatrick Mooney #endif /* defined(__amd64) */ 480*263f549eSPatrick Mooney 4819acbbeafSnn35248 if ((brand_action != EBA_NATIVE) && (PROC_IS_BRANDED(p))) { 4829acbbeafSnn35248 branded = 1; 4839acbbeafSnn35248 /* 48407678296Ssl108498 * We will be adding 4 entries to the aux vectors. One for 48507678296Ssl108498 * the the brandname and 3 for the brand specific aux vectors. 4869acbbeafSnn35248 */ 48707678296Ssl108498 args->auxsize += 4 * sizeof (aux_entry_t); 4889acbbeafSnn35248 } 4899acbbeafSnn35248 490a0de58d6SRoger A. Faulkner /* Hardware/Software capabilities */ 491a0de58d6SRoger A. Faulkner if (capphdr != NULL && 492a0de58d6SRoger A. Faulkner (capsize = capphdr->p_filesz) > 0 && 493a0de58d6SRoger A. Faulkner capsize <= 16 * sizeof (*cap)) { 494a0de58d6SRoger A. Faulkner int ncaps = capsize / sizeof (*cap); 495a0de58d6SRoger A. Faulkner Cap *cp; 496a0de58d6SRoger A. Faulkner 497a0de58d6SRoger A. Faulkner cap = kmem_alloc(capsize, KM_SLEEP); 498a0de58d6SRoger A. Faulkner if ((error = vn_rdwr(UIO_READ, vp, (caddr_t)cap, 499a0de58d6SRoger A. Faulkner capsize, (offset_t)capphdr->p_offset, 500a0de58d6SRoger A. Faulkner UIO_SYSSPACE, 0, (rlim64_t)0, CRED(), &resid)) != 0) { 501a0de58d6SRoger A. Faulkner uprintf("%s: Cannot read capabilities section\n", 502a0de58d6SRoger A. Faulkner exec_file); 503a0de58d6SRoger A. Faulkner goto out; 504a0de58d6SRoger A. Faulkner } 505a0de58d6SRoger A. Faulkner for (cp = cap; cp < cap + ncaps; cp++) { 506a0de58d6SRoger A. Faulkner if (cp->c_tag == CA_SUNW_SF_1 && 507a0de58d6SRoger A. Faulkner (cp->c_un.c_val & SF1_SUNW_ADDR32)) { 508a0de58d6SRoger A. Faulkner if (args->to_model == DATAMODEL_LP64) 509a0de58d6SRoger A. Faulkner args->addr32 = 1; 510a0de58d6SRoger A. Faulkner break; 511a0de58d6SRoger A. Faulkner } 512a0de58d6SRoger A. Faulkner } 513a0de58d6SRoger A. Faulkner } 514a0de58d6SRoger A. Faulkner 5157c478bd9Sstevel@tonic-gate aux = bigwad->elfargs; 5167c478bd9Sstevel@tonic-gate /* 5177c478bd9Sstevel@tonic-gate * Move args to the user's stack. 518386e9c9eSJerry Jelinek * This can fill in the AT_SUN_PLATFORM and AT_SUN_EXECNAME aux entries. 5197c478bd9Sstevel@tonic-gate */ 5207c478bd9Sstevel@tonic-gate if ((error = exec_args(uap, args, idatap, (void **)&aux)) != 0) { 5217c478bd9Sstevel@tonic-gate if (error == -1) { 5227c478bd9Sstevel@tonic-gate error = ENOEXEC; 5237c478bd9Sstevel@tonic-gate goto bad; 5247c478bd9Sstevel@tonic-gate } 5257c478bd9Sstevel@tonic-gate goto out; 5267c478bd9Sstevel@tonic-gate } 5279acbbeafSnn35248 /* we're single threaded after this point */ 5287c478bd9Sstevel@tonic-gate 5297c478bd9Sstevel@tonic-gate /* 5307c478bd9Sstevel@tonic-gate * If this is an ET_DYN executable (shared object), 5317c478bd9Sstevel@tonic-gate * determine its memory size so that mapelfexec() can load it. 5327c478bd9Sstevel@tonic-gate */ 5337c478bd9Sstevel@tonic-gate if (ehdrp->e_type == ET_DYN) 53430da1432Sahl len = elfsize(ehdrp, nphdrs, phdrbase, NULL); 5357c478bd9Sstevel@tonic-gate else 5367c478bd9Sstevel@tonic-gate len = 0; 5377c478bd9Sstevel@tonic-gate 5387c478bd9Sstevel@tonic-gate dtrphdr = NULL; 5397c478bd9Sstevel@tonic-gate 54030da1432Sahl if ((error = mapelfexec(vp, ehdrp, nphdrs, phdrbase, &uphdr, &dyphdr, 5419acbbeafSnn35248 &stphdr, &dtrphdr, dataphdrp, &bssbase, &brkbase, &voffset, NULL, 5429acbbeafSnn35248 len, execsz, &brksize)) != 0) 5437c478bd9Sstevel@tonic-gate goto bad; 5447c478bd9Sstevel@tonic-gate 5457c478bd9Sstevel@tonic-gate if (uphdr != NULL && dyphdr == NULL) 5467c478bd9Sstevel@tonic-gate goto bad; 5477c478bd9Sstevel@tonic-gate 5487c478bd9Sstevel@tonic-gate if (dtrphdr != NULL && dtrace_safe_phdr(dtrphdr, args, voffset) != 0) { 5497c478bd9Sstevel@tonic-gate uprintf("%s: Bad DTrace phdr in %s\n", exec_file, exec_file); 5507c478bd9Sstevel@tonic-gate goto bad; 5517c478bd9Sstevel@tonic-gate } 5527c478bd9Sstevel@tonic-gate 5537c478bd9Sstevel@tonic-gate if (dyphdr != NULL) { 5547c478bd9Sstevel@tonic-gate size_t len; 5557c478bd9Sstevel@tonic-gate uintptr_t lddata; 5567c478bd9Sstevel@tonic-gate char *p; 5577c478bd9Sstevel@tonic-gate struct vnode *nvp; 5587c478bd9Sstevel@tonic-gate 5597c478bd9Sstevel@tonic-gate dlnsize = dyphdr->p_filesz; 5607c478bd9Sstevel@tonic-gate 5617c478bd9Sstevel@tonic-gate if (dlnsize > MAXPATHLEN || dlnsize <= 0) 5627c478bd9Sstevel@tonic-gate goto bad; 5637c478bd9Sstevel@tonic-gate 5647c478bd9Sstevel@tonic-gate /* 5657c478bd9Sstevel@tonic-gate * Read in "interpreter" pathname. 5667c478bd9Sstevel@tonic-gate */ 5677c478bd9Sstevel@tonic-gate if ((error = vn_rdwr(UIO_READ, vp, dlnp, dyphdr->p_filesz, 5687c478bd9Sstevel@tonic-gate (offset_t)dyphdr->p_offset, UIO_SYSSPACE, 0, (rlim64_t)0, 5697c478bd9Sstevel@tonic-gate CRED(), &resid)) != 0) { 5707c478bd9Sstevel@tonic-gate uprintf("%s: Cannot obtain interpreter pathname\n", 5717c478bd9Sstevel@tonic-gate exec_file); 5727c478bd9Sstevel@tonic-gate goto bad; 5737c478bd9Sstevel@tonic-gate } 5747c478bd9Sstevel@tonic-gate 5757c478bd9Sstevel@tonic-gate if (resid != 0 || dlnp[dlnsize - 1] != '\0') 5767c478bd9Sstevel@tonic-gate goto bad; 5777c478bd9Sstevel@tonic-gate 5787c478bd9Sstevel@tonic-gate /* 5797c478bd9Sstevel@tonic-gate * Search for '$ORIGIN' token in interpreter path. 5807c478bd9Sstevel@tonic-gate * If found, expand it. 5817c478bd9Sstevel@tonic-gate */ 5827c478bd9Sstevel@tonic-gate for (p = dlnp; p = strchr(p, '$'); ) { 5837c478bd9Sstevel@tonic-gate uint_t len, curlen; 5847c478bd9Sstevel@tonic-gate char *_ptr; 5857c478bd9Sstevel@tonic-gate 5867c478bd9Sstevel@tonic-gate if (strncmp(++p, ORIGIN_STR, ORIGIN_STR_SIZE)) 5877c478bd9Sstevel@tonic-gate continue; 5887c478bd9Sstevel@tonic-gate 5897c478bd9Sstevel@tonic-gate curlen = 0; 5907c478bd9Sstevel@tonic-gate len = p - dlnp - 1; 5917c478bd9Sstevel@tonic-gate if (len) { 5927c478bd9Sstevel@tonic-gate bcopy(dlnp, pathbufp, len); 5937c478bd9Sstevel@tonic-gate curlen += len; 5947c478bd9Sstevel@tonic-gate } 5957c478bd9Sstevel@tonic-gate if (_ptr = strrchr(args->pathname, '/')) { 5967c478bd9Sstevel@tonic-gate len = _ptr - args->pathname; 5977c478bd9Sstevel@tonic-gate if ((curlen + len) > MAXPATHLEN) 5987c478bd9Sstevel@tonic-gate break; 5997c478bd9Sstevel@tonic-gate 6007c478bd9Sstevel@tonic-gate bcopy(args->pathname, &pathbufp[curlen], len); 6017c478bd9Sstevel@tonic-gate curlen += len; 6027c478bd9Sstevel@tonic-gate } else { 6037c478bd9Sstevel@tonic-gate /* 6047c478bd9Sstevel@tonic-gate * executable is a basename found in the 6057c478bd9Sstevel@tonic-gate * current directory. So - just substitue 6067c478bd9Sstevel@tonic-gate * '.' for ORIGIN. 6077c478bd9Sstevel@tonic-gate */ 6087c478bd9Sstevel@tonic-gate pathbufp[curlen] = '.'; 6097c478bd9Sstevel@tonic-gate curlen++; 6107c478bd9Sstevel@tonic-gate } 6117c478bd9Sstevel@tonic-gate p += ORIGIN_STR_SIZE; 6127c478bd9Sstevel@tonic-gate len = strlen(p); 6137c478bd9Sstevel@tonic-gate 6147c478bd9Sstevel@tonic-gate if ((curlen + len) > MAXPATHLEN) 6157c478bd9Sstevel@tonic-gate break; 6167c478bd9Sstevel@tonic-gate bcopy(p, &pathbufp[curlen], len); 6177c478bd9Sstevel@tonic-gate curlen += len; 6187c478bd9Sstevel@tonic-gate pathbufp[curlen++] = '\0'; 6197c478bd9Sstevel@tonic-gate bcopy(pathbufp, dlnp, curlen); 6207c478bd9Sstevel@tonic-gate } 6217c478bd9Sstevel@tonic-gate 6227c478bd9Sstevel@tonic-gate /* 6237c478bd9Sstevel@tonic-gate * /usr/lib/ld.so.1 is known to be a symlink to /lib/ld.so.1 6247c478bd9Sstevel@tonic-gate * (and /usr/lib/64/ld.so.1 is a symlink to /lib/64/ld.so.1). 6257c478bd9Sstevel@tonic-gate * Just in case /usr is not mounted, change it now. 6267c478bd9Sstevel@tonic-gate */ 6277c478bd9Sstevel@tonic-gate if (strcmp(dlnp, USR_LIB_RTLD) == 0) 6287c478bd9Sstevel@tonic-gate dlnp += 4; 6297c478bd9Sstevel@tonic-gate error = lookupname(dlnp, UIO_SYSSPACE, FOLLOW, NULLVPP, &nvp); 6307c478bd9Sstevel@tonic-gate if (error && dlnp != bigwad->dl_name) { 6317c478bd9Sstevel@tonic-gate /* new kernel, old user-level */ 6327c478bd9Sstevel@tonic-gate error = lookupname(dlnp -= 4, UIO_SYSSPACE, FOLLOW, 6337c478bd9Sstevel@tonic-gate NULLVPP, &nvp); 6347c478bd9Sstevel@tonic-gate } 6357c478bd9Sstevel@tonic-gate if (error) { 6367c478bd9Sstevel@tonic-gate uprintf("%s: Cannot find %s\n", exec_file, dlnp); 6377c478bd9Sstevel@tonic-gate goto bad; 6387c478bd9Sstevel@tonic-gate } 6397c478bd9Sstevel@tonic-gate 6407c478bd9Sstevel@tonic-gate /* 6417c478bd9Sstevel@tonic-gate * Setup the "aux" vector. 6427c478bd9Sstevel@tonic-gate */ 6437c478bd9Sstevel@tonic-gate if (uphdr) { 6447c478bd9Sstevel@tonic-gate if (ehdrp->e_type == ET_DYN) { 6457c478bd9Sstevel@tonic-gate /* don't use the first page */ 6467c478bd9Sstevel@tonic-gate bigwad->exenv.ex_brkbase = (caddr_t)PAGESIZE; 6477c478bd9Sstevel@tonic-gate bigwad->exenv.ex_bssbase = (caddr_t)PAGESIZE; 6487c478bd9Sstevel@tonic-gate } else { 6497c478bd9Sstevel@tonic-gate bigwad->exenv.ex_bssbase = bssbase; 6507c478bd9Sstevel@tonic-gate bigwad->exenv.ex_brkbase = brkbase; 6517c478bd9Sstevel@tonic-gate } 6527c478bd9Sstevel@tonic-gate bigwad->exenv.ex_brksize = brksize; 6537c478bd9Sstevel@tonic-gate bigwad->exenv.ex_magic = elfmagic; 6547c478bd9Sstevel@tonic-gate bigwad->exenv.ex_vp = vp; 6557c478bd9Sstevel@tonic-gate setexecenv(&bigwad->exenv); 6567c478bd9Sstevel@tonic-gate 6577c478bd9Sstevel@tonic-gate ADDAUX(aux, AT_PHDR, uphdr->p_vaddr + voffset) 6587c478bd9Sstevel@tonic-gate ADDAUX(aux, AT_PHENT, ehdrp->e_phentsize) 65930da1432Sahl ADDAUX(aux, AT_PHNUM, nphdrs) 6607c478bd9Sstevel@tonic-gate ADDAUX(aux, AT_ENTRY, ehdrp->e_entry + voffset) 6617c478bd9Sstevel@tonic-gate } else { 6627c478bd9Sstevel@tonic-gate if ((error = execopen(&vp, &fd)) != 0) { 6637c478bd9Sstevel@tonic-gate VN_RELE(nvp); 6647c478bd9Sstevel@tonic-gate goto bad; 6657c478bd9Sstevel@tonic-gate } 6667c478bd9Sstevel@tonic-gate 6677c478bd9Sstevel@tonic-gate ADDAUX(aux, AT_EXECFD, fd) 6687c478bd9Sstevel@tonic-gate } 6697c478bd9Sstevel@tonic-gate 6707c478bd9Sstevel@tonic-gate if ((error = execpermissions(nvp, &bigwad->vattr, args)) != 0) { 6717c478bd9Sstevel@tonic-gate VN_RELE(nvp); 6727c478bd9Sstevel@tonic-gate uprintf("%s: Cannot execute %s\n", exec_file, dlnp); 6737c478bd9Sstevel@tonic-gate goto bad; 6747c478bd9Sstevel@tonic-gate } 6757c478bd9Sstevel@tonic-gate 6767c478bd9Sstevel@tonic-gate /* 6777c478bd9Sstevel@tonic-gate * Now obtain the ELF header along with the entire program 6787c478bd9Sstevel@tonic-gate * header contained in "nvp". 6797c478bd9Sstevel@tonic-gate */ 6807c478bd9Sstevel@tonic-gate kmem_free(phdrbase, phdrsize); 6817c478bd9Sstevel@tonic-gate phdrbase = NULL; 68230da1432Sahl if ((error = getelfhead(nvp, CRED(), ehdrp, &nshdrs, 68330da1432Sahl &shstrndx, &nphdrs)) != 0 || 68430da1432Sahl (error = getelfphdr(nvp, CRED(), ehdrp, nphdrs, &phdrbase, 6857c478bd9Sstevel@tonic-gate &phdrsize)) != 0) { 6867c478bd9Sstevel@tonic-gate VN_RELE(nvp); 6877c478bd9Sstevel@tonic-gate uprintf("%s: Cannot read %s\n", exec_file, dlnp); 6887c478bd9Sstevel@tonic-gate goto bad; 6897c478bd9Sstevel@tonic-gate } 6907c478bd9Sstevel@tonic-gate 6917c478bd9Sstevel@tonic-gate /* 6927c478bd9Sstevel@tonic-gate * Determine memory size of the "interpreter's" loadable 6937c478bd9Sstevel@tonic-gate * sections. This size is then used to obtain the virtual 6947c478bd9Sstevel@tonic-gate * address of a hole, in the user's address space, large 6957c478bd9Sstevel@tonic-gate * enough to map the "interpreter". 6967c478bd9Sstevel@tonic-gate */ 69730da1432Sahl if ((len = elfsize(ehdrp, nphdrs, phdrbase, &lddata)) == 0) { 6987c478bd9Sstevel@tonic-gate VN_RELE(nvp); 6997c478bd9Sstevel@tonic-gate uprintf("%s: Nothing to load in %s\n", exec_file, dlnp); 7007c478bd9Sstevel@tonic-gate goto bad; 7017c478bd9Sstevel@tonic-gate } 7027c478bd9Sstevel@tonic-gate 7037c478bd9Sstevel@tonic-gate dtrphdr = NULL; 7047c478bd9Sstevel@tonic-gate 70530da1432Sahl error = mapelfexec(nvp, ehdrp, nphdrs, phdrbase, &junk, &junk, 7069acbbeafSnn35248 &junk, &dtrphdr, NULL, NULL, NULL, &voffset, NULL, len, 7079acbbeafSnn35248 execsz, NULL); 7087c478bd9Sstevel@tonic-gate if (error || junk != NULL) { 7097c478bd9Sstevel@tonic-gate VN_RELE(nvp); 7107c478bd9Sstevel@tonic-gate uprintf("%s: Cannot map %s\n", exec_file, dlnp); 7117c478bd9Sstevel@tonic-gate goto bad; 7127c478bd9Sstevel@tonic-gate } 7137c478bd9Sstevel@tonic-gate 7147c478bd9Sstevel@tonic-gate /* 7157c478bd9Sstevel@tonic-gate * We use the DTrace program header to initialize the 7167c478bd9Sstevel@tonic-gate * architecture-specific user per-LWP location. The dtrace 7177c478bd9Sstevel@tonic-gate * fasttrap provider requires ready access to per-LWP scratch 7187c478bd9Sstevel@tonic-gate * space. We assume that there is only one such program header 7197c478bd9Sstevel@tonic-gate * in the interpreter. 7207c478bd9Sstevel@tonic-gate */ 7217c478bd9Sstevel@tonic-gate if (dtrphdr != NULL && 7227c478bd9Sstevel@tonic-gate dtrace_safe_phdr(dtrphdr, args, voffset) != 0) { 7237c478bd9Sstevel@tonic-gate VN_RELE(nvp); 7247c478bd9Sstevel@tonic-gate uprintf("%s: Bad DTrace phdr in %s\n", exec_file, dlnp); 7257c478bd9Sstevel@tonic-gate goto bad; 7267c478bd9Sstevel@tonic-gate } 7277c478bd9Sstevel@tonic-gate 7287c478bd9Sstevel@tonic-gate VN_RELE(nvp); 7297c478bd9Sstevel@tonic-gate ADDAUX(aux, AT_SUN_LDDATA, voffset + lddata) 7307c478bd9Sstevel@tonic-gate } 7317c478bd9Sstevel@tonic-gate 7327c478bd9Sstevel@tonic-gate if (hasauxv) { 7337c478bd9Sstevel@tonic-gate int auxf = AF_SUN_HWCAPVERIFY; 734*263f549eSPatrick Mooney 7357c478bd9Sstevel@tonic-gate /* 736386e9c9eSJerry Jelinek * Note: AT_SUN_PLATFORM and AT_SUN_EXECNAME were filled in via 737386e9c9eSJerry Jelinek * exec_args() 7387c478bd9Sstevel@tonic-gate */ 7397c478bd9Sstevel@tonic-gate ADDAUX(aux, AT_BASE, voffset) 7407c478bd9Sstevel@tonic-gate ADDAUX(aux, AT_FLAGS, at_flags) 7417c478bd9Sstevel@tonic-gate ADDAUX(aux, AT_PAGESZ, PAGESIZE) 7427c478bd9Sstevel@tonic-gate /* 7437c478bd9Sstevel@tonic-gate * Linker flags. (security) 7447c478bd9Sstevel@tonic-gate * p_flag not yet set at this time. 7457c478bd9Sstevel@tonic-gate * We rely on gexec() to provide us with the information. 746cc4b03b5Scasper * If the application is set-uid but this is not reflected 747cc4b03b5Scasper * in a mismatch between real/effective uids/gids, then 748cc4b03b5Scasper * don't treat this as a set-uid exec. So we care about 749cc4b03b5Scasper * the EXECSETID_UGIDS flag but not the ...SETID flag. 7507c478bd9Sstevel@tonic-gate */ 751b71d513aSedp if ((setid &= ~EXECSETID_SETID) != 0) 752b71d513aSedp auxf |= AF_SUN_SETUGID; 7531022fd2aS 7541022fd2aS /* 7551022fd2aS * If we're running a native process from within a branded 7561022fd2aS * zone under pfexec then we clear the AF_SUN_SETUGID flag so 7571022fd2aS * that the native ld.so.1 is able to link with the native 7581022fd2aS * libraries instead of using the brand libraries that are 7591022fd2aS * installed in the zone. We only do this for processes 7601022fd2aS * which we trust because we see they are already running 7611022fd2aS * under pfexec (where uid != euid). This prevents a 7621022fd2aS * malicious user within the zone from crafting a wrapper to 7631022fd2aS * run native suid commands with unsecure libraries interposed. 7641022fd2aS */ 7651022fd2aS if ((brand_action == EBA_NATIVE) && (PROC_IS_BRANDED(p) && 7661022fd2aS (setid &= ~EXECSETID_SETID) != 0)) 7671022fd2aS auxf &= ~AF_SUN_SETUGID; 7681022fd2aS 769b71d513aSedp /* 770b71d513aSedp * Record the user addr of the auxflags aux vector entry 771b71d513aSedp * since brands may optionally want to manipulate this field. 772b71d513aSedp */ 773b71d513aSedp args->auxp_auxflags = 774b71d513aSedp (char *)((char *)args->stackend + 775b71d513aSedp ((char *)&aux->a_type - 776b71d513aSedp (char *)bigwad->elfargs)); 777b71d513aSedp ADDAUX(aux, AT_SUN_AUXFLAGS, auxf); 7787c478bd9Sstevel@tonic-gate /* 7797c478bd9Sstevel@tonic-gate * Hardware capability flag word (performance hints) 7807c478bd9Sstevel@tonic-gate * Used for choosing faster library routines. 7817c478bd9Sstevel@tonic-gate * (Potentially different between 32-bit and 64-bit ABIs) 7827c478bd9Sstevel@tonic-gate */ 7837c478bd9Sstevel@tonic-gate #if defined(_LP64) 784ebb8ac07SRobert Mustacchi if (args->to_model == DATAMODEL_NATIVE) { 7857c478bd9Sstevel@tonic-gate ADDAUX(aux, AT_SUN_HWCAP, auxv_hwcap) 786ebb8ac07SRobert Mustacchi ADDAUX(aux, AT_SUN_HWCAP2, auxv_hwcap_2) 787ebb8ac07SRobert Mustacchi } else { 7887c478bd9Sstevel@tonic-gate ADDAUX(aux, AT_SUN_HWCAP, auxv_hwcap32) 789ebb8ac07SRobert Mustacchi ADDAUX(aux, AT_SUN_HWCAP2, auxv_hwcap32_2) 790ebb8ac07SRobert Mustacchi } 7917c478bd9Sstevel@tonic-gate #else 7927c478bd9Sstevel@tonic-gate ADDAUX(aux, AT_SUN_HWCAP, auxv_hwcap) 793ebb8ac07SRobert Mustacchi ADDAUX(aux, AT_SUN_HWCAP2, auxv_hwcap_2) 7947c478bd9Sstevel@tonic-gate #endif 7959acbbeafSnn35248 if (branded) { 7969acbbeafSnn35248 /* 79707678296Ssl108498 * Reserve space for the brand-private aux vectors, 7989acbbeafSnn35248 * and record the user addr of that space. 7999acbbeafSnn35248 */ 80007678296Ssl108498 args->auxp_brand = 801396a100bSedp (char *)((char *)args->stackend + 802396a100bSedp ((char *)&aux->a_type - 803396a100bSedp (char *)bigwad->elfargs)); 80407678296Ssl108498 ADDAUX(aux, AT_SUN_BRAND_AUX1, 0) 80507678296Ssl108498 ADDAUX(aux, AT_SUN_BRAND_AUX2, 0) 80607678296Ssl108498 ADDAUX(aux, AT_SUN_BRAND_AUX3, 0) 8079acbbeafSnn35248 } 8089acbbeafSnn35248 809*263f549eSPatrick Mooney /* 810*263f549eSPatrick Mooney * Add the comm page auxv entry, mapping it in if needed. 811*263f549eSPatrick Mooney */ 812*263f549eSPatrick Mooney #if defined(__amd64) 813*263f549eSPatrick Mooney if (args->commpage != NULL || 814*263f549eSPatrick Mooney (args->commpage = (uintptr_t)comm_page_mapin()) != NULL) { 815*263f549eSPatrick Mooney ADDAUX(aux, AT_SUN_COMMPAGE, args->commpage) 816*263f549eSPatrick Mooney } else { 817*263f549eSPatrick Mooney /* 818*263f549eSPatrick Mooney * If the comm page cannot be mapped, pad out the auxv 819*263f549eSPatrick Mooney * to satisfy later size checks. 820*263f549eSPatrick Mooney */ 821*263f549eSPatrick Mooney ADDAUX(aux, AT_NULL, 0) 822*263f549eSPatrick Mooney } 823*263f549eSPatrick Mooney #endif /* defined(__amd64) */ 824*263f549eSPatrick Mooney 8257c478bd9Sstevel@tonic-gate ADDAUX(aux, AT_NULL, 0) 8267c478bd9Sstevel@tonic-gate postfixsize = (char *)aux - (char *)bigwad->elfargs; 827386e9c9eSJerry Jelinek 828386e9c9eSJerry Jelinek /* 829386e9c9eSJerry Jelinek * We make assumptions above when we determine how many aux 830386e9c9eSJerry Jelinek * vector entries we will be adding. However, if we have an 831386e9c9eSJerry Jelinek * invalid elf file, it is possible that mapelfexec might 832386e9c9eSJerry Jelinek * behave differently (but not return an error), in which case 833386e9c9eSJerry Jelinek * the number of aux entries we actually add will be different. 834386e9c9eSJerry Jelinek * We detect that now and error out. 835386e9c9eSJerry Jelinek */ 836386e9c9eSJerry Jelinek if (postfixsize != args->auxsize) { 837386e9c9eSJerry Jelinek DTRACE_PROBE2(elfexec_badaux, int, postfixsize, 838386e9c9eSJerry Jelinek int, args->auxsize); 839386e9c9eSJerry Jelinek goto bad; 840386e9c9eSJerry Jelinek } 8417c478bd9Sstevel@tonic-gate ASSERT(postfixsize <= __KERN_NAUXV_IMPL * sizeof (aux_entry_t)); 8427c478bd9Sstevel@tonic-gate } 8437c478bd9Sstevel@tonic-gate 8447c478bd9Sstevel@tonic-gate /* 8457c478bd9Sstevel@tonic-gate * For the 64-bit kernel, the limit is big enough that rounding it up 8467c478bd9Sstevel@tonic-gate * to a page can overflow the 64-bit limit, so we check for btopr() 8477c478bd9Sstevel@tonic-gate * overflowing here by comparing it with the unrounded limit in pages. 8487c478bd9Sstevel@tonic-gate * If it hasn't overflowed, compare the exec size with the rounded up 8497c478bd9Sstevel@tonic-gate * limit in pages. Otherwise, just compare with the unrounded limit. 8507c478bd9Sstevel@tonic-gate */ 8517c478bd9Sstevel@tonic-gate limit = btop(p->p_vmem_ctl); 8527c478bd9Sstevel@tonic-gate roundlimit = btopr(p->p_vmem_ctl); 8537c478bd9Sstevel@tonic-gate if ((roundlimit > limit && *execsz > roundlimit) || 8547c478bd9Sstevel@tonic-gate (roundlimit < limit && *execsz > limit)) { 8557c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock); 8567c478bd9Sstevel@tonic-gate (void) rctl_action(rctlproc_legacy[RLIMIT_VMEM], p->p_rctls, p, 8577c478bd9Sstevel@tonic-gate RCA_SAFE); 8587c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 8597c478bd9Sstevel@tonic-gate error = ENOMEM; 8607c478bd9Sstevel@tonic-gate goto bad; 8617c478bd9Sstevel@tonic-gate } 8627c478bd9Sstevel@tonic-gate 8637c478bd9Sstevel@tonic-gate bzero(up->u_auxv, sizeof (up->u_auxv)); 864*263f549eSPatrick Mooney up->u_commpagep = args->commpage; 8657c478bd9Sstevel@tonic-gate if (postfixsize) { 8667c478bd9Sstevel@tonic-gate int num_auxv; 8677c478bd9Sstevel@tonic-gate 8687c478bd9Sstevel@tonic-gate /* 8697c478bd9Sstevel@tonic-gate * Copy the aux vector to the user stack. 8707c478bd9Sstevel@tonic-gate */ 8717c478bd9Sstevel@tonic-gate error = execpoststack(args, bigwad->elfargs, postfixsize); 8727c478bd9Sstevel@tonic-gate if (error) 8737c478bd9Sstevel@tonic-gate goto bad; 8747c478bd9Sstevel@tonic-gate 8757c478bd9Sstevel@tonic-gate /* 8767c478bd9Sstevel@tonic-gate * Copy auxv to the process's user structure for use by /proc. 8779acbbeafSnn35248 * If this is a branded process, the brand's exec routine will 8789acbbeafSnn35248 * copy it's private entries to the user structure later. It 8799acbbeafSnn35248 * relies on the fact that the blank entries are at the end. 8807c478bd9Sstevel@tonic-gate */ 8817c478bd9Sstevel@tonic-gate num_auxv = postfixsize / sizeof (aux_entry_t); 8827c478bd9Sstevel@tonic-gate ASSERT(num_auxv <= sizeof (up->u_auxv) / sizeof (auxv_t)); 8837c478bd9Sstevel@tonic-gate aux = bigwad->elfargs; 8847c478bd9Sstevel@tonic-gate for (i = 0; i < num_auxv; i++) { 8857c478bd9Sstevel@tonic-gate up->u_auxv[i].a_type = aux[i].a_type; 8867c478bd9Sstevel@tonic-gate up->u_auxv[i].a_un.a_val = (aux_val_t)aux[i].a_un.a_val; 8877c478bd9Sstevel@tonic-gate } 8887c478bd9Sstevel@tonic-gate } 8897c478bd9Sstevel@tonic-gate 8907c478bd9Sstevel@tonic-gate /* 8917c478bd9Sstevel@tonic-gate * Pass back the starting address so we can set the program counter. 8927c478bd9Sstevel@tonic-gate */ 8937c478bd9Sstevel@tonic-gate args->entry = (uintptr_t)(ehdrp->e_entry + voffset); 8947c478bd9Sstevel@tonic-gate 8957c478bd9Sstevel@tonic-gate if (!uphdr) { 8967c478bd9Sstevel@tonic-gate if (ehdrp->e_type == ET_DYN) { 8977c478bd9Sstevel@tonic-gate /* 8987c478bd9Sstevel@tonic-gate * If we are executing a shared library which doesn't 8997c478bd9Sstevel@tonic-gate * have a interpreter (probably ld.so.1) then 9007c478bd9Sstevel@tonic-gate * we don't set the brkbase now. Instead we 9017c478bd9Sstevel@tonic-gate * delay it's setting until the first call 9027c478bd9Sstevel@tonic-gate * via grow.c::brk(). This permits ld.so.1 to 9037c478bd9Sstevel@tonic-gate * initialize brkbase to the tail of the executable it 9047c478bd9Sstevel@tonic-gate * loads (which is where it needs to be). 9057c478bd9Sstevel@tonic-gate */ 9067c478bd9Sstevel@tonic-gate bigwad->exenv.ex_brkbase = (caddr_t)0; 9077c478bd9Sstevel@tonic-gate bigwad->exenv.ex_bssbase = (caddr_t)0; 9087c478bd9Sstevel@tonic-gate bigwad->exenv.ex_brksize = 0; 9097c478bd9Sstevel@tonic-gate } else { 9107c478bd9Sstevel@tonic-gate bigwad->exenv.ex_brkbase = brkbase; 9117c478bd9Sstevel@tonic-gate bigwad->exenv.ex_bssbase = bssbase; 9127c478bd9Sstevel@tonic-gate bigwad->exenv.ex_brksize = brksize; 9137c478bd9Sstevel@tonic-gate } 9147c478bd9Sstevel@tonic-gate bigwad->exenv.ex_magic = elfmagic; 9157c478bd9Sstevel@tonic-gate bigwad->exenv.ex_vp = vp; 9167c478bd9Sstevel@tonic-gate setexecenv(&bigwad->exenv); 9177c478bd9Sstevel@tonic-gate } 9187c478bd9Sstevel@tonic-gate 9197c478bd9Sstevel@tonic-gate ASSERT(error == 0); 9207c478bd9Sstevel@tonic-gate goto out; 9217c478bd9Sstevel@tonic-gate 9227c478bd9Sstevel@tonic-gate bad: 9237c478bd9Sstevel@tonic-gate if (fd != -1) /* did we open the a.out yet */ 9247c478bd9Sstevel@tonic-gate (void) execclose(fd); 9257c478bd9Sstevel@tonic-gate 9267c478bd9Sstevel@tonic-gate psignal(p, SIGKILL); 9277c478bd9Sstevel@tonic-gate 9287c478bd9Sstevel@tonic-gate if (error == 0) 9297c478bd9Sstevel@tonic-gate error = ENOEXEC; 9307c478bd9Sstevel@tonic-gate out: 9317c478bd9Sstevel@tonic-gate if (phdrbase != NULL) 9327c478bd9Sstevel@tonic-gate kmem_free(phdrbase, phdrsize); 933a0de58d6SRoger A. Faulkner if (cap != NULL) 934a0de58d6SRoger A. Faulkner kmem_free(cap, capsize); 9357c478bd9Sstevel@tonic-gate kmem_free(bigwad, sizeof (struct bigwad)); 9367c478bd9Sstevel@tonic-gate return (error); 9377c478bd9Sstevel@tonic-gate } 9387c478bd9Sstevel@tonic-gate 9397c478bd9Sstevel@tonic-gate /* 9407c478bd9Sstevel@tonic-gate * Compute the memory size requirement for the ELF file. 9417c478bd9Sstevel@tonic-gate */ 9427c478bd9Sstevel@tonic-gate static size_t 94330da1432Sahl elfsize(Ehdr *ehdrp, int nphdrs, caddr_t phdrbase, uintptr_t *lddata) 9447c478bd9Sstevel@tonic-gate { 9457c478bd9Sstevel@tonic-gate size_t len; 9467c478bd9Sstevel@tonic-gate Phdr *phdrp = (Phdr *)phdrbase; 9477c478bd9Sstevel@tonic-gate int hsize = ehdrp->e_phentsize; 9487c478bd9Sstevel@tonic-gate int first = 1; 9497c478bd9Sstevel@tonic-gate int dfirst = 1; /* first data segment */ 9507c478bd9Sstevel@tonic-gate uintptr_t loaddr = 0; 9517c478bd9Sstevel@tonic-gate uintptr_t hiaddr = 0; 9527c478bd9Sstevel@tonic-gate uintptr_t lo, hi; 9537c478bd9Sstevel@tonic-gate int i; 9547c478bd9Sstevel@tonic-gate 95530da1432Sahl for (i = nphdrs; i > 0; i--) { 9567c478bd9Sstevel@tonic-gate if (phdrp->p_type == PT_LOAD) { 9577c478bd9Sstevel@tonic-gate lo = phdrp->p_vaddr; 9587c478bd9Sstevel@tonic-gate hi = lo + phdrp->p_memsz; 9597c478bd9Sstevel@tonic-gate if (first) { 9607c478bd9Sstevel@tonic-gate loaddr = lo; 9617c478bd9Sstevel@tonic-gate hiaddr = hi; 9627c478bd9Sstevel@tonic-gate first = 0; 9637c478bd9Sstevel@tonic-gate } else { 9647c478bd9Sstevel@tonic-gate if (loaddr > lo) 9657c478bd9Sstevel@tonic-gate loaddr = lo; 9667c478bd9Sstevel@tonic-gate if (hiaddr < hi) 9677c478bd9Sstevel@tonic-gate hiaddr = hi; 9687c478bd9Sstevel@tonic-gate } 9697c478bd9Sstevel@tonic-gate 9707c478bd9Sstevel@tonic-gate /* 9717c478bd9Sstevel@tonic-gate * save the address of the first data segment 9727c478bd9Sstevel@tonic-gate * of a object - used for the AT_SUNW_LDDATA 9737c478bd9Sstevel@tonic-gate * aux entry. 9747c478bd9Sstevel@tonic-gate */ 9757c478bd9Sstevel@tonic-gate if ((lddata != NULL) && dfirst && 9767c478bd9Sstevel@tonic-gate (phdrp->p_flags & PF_W)) { 9777c478bd9Sstevel@tonic-gate *lddata = lo; 9787c478bd9Sstevel@tonic-gate dfirst = 0; 9797c478bd9Sstevel@tonic-gate } 9807c478bd9Sstevel@tonic-gate } 9817c478bd9Sstevel@tonic-gate phdrp = (Phdr *)((caddr_t)phdrp + hsize); 9827c478bd9Sstevel@tonic-gate } 9837c478bd9Sstevel@tonic-gate 9847c478bd9Sstevel@tonic-gate len = hiaddr - (loaddr & PAGEMASK); 9857c478bd9Sstevel@tonic-gate len = roundup(len, PAGESIZE); 9867c478bd9Sstevel@tonic-gate 9877c478bd9Sstevel@tonic-gate return (len); 9887c478bd9Sstevel@tonic-gate } 9897c478bd9Sstevel@tonic-gate 9907c478bd9Sstevel@tonic-gate /* 9917c478bd9Sstevel@tonic-gate * Read in the ELF header and program header table. 9927c478bd9Sstevel@tonic-gate * SUSV3 requires: 9937c478bd9Sstevel@tonic-gate * ENOEXEC File format is not recognized 9947c478bd9Sstevel@tonic-gate * EINVAL Format recognized but execution not supported 9957c478bd9Sstevel@tonic-gate */ 9967c478bd9Sstevel@tonic-gate static int 99730da1432Sahl getelfhead(vnode_t *vp, cred_t *credp, Ehdr *ehdr, int *nshdrs, int *shstrndx, 99830da1432Sahl int *nphdrs) 9997c478bd9Sstevel@tonic-gate { 10007c478bd9Sstevel@tonic-gate int error; 10017c478bd9Sstevel@tonic-gate ssize_t resid; 10027c478bd9Sstevel@tonic-gate 10037c478bd9Sstevel@tonic-gate /* 10047c478bd9Sstevel@tonic-gate * We got here by the first two bytes in ident, 10057c478bd9Sstevel@tonic-gate * now read the entire ELF header. 10067c478bd9Sstevel@tonic-gate */ 10077c478bd9Sstevel@tonic-gate if ((error = vn_rdwr(UIO_READ, vp, (caddr_t)ehdr, 10087c478bd9Sstevel@tonic-gate sizeof (Ehdr), (offset_t)0, UIO_SYSSPACE, 0, 10097c478bd9Sstevel@tonic-gate (rlim64_t)0, credp, &resid)) != 0) 10107c478bd9Sstevel@tonic-gate return (error); 10117c478bd9Sstevel@tonic-gate 10127c478bd9Sstevel@tonic-gate /* 10137c478bd9Sstevel@tonic-gate * Since a separate version is compiled for handling 32-bit and 10147c478bd9Sstevel@tonic-gate * 64-bit ELF executables on a 64-bit kernel, the 64-bit version 10157c478bd9Sstevel@tonic-gate * doesn't need to be able to deal with 32-bit ELF files. 10167c478bd9Sstevel@tonic-gate */ 10177c478bd9Sstevel@tonic-gate if (resid != 0 || 10187c478bd9Sstevel@tonic-gate ehdr->e_ident[EI_MAG2] != ELFMAG2 || 10197c478bd9Sstevel@tonic-gate ehdr->e_ident[EI_MAG3] != ELFMAG3) 10207c478bd9Sstevel@tonic-gate return (ENOEXEC); 102130da1432Sahl 10227c478bd9Sstevel@tonic-gate if ((ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN) || 10237c478bd9Sstevel@tonic-gate #if defined(_ILP32) || defined(_ELF32_COMPAT) 10247c478bd9Sstevel@tonic-gate ehdr->e_ident[EI_CLASS] != ELFCLASS32 || 10257c478bd9Sstevel@tonic-gate #else 10267c478bd9Sstevel@tonic-gate ehdr->e_ident[EI_CLASS] != ELFCLASS64 || 10277c478bd9Sstevel@tonic-gate #endif 10287c478bd9Sstevel@tonic-gate !elfheadcheck(ehdr->e_ident[EI_DATA], ehdr->e_machine, 10297c478bd9Sstevel@tonic-gate ehdr->e_flags)) 10307c478bd9Sstevel@tonic-gate return (EINVAL); 10317c478bd9Sstevel@tonic-gate 103230da1432Sahl *nshdrs = ehdr->e_shnum; 103330da1432Sahl *shstrndx = ehdr->e_shstrndx; 103430da1432Sahl *nphdrs = ehdr->e_phnum; 103530da1432Sahl 103630da1432Sahl /* 103730da1432Sahl * If e_shnum, e_shstrndx, or e_phnum is its sentinel value, we need 103830da1432Sahl * to read in the section header at index zero to acces the true 103930da1432Sahl * values for those fields. 104030da1432Sahl */ 104130da1432Sahl if ((*nshdrs == 0 && ehdr->e_shoff != 0) || 104230da1432Sahl *shstrndx == SHN_XINDEX || *nphdrs == PN_XNUM) { 104330da1432Sahl Shdr shdr; 104430da1432Sahl 104530da1432Sahl if (ehdr->e_shoff == 0) 104630da1432Sahl return (EINVAL); 104730da1432Sahl 104830da1432Sahl if ((error = vn_rdwr(UIO_READ, vp, (caddr_t)&shdr, 104930da1432Sahl sizeof (shdr), (offset_t)ehdr->e_shoff, UIO_SYSSPACE, 0, 105030da1432Sahl (rlim64_t)0, credp, &resid)) != 0) 105130da1432Sahl return (error); 105230da1432Sahl 105330da1432Sahl if (*nshdrs == 0) 105430da1432Sahl *nshdrs = shdr.sh_size; 105530da1432Sahl if (*shstrndx == SHN_XINDEX) 105630da1432Sahl *shstrndx = shdr.sh_link; 105730da1432Sahl if (*nphdrs == PN_XNUM && shdr.sh_info != 0) 105830da1432Sahl *nphdrs = shdr.sh_info; 105930da1432Sahl } 106030da1432Sahl 10617c478bd9Sstevel@tonic-gate return (0); 10627c478bd9Sstevel@tonic-gate } 10637c478bd9Sstevel@tonic-gate 10647c478bd9Sstevel@tonic-gate #ifdef _ELF32_COMPAT 10657c478bd9Sstevel@tonic-gate extern size_t elf_nphdr_max; 10667c478bd9Sstevel@tonic-gate #else 10677c478bd9Sstevel@tonic-gate size_t elf_nphdr_max = 1000; 10687c478bd9Sstevel@tonic-gate #endif 10697c478bd9Sstevel@tonic-gate 10707c478bd9Sstevel@tonic-gate static int 107130da1432Sahl getelfphdr(vnode_t *vp, cred_t *credp, const Ehdr *ehdr, int nphdrs, 10727c478bd9Sstevel@tonic-gate caddr_t *phbasep, ssize_t *phsizep) 10737c478bd9Sstevel@tonic-gate { 10747c478bd9Sstevel@tonic-gate ssize_t resid, minsize; 10757c478bd9Sstevel@tonic-gate int err; 10767c478bd9Sstevel@tonic-gate 10777c478bd9Sstevel@tonic-gate /* 10787c478bd9Sstevel@tonic-gate * Since we're going to be using e_phentsize to iterate down the 10797c478bd9Sstevel@tonic-gate * array of program headers, it must be 8-byte aligned or else 10807c478bd9Sstevel@tonic-gate * a we might cause a misaligned access. We use all members through 10817c478bd9Sstevel@tonic-gate * p_flags on 32-bit ELF files and p_memsz on 64-bit ELF files so 10827c478bd9Sstevel@tonic-gate * e_phentsize must be at least large enough to include those 10837c478bd9Sstevel@tonic-gate * members. 10847c478bd9Sstevel@tonic-gate */ 10857c478bd9Sstevel@tonic-gate #if !defined(_LP64) || defined(_ELF32_COMPAT) 10867c478bd9Sstevel@tonic-gate minsize = offsetof(Phdr, p_flags) + sizeof (((Phdr *)NULL)->p_flags); 10877c478bd9Sstevel@tonic-gate #else 10887c478bd9Sstevel@tonic-gate minsize = offsetof(Phdr, p_memsz) + sizeof (((Phdr *)NULL)->p_memsz); 10897c478bd9Sstevel@tonic-gate #endif 10907c478bd9Sstevel@tonic-gate if (ehdr->e_phentsize < minsize || (ehdr->e_phentsize & 3)) 10917c478bd9Sstevel@tonic-gate return (EINVAL); 10927c478bd9Sstevel@tonic-gate 109330da1432Sahl *phsizep = nphdrs * ehdr->e_phentsize; 10947c478bd9Sstevel@tonic-gate 10957c478bd9Sstevel@tonic-gate if (*phsizep > sizeof (Phdr) * elf_nphdr_max) { 10967c478bd9Sstevel@tonic-gate if ((*phbasep = kmem_alloc(*phsizep, KM_NOSLEEP)) == NULL) 10977c478bd9Sstevel@tonic-gate return (ENOMEM); 10987c478bd9Sstevel@tonic-gate } else { 10997c478bd9Sstevel@tonic-gate *phbasep = kmem_alloc(*phsizep, KM_SLEEP); 11007c478bd9Sstevel@tonic-gate } 11017c478bd9Sstevel@tonic-gate 11027c478bd9Sstevel@tonic-gate if ((err = vn_rdwr(UIO_READ, vp, *phbasep, *phsizep, 11037c478bd9Sstevel@tonic-gate (offset_t)ehdr->e_phoff, UIO_SYSSPACE, 0, (rlim64_t)0, 11047c478bd9Sstevel@tonic-gate credp, &resid)) != 0) { 11057c478bd9Sstevel@tonic-gate kmem_free(*phbasep, *phsizep); 11067c478bd9Sstevel@tonic-gate *phbasep = NULL; 11077c478bd9Sstevel@tonic-gate return (err); 11087c478bd9Sstevel@tonic-gate } 11097c478bd9Sstevel@tonic-gate 11107c478bd9Sstevel@tonic-gate return (0); 11117c478bd9Sstevel@tonic-gate } 11127c478bd9Sstevel@tonic-gate 11137c478bd9Sstevel@tonic-gate #ifdef _ELF32_COMPAT 11147c478bd9Sstevel@tonic-gate extern size_t elf_nshdr_max; 11157c478bd9Sstevel@tonic-gate extern size_t elf_shstrtab_max; 11167c478bd9Sstevel@tonic-gate #else 11177c478bd9Sstevel@tonic-gate size_t elf_nshdr_max = 10000; 11187c478bd9Sstevel@tonic-gate size_t elf_shstrtab_max = 100 * 1024; 11197c478bd9Sstevel@tonic-gate #endif 11207c478bd9Sstevel@tonic-gate 11217c478bd9Sstevel@tonic-gate 11227c478bd9Sstevel@tonic-gate static int 11237c478bd9Sstevel@tonic-gate getelfshdr(vnode_t *vp, cred_t *credp, const Ehdr *ehdr, 112430da1432Sahl int nshdrs, int shstrndx, caddr_t *shbasep, ssize_t *shsizep, 11257c478bd9Sstevel@tonic-gate char **shstrbasep, ssize_t *shstrsizep) 11267c478bd9Sstevel@tonic-gate { 11277c478bd9Sstevel@tonic-gate ssize_t resid, minsize; 11287c478bd9Sstevel@tonic-gate int err; 11297c478bd9Sstevel@tonic-gate Shdr *shdr; 11307c478bd9Sstevel@tonic-gate 11317c478bd9Sstevel@tonic-gate /* 11327c478bd9Sstevel@tonic-gate * Since we're going to be using e_shentsize to iterate down the 11337c478bd9Sstevel@tonic-gate * array of section headers, it must be 8-byte aligned or else 11347c478bd9Sstevel@tonic-gate * a we might cause a misaligned access. We use all members through 11357c478bd9Sstevel@tonic-gate * sh_entsize (on both 32- and 64-bit ELF files) so e_shentsize 113630da1432Sahl * must be at least large enough to include that member. The index 113730da1432Sahl * of the string table section must also be valid. 11387c478bd9Sstevel@tonic-gate */ 11397c478bd9Sstevel@tonic-gate minsize = offsetof(Shdr, sh_entsize) + sizeof (shdr->sh_entsize); 11407c478bd9Sstevel@tonic-gate if (ehdr->e_shentsize < minsize || (ehdr->e_shentsize & 3) || 114130da1432Sahl shstrndx >= nshdrs) 11427c478bd9Sstevel@tonic-gate return (EINVAL); 11437c478bd9Sstevel@tonic-gate 114430da1432Sahl *shsizep = nshdrs * ehdr->e_shentsize; 11457c478bd9Sstevel@tonic-gate 11467c478bd9Sstevel@tonic-gate if (*shsizep > sizeof (Shdr) * elf_nshdr_max) { 11477c478bd9Sstevel@tonic-gate if ((*shbasep = kmem_alloc(*shsizep, KM_NOSLEEP)) == NULL) 11487c478bd9Sstevel@tonic-gate return (ENOMEM); 11497c478bd9Sstevel@tonic-gate } else { 11507c478bd9Sstevel@tonic-gate *shbasep = kmem_alloc(*shsizep, KM_SLEEP); 11517c478bd9Sstevel@tonic-gate } 11527c478bd9Sstevel@tonic-gate 11537c478bd9Sstevel@tonic-gate if ((err = vn_rdwr(UIO_READ, vp, *shbasep, *shsizep, 11547c478bd9Sstevel@tonic-gate (offset_t)ehdr->e_shoff, UIO_SYSSPACE, 0, (rlim64_t)0, 11557c478bd9Sstevel@tonic-gate credp, &resid)) != 0) { 11567c478bd9Sstevel@tonic-gate kmem_free(*shbasep, *shsizep); 11577c478bd9Sstevel@tonic-gate return (err); 11587c478bd9Sstevel@tonic-gate } 11597c478bd9Sstevel@tonic-gate 11607c478bd9Sstevel@tonic-gate /* 11617c478bd9Sstevel@tonic-gate * Pull the section string table out of the vnode; fail if the size 11627c478bd9Sstevel@tonic-gate * is zero. 11637c478bd9Sstevel@tonic-gate */ 116430da1432Sahl shdr = (Shdr *)(*shbasep + shstrndx * ehdr->e_shentsize); 11657c478bd9Sstevel@tonic-gate if ((*shstrsizep = shdr->sh_size) == 0) { 11667c478bd9Sstevel@tonic-gate kmem_free(*shbasep, *shsizep); 11677c478bd9Sstevel@tonic-gate return (EINVAL); 11687c478bd9Sstevel@tonic-gate } 11697c478bd9Sstevel@tonic-gate 11707c478bd9Sstevel@tonic-gate if (*shstrsizep > elf_shstrtab_max) { 11717c478bd9Sstevel@tonic-gate if ((*shstrbasep = kmem_alloc(*shstrsizep, 11727c478bd9Sstevel@tonic-gate KM_NOSLEEP)) == NULL) { 11737c478bd9Sstevel@tonic-gate kmem_free(*shbasep, *shsizep); 11747c478bd9Sstevel@tonic-gate return (ENOMEM); 11757c478bd9Sstevel@tonic-gate } 11767c478bd9Sstevel@tonic-gate } else { 11777c478bd9Sstevel@tonic-gate *shstrbasep = kmem_alloc(*shstrsizep, KM_SLEEP); 11787c478bd9Sstevel@tonic-gate } 11797c478bd9Sstevel@tonic-gate 11807c478bd9Sstevel@tonic-gate if ((err = vn_rdwr(UIO_READ, vp, *shstrbasep, *shstrsizep, 11817c478bd9Sstevel@tonic-gate (offset_t)shdr->sh_offset, UIO_SYSSPACE, 0, (rlim64_t)0, 11827c478bd9Sstevel@tonic-gate credp, &resid)) != 0) { 11837c478bd9Sstevel@tonic-gate kmem_free(*shbasep, *shsizep); 11847c478bd9Sstevel@tonic-gate kmem_free(*shstrbasep, *shstrsizep); 11857c478bd9Sstevel@tonic-gate return (err); 11867c478bd9Sstevel@tonic-gate } 11877c478bd9Sstevel@tonic-gate 11887c478bd9Sstevel@tonic-gate /* 11897c478bd9Sstevel@tonic-gate * Make sure the strtab is null-terminated to make sure we 11907c478bd9Sstevel@tonic-gate * don't run off the end of the table. 11917c478bd9Sstevel@tonic-gate */ 11927c478bd9Sstevel@tonic-gate (*shstrbasep)[*shstrsizep - 1] = '\0'; 11937c478bd9Sstevel@tonic-gate 11947c478bd9Sstevel@tonic-gate return (0); 11957c478bd9Sstevel@tonic-gate } 11967c478bd9Sstevel@tonic-gate 11977c478bd9Sstevel@tonic-gate static int 11987c478bd9Sstevel@tonic-gate mapelfexec( 11997c478bd9Sstevel@tonic-gate vnode_t *vp, 12007c478bd9Sstevel@tonic-gate Ehdr *ehdr, 120130da1432Sahl int nphdrs, 12027c478bd9Sstevel@tonic-gate caddr_t phdrbase, 12037c478bd9Sstevel@tonic-gate Phdr **uphdr, 12047c478bd9Sstevel@tonic-gate Phdr **dyphdr, 12057c478bd9Sstevel@tonic-gate Phdr **stphdr, 12067c478bd9Sstevel@tonic-gate Phdr **dtphdr, 12077c478bd9Sstevel@tonic-gate Phdr *dataphdrp, 12087c478bd9Sstevel@tonic-gate caddr_t *bssbase, 12097c478bd9Sstevel@tonic-gate caddr_t *brkbase, 12107c478bd9Sstevel@tonic-gate intptr_t *voffset, 12119acbbeafSnn35248 intptr_t *minaddr, 12127c478bd9Sstevel@tonic-gate size_t len, 12137c478bd9Sstevel@tonic-gate long *execsz, 12147c478bd9Sstevel@tonic-gate size_t *brksize) 12157c478bd9Sstevel@tonic-gate { 12167c478bd9Sstevel@tonic-gate Phdr *phdr; 12177c478bd9Sstevel@tonic-gate int i, prot, error; 121860946fe0Smec caddr_t addr = NULL; 12197c478bd9Sstevel@tonic-gate size_t zfodsz; 12207c478bd9Sstevel@tonic-gate int ptload = 0; 12217c478bd9Sstevel@tonic-gate int page; 12227c478bd9Sstevel@tonic-gate off_t offset; 12237c478bd9Sstevel@tonic-gate int hsize = ehdr->e_phentsize; 12249acbbeafSnn35248 caddr_t mintmp = (caddr_t)-1; 1225ec25b48fSsusans extern int use_brk_lpg; 12267c478bd9Sstevel@tonic-gate 12277c478bd9Sstevel@tonic-gate if (ehdr->e_type == ET_DYN) { 12287c478bd9Sstevel@tonic-gate /* 12297c478bd9Sstevel@tonic-gate * Obtain the virtual address of a hole in the 12307c478bd9Sstevel@tonic-gate * address space to map the "interpreter". 12317c478bd9Sstevel@tonic-gate */ 12327c478bd9Sstevel@tonic-gate map_addr(&addr, len, (offset_t)0, 1, 0); 12337c478bd9Sstevel@tonic-gate if (addr == NULL) 12347c478bd9Sstevel@tonic-gate return (ENOMEM); 12357c478bd9Sstevel@tonic-gate *voffset = (intptr_t)addr; 123682e77048Seh208807 123782e77048Seh208807 /* 123882e77048Seh208807 * Calculate the minimum vaddr so it can be subtracted out. 123982e77048Seh208807 * According to the ELF specification, since PT_LOAD sections 124082e77048Seh208807 * must be sorted by increasing p_vaddr values, this is 124182e77048Seh208807 * guaranteed to be the first PT_LOAD section. 124282e77048Seh208807 */ 124382e77048Seh208807 phdr = (Phdr *)phdrbase; 124482e77048Seh208807 for (i = nphdrs; i > 0; i--) { 124582e77048Seh208807 if (phdr->p_type == PT_LOAD) { 124682e77048Seh208807 *voffset -= (uintptr_t)phdr->p_vaddr; 124782e77048Seh208807 break; 124882e77048Seh208807 } 124982e77048Seh208807 phdr = (Phdr *)((caddr_t)phdr + hsize); 125082e77048Seh208807 } 125182e77048Seh208807 12527c478bd9Sstevel@tonic-gate } else { 12537c478bd9Sstevel@tonic-gate *voffset = 0; 12547c478bd9Sstevel@tonic-gate } 12557c478bd9Sstevel@tonic-gate phdr = (Phdr *)phdrbase; 125630da1432Sahl for (i = nphdrs; i > 0; i--) { 12577c478bd9Sstevel@tonic-gate switch (phdr->p_type) { 12587c478bd9Sstevel@tonic-gate case PT_LOAD: 12597c478bd9Sstevel@tonic-gate if ((*dyphdr != NULL) && (*uphdr == NULL)) 12607c478bd9Sstevel@tonic-gate return (0); 12617c478bd9Sstevel@tonic-gate 12627c478bd9Sstevel@tonic-gate ptload = 1; 12637c478bd9Sstevel@tonic-gate prot = PROT_USER; 12647c478bd9Sstevel@tonic-gate if (phdr->p_flags & PF_R) 12657c478bd9Sstevel@tonic-gate prot |= PROT_READ; 12667c478bd9Sstevel@tonic-gate if (phdr->p_flags & PF_W) 12677c478bd9Sstevel@tonic-gate prot |= PROT_WRITE; 12687c478bd9Sstevel@tonic-gate if (phdr->p_flags & PF_X) 12697c478bd9Sstevel@tonic-gate prot |= PROT_EXEC; 12707c478bd9Sstevel@tonic-gate 12717c478bd9Sstevel@tonic-gate addr = (caddr_t)((uintptr_t)phdr->p_vaddr + *voffset); 12729acbbeafSnn35248 12739acbbeafSnn35248 /* 12749acbbeafSnn35248 * Keep track of the segment with the lowest starting 12759acbbeafSnn35248 * address. 12769acbbeafSnn35248 */ 12779acbbeafSnn35248 if (addr < mintmp) 12789acbbeafSnn35248 mintmp = addr; 12799acbbeafSnn35248 12807c478bd9Sstevel@tonic-gate zfodsz = (size_t)phdr->p_memsz - phdr->p_filesz; 12817c478bd9Sstevel@tonic-gate 12827c478bd9Sstevel@tonic-gate offset = phdr->p_offset; 12837c478bd9Sstevel@tonic-gate if (((uintptr_t)offset & PAGEOFFSET) == 12847c478bd9Sstevel@tonic-gate ((uintptr_t)addr & PAGEOFFSET) && 12857c478bd9Sstevel@tonic-gate (!(vp->v_flag & VNOMAP))) { 12867c478bd9Sstevel@tonic-gate page = 1; 12877c478bd9Sstevel@tonic-gate } else { 12887c478bd9Sstevel@tonic-gate page = 0; 12897c478bd9Sstevel@tonic-gate } 12907c478bd9Sstevel@tonic-gate 1291ec25b48fSsusans /* 1292ec25b48fSsusans * Set the heap pagesize for OOB when the bss size 1293ec25b48fSsusans * is known and use_brk_lpg is not 0. 1294ec25b48fSsusans */ 1295ec25b48fSsusans if (brksize != NULL && use_brk_lpg && 1296ec25b48fSsusans zfodsz != 0 && phdr == dataphdrp && 1297ec25b48fSsusans (prot & PROT_WRITE)) { 1298ec25b48fSsusans size_t tlen = P2NPHASE((uintptr_t)addr + 1299ec25b48fSsusans phdr->p_filesz, PAGESIZE); 1300ec25b48fSsusans 1301ec25b48fSsusans if (zfodsz > tlen) { 1302ec25b48fSsusans curproc->p_brkpageszc = 1303ec25b48fSsusans page_szc(map_pgsz(MAPPGSZ_HEAP, 1304ec25b48fSsusans curproc, addr + phdr->p_filesz + 1305ec25b48fSsusans tlen, zfodsz - tlen, 0)); 1306ec25b48fSsusans } 1307ec25b48fSsusans } 1308ec25b48fSsusans 13093486346cSdavemq if (curproc->p_brkpageszc != 0 && phdr == dataphdrp && 13103486346cSdavemq (prot & PROT_WRITE)) { 13117c478bd9Sstevel@tonic-gate uint_t szc = curproc->p_brkpageszc; 13127c478bd9Sstevel@tonic-gate size_t pgsz = page_get_pagesize(szc); 1313ec25b48fSsusans caddr_t ebss = addr + phdr->p_memsz; 1314ec25b48fSsusans size_t extra_zfodsz; 13157c478bd9Sstevel@tonic-gate 13167c478bd9Sstevel@tonic-gate ASSERT(pgsz > PAGESIZE); 13177c478bd9Sstevel@tonic-gate 1318ec25b48fSsusans extra_zfodsz = P2NPHASE((uintptr_t)ebss, pgsz); 1319ec25b48fSsusans 13207c478bd9Sstevel@tonic-gate if (error = execmap(vp, addr, phdr->p_filesz, 1321ec25b48fSsusans zfodsz + extra_zfodsz, phdr->p_offset, 1322ec25b48fSsusans prot, page, szc)) 13237c478bd9Sstevel@tonic-gate goto bad; 13247c478bd9Sstevel@tonic-gate if (brksize != NULL) 1325ec25b48fSsusans *brksize = extra_zfodsz; 13267c478bd9Sstevel@tonic-gate } else { 13277c478bd9Sstevel@tonic-gate if (error = execmap(vp, addr, phdr->p_filesz, 13287c478bd9Sstevel@tonic-gate zfodsz, phdr->p_offset, prot, page, 0)) 13297c478bd9Sstevel@tonic-gate goto bad; 13307c478bd9Sstevel@tonic-gate } 13317c478bd9Sstevel@tonic-gate 13327c478bd9Sstevel@tonic-gate if (bssbase != NULL && addr >= *bssbase && 13337c478bd9Sstevel@tonic-gate phdr == dataphdrp) { 13347c478bd9Sstevel@tonic-gate *bssbase = addr + phdr->p_filesz; 13357c478bd9Sstevel@tonic-gate } 13367c478bd9Sstevel@tonic-gate if (brkbase != NULL && addr >= *brkbase) { 13377c478bd9Sstevel@tonic-gate *brkbase = addr + phdr->p_memsz; 13387c478bd9Sstevel@tonic-gate } 13397c478bd9Sstevel@tonic-gate 13407c478bd9Sstevel@tonic-gate *execsz += btopr(phdr->p_memsz); 13417c478bd9Sstevel@tonic-gate break; 13427c478bd9Sstevel@tonic-gate 13437c478bd9Sstevel@tonic-gate case PT_INTERP: 13447c478bd9Sstevel@tonic-gate if (ptload) 13457c478bd9Sstevel@tonic-gate goto bad; 13467c478bd9Sstevel@tonic-gate *dyphdr = phdr; 13477c478bd9Sstevel@tonic-gate break; 13487c478bd9Sstevel@tonic-gate 13497c478bd9Sstevel@tonic-gate case PT_SHLIB: 13507c478bd9Sstevel@tonic-gate *stphdr = phdr; 13517c478bd9Sstevel@tonic-gate break; 13527c478bd9Sstevel@tonic-gate 13537c478bd9Sstevel@tonic-gate case PT_PHDR: 13547c478bd9Sstevel@tonic-gate if (ptload) 13557c478bd9Sstevel@tonic-gate goto bad; 13567c478bd9Sstevel@tonic-gate *uphdr = phdr; 13577c478bd9Sstevel@tonic-gate break; 13587c478bd9Sstevel@tonic-gate 13597c478bd9Sstevel@tonic-gate case PT_NULL: 13607c478bd9Sstevel@tonic-gate case PT_DYNAMIC: 13617c478bd9Sstevel@tonic-gate case PT_NOTE: 13627c478bd9Sstevel@tonic-gate break; 13637c478bd9Sstevel@tonic-gate 13647c478bd9Sstevel@tonic-gate case PT_SUNWDTRACE: 13657c478bd9Sstevel@tonic-gate if (dtphdr != NULL) 13667c478bd9Sstevel@tonic-gate *dtphdr = phdr; 13677c478bd9Sstevel@tonic-gate break; 13687c478bd9Sstevel@tonic-gate 13697c478bd9Sstevel@tonic-gate default: 13707c478bd9Sstevel@tonic-gate break; 13717c478bd9Sstevel@tonic-gate } 13727c478bd9Sstevel@tonic-gate phdr = (Phdr *)((caddr_t)phdr + hsize); 13737c478bd9Sstevel@tonic-gate } 13749acbbeafSnn35248 13759acbbeafSnn35248 if (minaddr != NULL) { 13769acbbeafSnn35248 ASSERT(mintmp != (caddr_t)-1); 13779acbbeafSnn35248 *minaddr = (intptr_t)mintmp; 13789acbbeafSnn35248 } 13799acbbeafSnn35248 13807c478bd9Sstevel@tonic-gate return (0); 13817c478bd9Sstevel@tonic-gate bad: 13827c478bd9Sstevel@tonic-gate if (error == 0) 13837c478bd9Sstevel@tonic-gate error = EINVAL; 13847c478bd9Sstevel@tonic-gate return (error); 13857c478bd9Sstevel@tonic-gate } 13867c478bd9Sstevel@tonic-gate 13877c478bd9Sstevel@tonic-gate int 13887c478bd9Sstevel@tonic-gate elfnote(vnode_t *vp, offset_t *offsetp, int type, int descsz, void *desc, 13897c478bd9Sstevel@tonic-gate rlim64_t rlimit, cred_t *credp) 13907c478bd9Sstevel@tonic-gate { 13917c478bd9Sstevel@tonic-gate Note note; 13927c478bd9Sstevel@tonic-gate int error; 13937c478bd9Sstevel@tonic-gate 13947c478bd9Sstevel@tonic-gate bzero(¬e, sizeof (note)); 13957c478bd9Sstevel@tonic-gate bcopy("CORE", note.name, 4); 13967c478bd9Sstevel@tonic-gate note.nhdr.n_type = type; 13977c478bd9Sstevel@tonic-gate /* 13987c478bd9Sstevel@tonic-gate * The System V ABI states that n_namesz must be the length of the 13997c478bd9Sstevel@tonic-gate * string that follows the Nhdr structure including the terminating 14007c478bd9Sstevel@tonic-gate * null. The ABI also specifies that sufficient padding should be 14017c478bd9Sstevel@tonic-gate * included so that the description that follows the name string 14027c478bd9Sstevel@tonic-gate * begins on a 4- or 8-byte boundary for 32- and 64-bit binaries 14037c478bd9Sstevel@tonic-gate * respectively. However, since this change was not made correctly 14047c478bd9Sstevel@tonic-gate * at the time of the 64-bit port, both 32- and 64-bit binaries 14057c478bd9Sstevel@tonic-gate * descriptions are only guaranteed to begin on a 4-byte boundary. 14067c478bd9Sstevel@tonic-gate */ 14077c478bd9Sstevel@tonic-gate note.nhdr.n_namesz = 5; 14087c478bd9Sstevel@tonic-gate note.nhdr.n_descsz = roundup(descsz, sizeof (Word)); 14097c478bd9Sstevel@tonic-gate 14107c478bd9Sstevel@tonic-gate if (error = core_write(vp, UIO_SYSSPACE, *offsetp, ¬e, 14117c478bd9Sstevel@tonic-gate sizeof (note), rlimit, credp)) 14127c478bd9Sstevel@tonic-gate return (error); 14137c478bd9Sstevel@tonic-gate 14147c478bd9Sstevel@tonic-gate *offsetp += sizeof (note); 14157c478bd9Sstevel@tonic-gate 14167c478bd9Sstevel@tonic-gate if (error = core_write(vp, UIO_SYSSPACE, *offsetp, desc, 14177c478bd9Sstevel@tonic-gate note.nhdr.n_descsz, rlimit, credp)) 14187c478bd9Sstevel@tonic-gate return (error); 14197c478bd9Sstevel@tonic-gate 14207c478bd9Sstevel@tonic-gate *offsetp += note.nhdr.n_descsz; 14217c478bd9Sstevel@tonic-gate return (0); 14227c478bd9Sstevel@tonic-gate } 14237c478bd9Sstevel@tonic-gate 14247c478bd9Sstevel@tonic-gate /* 14257c478bd9Sstevel@tonic-gate * Copy the section data from one vnode to the section of another vnode. 14267c478bd9Sstevel@tonic-gate */ 14277c478bd9Sstevel@tonic-gate static void 14287c478bd9Sstevel@tonic-gate copy_scn(Shdr *src, vnode_t *src_vp, Shdr *dst, vnode_t *dst_vp, Off *doffset, 14297c478bd9Sstevel@tonic-gate void *buf, size_t size, cred_t *credp, rlim64_t rlimit) 14307c478bd9Sstevel@tonic-gate { 14317c478bd9Sstevel@tonic-gate ssize_t resid; 14327c478bd9Sstevel@tonic-gate size_t len, n = src->sh_size; 14337c478bd9Sstevel@tonic-gate offset_t off = 0; 14347c478bd9Sstevel@tonic-gate 14357c478bd9Sstevel@tonic-gate while (n != 0) { 14367c478bd9Sstevel@tonic-gate len = MIN(size, n); 14377c478bd9Sstevel@tonic-gate if (vn_rdwr(UIO_READ, src_vp, buf, len, src->sh_offset + off, 14387c478bd9Sstevel@tonic-gate UIO_SYSSPACE, 0, (rlim64_t)0, credp, &resid) != 0 || 14397c478bd9Sstevel@tonic-gate resid >= len || 14407c478bd9Sstevel@tonic-gate core_write(dst_vp, UIO_SYSSPACE, *doffset + off, 14417c478bd9Sstevel@tonic-gate buf, len - resid, rlimit, credp) != 0) { 14427c478bd9Sstevel@tonic-gate dst->sh_size = 0; 14437c478bd9Sstevel@tonic-gate dst->sh_offset = 0; 14447c478bd9Sstevel@tonic-gate return; 14457c478bd9Sstevel@tonic-gate } 14467c478bd9Sstevel@tonic-gate 14477c478bd9Sstevel@tonic-gate ASSERT(n >= len - resid); 14487c478bd9Sstevel@tonic-gate 14497c478bd9Sstevel@tonic-gate n -= len - resid; 14507c478bd9Sstevel@tonic-gate off += len - resid; 14517c478bd9Sstevel@tonic-gate } 14527c478bd9Sstevel@tonic-gate 14537c478bd9Sstevel@tonic-gate *doffset += src->sh_size; 14547c478bd9Sstevel@tonic-gate } 14557c478bd9Sstevel@tonic-gate 14567c478bd9Sstevel@tonic-gate #ifdef _ELF32_COMPAT 14577c478bd9Sstevel@tonic-gate extern size_t elf_datasz_max; 14587c478bd9Sstevel@tonic-gate #else 14597c478bd9Sstevel@tonic-gate size_t elf_datasz_max = 1 * 1024 * 1024; 14607c478bd9Sstevel@tonic-gate #endif 14617c478bd9Sstevel@tonic-gate 14627c478bd9Sstevel@tonic-gate /* 14637c478bd9Sstevel@tonic-gate * This function processes mappings that correspond to load objects to 14647c478bd9Sstevel@tonic-gate * examine their respective sections for elfcore(). It's called once with 14657c478bd9Sstevel@tonic-gate * v set to NULL to count the number of sections that we're going to need 14667c478bd9Sstevel@tonic-gate * and then again with v set to some allocated buffer that we fill in with 14677c478bd9Sstevel@tonic-gate * all the section data. 14687c478bd9Sstevel@tonic-gate */ 14697c478bd9Sstevel@tonic-gate static int 14707c478bd9Sstevel@tonic-gate process_scns(core_content_t content, proc_t *p, cred_t *credp, vnode_t *vp, 1471ab9a77c7Sahl Shdr *v, int nv, rlim64_t rlimit, Off *doffsetp, int *nshdrsp) 14727c478bd9Sstevel@tonic-gate { 14737c478bd9Sstevel@tonic-gate vnode_t *lastvp = NULL; 14747c478bd9Sstevel@tonic-gate struct seg *seg; 14757c478bd9Sstevel@tonic-gate int i, j; 14767c478bd9Sstevel@tonic-gate void *data = NULL; 14777c478bd9Sstevel@tonic-gate size_t datasz = 0; 14787c478bd9Sstevel@tonic-gate shstrtab_t shstrtab; 14797c478bd9Sstevel@tonic-gate struct as *as = p->p_as; 14807c478bd9Sstevel@tonic-gate int error = 0; 14817c478bd9Sstevel@tonic-gate 14827c478bd9Sstevel@tonic-gate if (v != NULL) 14837c478bd9Sstevel@tonic-gate shstrtab_init(&shstrtab); 14847c478bd9Sstevel@tonic-gate 14857c478bd9Sstevel@tonic-gate i = 1; 14867c478bd9Sstevel@tonic-gate for (seg = AS_SEGFIRST(as); seg != NULL; seg = AS_SEGNEXT(as, seg)) { 14877c478bd9Sstevel@tonic-gate uint_t prot; 14887c478bd9Sstevel@tonic-gate vnode_t *mvp; 14897c478bd9Sstevel@tonic-gate void *tmp = NULL; 14907c478bd9Sstevel@tonic-gate caddr_t saddr = seg->s_base; 14917c478bd9Sstevel@tonic-gate caddr_t naddr; 14927c478bd9Sstevel@tonic-gate caddr_t eaddr; 14937c478bd9Sstevel@tonic-gate size_t segsize; 14947c478bd9Sstevel@tonic-gate 14957c478bd9Sstevel@tonic-gate Ehdr ehdr; 149630da1432Sahl int nshdrs, shstrndx, nphdrs; 14977c478bd9Sstevel@tonic-gate caddr_t shbase; 14987c478bd9Sstevel@tonic-gate ssize_t shsize; 14997c478bd9Sstevel@tonic-gate char *shstrbase; 15007c478bd9Sstevel@tonic-gate ssize_t shstrsize; 15017c478bd9Sstevel@tonic-gate 15027c478bd9Sstevel@tonic-gate Shdr *shdr; 15037c478bd9Sstevel@tonic-gate const char *name; 15047c478bd9Sstevel@tonic-gate size_t sz; 15057c478bd9Sstevel@tonic-gate uintptr_t off; 15067c478bd9Sstevel@tonic-gate 15077c478bd9Sstevel@tonic-gate int ctf_ndx = 0; 15087c478bd9Sstevel@tonic-gate int symtab_ndx = 0; 15097c478bd9Sstevel@tonic-gate 15107c478bd9Sstevel@tonic-gate /* 15117c478bd9Sstevel@tonic-gate * Since we're just looking for text segments of load 15127c478bd9Sstevel@tonic-gate * objects, we only care about the protection bits; we don't 15137c478bd9Sstevel@tonic-gate * care about the actual size of the segment so we use the 15147c478bd9Sstevel@tonic-gate * reserved size. If the segment's size is zero, there's 15157c478bd9Sstevel@tonic-gate * something fishy going on so we ignore this segment. 15167c478bd9Sstevel@tonic-gate */ 15177c478bd9Sstevel@tonic-gate if (seg->s_ops != &segvn_ops || 15187c478bd9Sstevel@tonic-gate SEGOP_GETVP(seg, seg->s_base, &mvp) != 0 || 15197c478bd9Sstevel@tonic-gate mvp == lastvp || mvp == NULL || mvp->v_type != VREG || 15207c478bd9Sstevel@tonic-gate (segsize = pr_getsegsize(seg, 1)) == 0) 15217c478bd9Sstevel@tonic-gate continue; 15227c478bd9Sstevel@tonic-gate 15237c478bd9Sstevel@tonic-gate eaddr = saddr + segsize; 15247c478bd9Sstevel@tonic-gate prot = pr_getprot(seg, 1, &tmp, &saddr, &naddr, eaddr); 15257c478bd9Sstevel@tonic-gate pr_getprot_done(&tmp); 15267c478bd9Sstevel@tonic-gate 15277c478bd9Sstevel@tonic-gate /* 15287c478bd9Sstevel@tonic-gate * Skip this segment unless the protection bits look like 15297c478bd9Sstevel@tonic-gate * what we'd expect for a text segment. 15307c478bd9Sstevel@tonic-gate */ 15317c478bd9Sstevel@tonic-gate if ((prot & (PROT_WRITE | PROT_EXEC)) != PROT_EXEC) 15327c478bd9Sstevel@tonic-gate continue; 15337c478bd9Sstevel@tonic-gate 153430da1432Sahl if (getelfhead(mvp, credp, &ehdr, &nshdrs, &shstrndx, 153530da1432Sahl &nphdrs) != 0 || 153630da1432Sahl getelfshdr(mvp, credp, &ehdr, nshdrs, shstrndx, 153730da1432Sahl &shbase, &shsize, &shstrbase, &shstrsize) != 0) 15387c478bd9Sstevel@tonic-gate continue; 15397c478bd9Sstevel@tonic-gate 15407c478bd9Sstevel@tonic-gate off = ehdr.e_shentsize; 154130da1432Sahl for (j = 1; j < nshdrs; j++, off += ehdr.e_shentsize) { 15427c478bd9Sstevel@tonic-gate Shdr *symtab = NULL, *strtab; 15437c478bd9Sstevel@tonic-gate 15447c478bd9Sstevel@tonic-gate shdr = (Shdr *)(shbase + off); 15457c478bd9Sstevel@tonic-gate 15467c478bd9Sstevel@tonic-gate if (shdr->sh_name >= shstrsize) 15477c478bd9Sstevel@tonic-gate continue; 15487c478bd9Sstevel@tonic-gate 15497c478bd9Sstevel@tonic-gate name = shstrbase + shdr->sh_name; 15507c478bd9Sstevel@tonic-gate 15517c478bd9Sstevel@tonic-gate if (strcmp(name, shstrtab_data[STR_CTF]) == 0) { 15527c478bd9Sstevel@tonic-gate if ((content & CC_CONTENT_CTF) == 0 || 15537c478bd9Sstevel@tonic-gate ctf_ndx != 0) 15547c478bd9Sstevel@tonic-gate continue; 15557c478bd9Sstevel@tonic-gate 15567c478bd9Sstevel@tonic-gate if (shdr->sh_link > 0 && 155730da1432Sahl shdr->sh_link < nshdrs) { 15587c478bd9Sstevel@tonic-gate symtab = (Shdr *)(shbase + 15597c478bd9Sstevel@tonic-gate shdr->sh_link * ehdr.e_shentsize); 15607c478bd9Sstevel@tonic-gate } 15617c478bd9Sstevel@tonic-gate 1562ab9a77c7Sahl if (v != NULL && i < nv - 1) { 15637c478bd9Sstevel@tonic-gate if (shdr->sh_size > datasz && 15647c478bd9Sstevel@tonic-gate shdr->sh_size <= elf_datasz_max) { 15657c478bd9Sstevel@tonic-gate if (data != NULL) 15667c478bd9Sstevel@tonic-gate kmem_free(data, datasz); 15677c478bd9Sstevel@tonic-gate 15687c478bd9Sstevel@tonic-gate datasz = shdr->sh_size; 15697c478bd9Sstevel@tonic-gate data = kmem_alloc(datasz, 15707c478bd9Sstevel@tonic-gate KM_SLEEP); 15717c478bd9Sstevel@tonic-gate } 15727c478bd9Sstevel@tonic-gate 15737c478bd9Sstevel@tonic-gate v[i].sh_name = shstrtab_ndx(&shstrtab, 15747c478bd9Sstevel@tonic-gate STR_CTF); 15757c478bd9Sstevel@tonic-gate v[i].sh_addr = (Addr)(uintptr_t)saddr; 15767c478bd9Sstevel@tonic-gate v[i].sh_type = SHT_PROGBITS; 15777c478bd9Sstevel@tonic-gate v[i].sh_addralign = 4; 15787c478bd9Sstevel@tonic-gate *doffsetp = roundup(*doffsetp, 15797c478bd9Sstevel@tonic-gate v[i].sh_addralign); 15807c478bd9Sstevel@tonic-gate v[i].sh_offset = *doffsetp; 15817c478bd9Sstevel@tonic-gate v[i].sh_size = shdr->sh_size; 15827c478bd9Sstevel@tonic-gate if (symtab == NULL) { 15837c478bd9Sstevel@tonic-gate v[i].sh_link = 0; 15847c478bd9Sstevel@tonic-gate } else if (symtab->sh_type == 15857c478bd9Sstevel@tonic-gate SHT_SYMTAB && 15867c478bd9Sstevel@tonic-gate symtab_ndx != 0) { 15877c478bd9Sstevel@tonic-gate v[i].sh_link = 15887c478bd9Sstevel@tonic-gate symtab_ndx; 15897c478bd9Sstevel@tonic-gate } else { 15907c478bd9Sstevel@tonic-gate v[i].sh_link = i + 1; 15917c478bd9Sstevel@tonic-gate } 15927c478bd9Sstevel@tonic-gate 15937c478bd9Sstevel@tonic-gate copy_scn(shdr, mvp, &v[i], vp, 15947c478bd9Sstevel@tonic-gate doffsetp, data, datasz, credp, 15957c478bd9Sstevel@tonic-gate rlimit); 15967c478bd9Sstevel@tonic-gate } 15977c478bd9Sstevel@tonic-gate 15987c478bd9Sstevel@tonic-gate ctf_ndx = i++; 15997c478bd9Sstevel@tonic-gate 16007c478bd9Sstevel@tonic-gate /* 16017c478bd9Sstevel@tonic-gate * We've already dumped the symtab. 16027c478bd9Sstevel@tonic-gate */ 16037c478bd9Sstevel@tonic-gate if (symtab != NULL && 16047c478bd9Sstevel@tonic-gate symtab->sh_type == SHT_SYMTAB && 16057c478bd9Sstevel@tonic-gate symtab_ndx != 0) 16067c478bd9Sstevel@tonic-gate continue; 16077c478bd9Sstevel@tonic-gate 16087c478bd9Sstevel@tonic-gate } else if (strcmp(name, 16097c478bd9Sstevel@tonic-gate shstrtab_data[STR_SYMTAB]) == 0) { 16107c478bd9Sstevel@tonic-gate if ((content & CC_CONTENT_SYMTAB) == 0 || 16117c478bd9Sstevel@tonic-gate symtab != 0) 16127c478bd9Sstevel@tonic-gate continue; 16137c478bd9Sstevel@tonic-gate 16147c478bd9Sstevel@tonic-gate symtab = shdr; 16157c478bd9Sstevel@tonic-gate } 16167c478bd9Sstevel@tonic-gate 16177c478bd9Sstevel@tonic-gate if (symtab != NULL) { 16187c478bd9Sstevel@tonic-gate if ((symtab->sh_type != SHT_DYNSYM && 16197c478bd9Sstevel@tonic-gate symtab->sh_type != SHT_SYMTAB) || 16207c478bd9Sstevel@tonic-gate symtab->sh_link == 0 || 162130da1432Sahl symtab->sh_link >= nshdrs) 16227c478bd9Sstevel@tonic-gate continue; 16237c478bd9Sstevel@tonic-gate 16247c478bd9Sstevel@tonic-gate strtab = (Shdr *)(shbase + 16257c478bd9Sstevel@tonic-gate symtab->sh_link * ehdr.e_shentsize); 16267c478bd9Sstevel@tonic-gate 16277c478bd9Sstevel@tonic-gate if (strtab->sh_type != SHT_STRTAB) 16287c478bd9Sstevel@tonic-gate continue; 16297c478bd9Sstevel@tonic-gate 1630ab9a77c7Sahl if (v != NULL && i < nv - 2) { 16317c478bd9Sstevel@tonic-gate sz = MAX(symtab->sh_size, 16327c478bd9Sstevel@tonic-gate strtab->sh_size); 16337c478bd9Sstevel@tonic-gate if (sz > datasz && 16347c478bd9Sstevel@tonic-gate sz <= elf_datasz_max) { 16357c478bd9Sstevel@tonic-gate if (data != NULL) 16367c478bd9Sstevel@tonic-gate kmem_free(data, datasz); 16377c478bd9Sstevel@tonic-gate 16387c478bd9Sstevel@tonic-gate datasz = sz; 16397c478bd9Sstevel@tonic-gate data = kmem_alloc(datasz, 16407c478bd9Sstevel@tonic-gate KM_SLEEP); 16417c478bd9Sstevel@tonic-gate } 16427c478bd9Sstevel@tonic-gate 16437c478bd9Sstevel@tonic-gate if (symtab->sh_type == SHT_DYNSYM) { 16447c478bd9Sstevel@tonic-gate v[i].sh_name = shstrtab_ndx( 16457c478bd9Sstevel@tonic-gate &shstrtab, STR_DYNSYM); 16467c478bd9Sstevel@tonic-gate v[i + 1].sh_name = shstrtab_ndx( 16477c478bd9Sstevel@tonic-gate &shstrtab, STR_DYNSTR); 16487c478bd9Sstevel@tonic-gate } else { 16497c478bd9Sstevel@tonic-gate v[i].sh_name = shstrtab_ndx( 16507c478bd9Sstevel@tonic-gate &shstrtab, STR_SYMTAB); 16517c478bd9Sstevel@tonic-gate v[i + 1].sh_name = shstrtab_ndx( 16527c478bd9Sstevel@tonic-gate &shstrtab, STR_STRTAB); 16537c478bd9Sstevel@tonic-gate } 16547c478bd9Sstevel@tonic-gate 16557c478bd9Sstevel@tonic-gate v[i].sh_type = symtab->sh_type; 16567c478bd9Sstevel@tonic-gate v[i].sh_addr = symtab->sh_addr; 16577c478bd9Sstevel@tonic-gate if (ehdr.e_type == ET_DYN || 16587c478bd9Sstevel@tonic-gate v[i].sh_addr == 0) 16597c478bd9Sstevel@tonic-gate v[i].sh_addr += 16607c478bd9Sstevel@tonic-gate (Addr)(uintptr_t)saddr; 16617c478bd9Sstevel@tonic-gate v[i].sh_addralign = 16627c478bd9Sstevel@tonic-gate symtab->sh_addralign; 16637c478bd9Sstevel@tonic-gate *doffsetp = roundup(*doffsetp, 16647c478bd9Sstevel@tonic-gate v[i].sh_addralign); 16657c478bd9Sstevel@tonic-gate v[i].sh_offset = *doffsetp; 16667c478bd9Sstevel@tonic-gate v[i].sh_size = symtab->sh_size; 16677c478bd9Sstevel@tonic-gate v[i].sh_link = i + 1; 16687c478bd9Sstevel@tonic-gate v[i].sh_entsize = symtab->sh_entsize; 16697c478bd9Sstevel@tonic-gate v[i].sh_info = symtab->sh_info; 16707c478bd9Sstevel@tonic-gate 16717c478bd9Sstevel@tonic-gate copy_scn(symtab, mvp, &v[i], vp, 16727c478bd9Sstevel@tonic-gate doffsetp, data, datasz, credp, 16737c478bd9Sstevel@tonic-gate rlimit); 16747c478bd9Sstevel@tonic-gate 16757c478bd9Sstevel@tonic-gate v[i + 1].sh_type = SHT_STRTAB; 16767c478bd9Sstevel@tonic-gate v[i + 1].sh_flags = SHF_STRINGS; 16777c478bd9Sstevel@tonic-gate v[i + 1].sh_addr = symtab->sh_addr; 16787c478bd9Sstevel@tonic-gate if (ehdr.e_type == ET_DYN || 16797c478bd9Sstevel@tonic-gate v[i + 1].sh_addr == 0) 16807c478bd9Sstevel@tonic-gate v[i + 1].sh_addr += 16817c478bd9Sstevel@tonic-gate (Addr)(uintptr_t)saddr; 16827c478bd9Sstevel@tonic-gate v[i + 1].sh_addralign = 16837c478bd9Sstevel@tonic-gate strtab->sh_addralign; 16847c478bd9Sstevel@tonic-gate *doffsetp = roundup(*doffsetp, 16857c478bd9Sstevel@tonic-gate v[i + 1].sh_addralign); 16867c478bd9Sstevel@tonic-gate v[i + 1].sh_offset = *doffsetp; 16877c478bd9Sstevel@tonic-gate v[i + 1].sh_size = strtab->sh_size; 16887c478bd9Sstevel@tonic-gate 16897c478bd9Sstevel@tonic-gate copy_scn(strtab, mvp, &v[i + 1], vp, 16907c478bd9Sstevel@tonic-gate doffsetp, data, datasz, credp, 16917c478bd9Sstevel@tonic-gate rlimit); 16927c478bd9Sstevel@tonic-gate } 16937c478bd9Sstevel@tonic-gate 16947c478bd9Sstevel@tonic-gate if (symtab->sh_type == SHT_SYMTAB) 16957c478bd9Sstevel@tonic-gate symtab_ndx = i; 16967c478bd9Sstevel@tonic-gate i += 2; 16977c478bd9Sstevel@tonic-gate } 16987c478bd9Sstevel@tonic-gate } 16997c478bd9Sstevel@tonic-gate 17007c478bd9Sstevel@tonic-gate kmem_free(shstrbase, shstrsize); 17017c478bd9Sstevel@tonic-gate kmem_free(shbase, shsize); 17027c478bd9Sstevel@tonic-gate 17037c478bd9Sstevel@tonic-gate lastvp = mvp; 17047c478bd9Sstevel@tonic-gate } 17057c478bd9Sstevel@tonic-gate 17067c478bd9Sstevel@tonic-gate if (v == NULL) { 17077c478bd9Sstevel@tonic-gate if (i == 1) 17087c478bd9Sstevel@tonic-gate *nshdrsp = 0; 17097c478bd9Sstevel@tonic-gate else 17107c478bd9Sstevel@tonic-gate *nshdrsp = i + 1; 17117c478bd9Sstevel@tonic-gate goto done; 17127c478bd9Sstevel@tonic-gate } 17137c478bd9Sstevel@tonic-gate 1714ab9a77c7Sahl if (i != nv - 1) { 17157c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "elfcore: core dump failed for " 17167c478bd9Sstevel@tonic-gate "process %d; address space is changing", p->p_pid); 17177c478bd9Sstevel@tonic-gate error = EIO; 17187c478bd9Sstevel@tonic-gate goto done; 17197c478bd9Sstevel@tonic-gate } 17207c478bd9Sstevel@tonic-gate 17217c478bd9Sstevel@tonic-gate v[i].sh_name = shstrtab_ndx(&shstrtab, STR_SHSTRTAB); 17227c478bd9Sstevel@tonic-gate v[i].sh_size = shstrtab_size(&shstrtab); 17237c478bd9Sstevel@tonic-gate v[i].sh_addralign = 1; 17247c478bd9Sstevel@tonic-gate *doffsetp = roundup(*doffsetp, v[i].sh_addralign); 17257c478bd9Sstevel@tonic-gate v[i].sh_offset = *doffsetp; 17267c478bd9Sstevel@tonic-gate v[i].sh_flags = SHF_STRINGS; 17277c478bd9Sstevel@tonic-gate v[i].sh_type = SHT_STRTAB; 17287c478bd9Sstevel@tonic-gate 17297c478bd9Sstevel@tonic-gate if (v[i].sh_size > datasz) { 17307c478bd9Sstevel@tonic-gate if (data != NULL) 17317c478bd9Sstevel@tonic-gate kmem_free(data, datasz); 17327c478bd9Sstevel@tonic-gate 17337c478bd9Sstevel@tonic-gate datasz = v[i].sh_size; 17347c478bd9Sstevel@tonic-gate data = kmem_alloc(datasz, 17357c478bd9Sstevel@tonic-gate KM_SLEEP); 17367c478bd9Sstevel@tonic-gate } 17377c478bd9Sstevel@tonic-gate 17387c478bd9Sstevel@tonic-gate shstrtab_dump(&shstrtab, data); 17397c478bd9Sstevel@tonic-gate 17407c478bd9Sstevel@tonic-gate if ((error = core_write(vp, UIO_SYSSPACE, *doffsetp, 17417c478bd9Sstevel@tonic-gate data, v[i].sh_size, rlimit, credp)) != 0) 17427c478bd9Sstevel@tonic-gate goto done; 17437c478bd9Sstevel@tonic-gate 17447c478bd9Sstevel@tonic-gate *doffsetp += v[i].sh_size; 17457c478bd9Sstevel@tonic-gate 17467c478bd9Sstevel@tonic-gate done: 17477c478bd9Sstevel@tonic-gate if (data != NULL) 17487c478bd9Sstevel@tonic-gate kmem_free(data, datasz); 17497c478bd9Sstevel@tonic-gate 17507c478bd9Sstevel@tonic-gate return (error); 17517c478bd9Sstevel@tonic-gate } 17527c478bd9Sstevel@tonic-gate 17537c478bd9Sstevel@tonic-gate int 17547c478bd9Sstevel@tonic-gate elfcore(vnode_t *vp, proc_t *p, cred_t *credp, rlim64_t rlimit, int sig, 17557c478bd9Sstevel@tonic-gate core_content_t content) 17567c478bd9Sstevel@tonic-gate { 17577c478bd9Sstevel@tonic-gate offset_t poffset, soffset; 17587c478bd9Sstevel@tonic-gate Off doffset; 17597c478bd9Sstevel@tonic-gate int error, i, nphdrs, nshdrs; 17607c478bd9Sstevel@tonic-gate int overflow = 0; 17617c478bd9Sstevel@tonic-gate struct seg *seg; 17627c478bd9Sstevel@tonic-gate struct as *as = p->p_as; 17637c478bd9Sstevel@tonic-gate union { 17647c478bd9Sstevel@tonic-gate Ehdr ehdr; 17657c478bd9Sstevel@tonic-gate Phdr phdr[1]; 17667c478bd9Sstevel@tonic-gate Shdr shdr[1]; 17677c478bd9Sstevel@tonic-gate } *bigwad; 17687c478bd9Sstevel@tonic-gate size_t bigsize; 17697c478bd9Sstevel@tonic-gate size_t phdrsz, shdrsz; 17707c478bd9Sstevel@tonic-gate Ehdr *ehdr; 17717c478bd9Sstevel@tonic-gate Phdr *v; 17727c478bd9Sstevel@tonic-gate caddr_t brkbase; 17737c478bd9Sstevel@tonic-gate size_t brksize; 17747c478bd9Sstevel@tonic-gate caddr_t stkbase; 17757c478bd9Sstevel@tonic-gate size_t stksize; 17767c478bd9Sstevel@tonic-gate int ntries = 0; 1777f971a346SBryan Cantrill klwp_t *lwp = ttolwp(curthread); 17787c478bd9Sstevel@tonic-gate 17797c478bd9Sstevel@tonic-gate top: 17807c478bd9Sstevel@tonic-gate /* 17817c478bd9Sstevel@tonic-gate * Make sure we have everything we need (registers, etc.). 17827c478bd9Sstevel@tonic-gate * All other lwps have already stopped and are in an orderly state. 17837c478bd9Sstevel@tonic-gate */ 17847c478bd9Sstevel@tonic-gate ASSERT(p == ttoproc(curthread)); 17857c478bd9Sstevel@tonic-gate prstop(0, 0); 17867c478bd9Sstevel@tonic-gate 1787dc32d872SJosef 'Jeff' Sipek AS_LOCK_ENTER(as, RW_WRITER); 17887c478bd9Sstevel@tonic-gate nphdrs = prnsegs(as, 0) + 2; /* two CORE note sections */ 17897c478bd9Sstevel@tonic-gate 17907c478bd9Sstevel@tonic-gate /* 17917c478bd9Sstevel@tonic-gate * Count the number of section headers we're going to need. 17927c478bd9Sstevel@tonic-gate */ 17937c478bd9Sstevel@tonic-gate nshdrs = 0; 17947c478bd9Sstevel@tonic-gate if (content & (CC_CONTENT_CTF | CC_CONTENT_SYMTAB)) { 17957c478bd9Sstevel@tonic-gate (void) process_scns(content, p, credp, NULL, NULL, NULL, 0, 17967c478bd9Sstevel@tonic-gate NULL, &nshdrs); 17977c478bd9Sstevel@tonic-gate } 1798dc32d872SJosef 'Jeff' Sipek AS_LOCK_EXIT(as); 17997c478bd9Sstevel@tonic-gate 180030da1432Sahl ASSERT(nshdrs == 0 || nshdrs > 1); 180130da1432Sahl 180230da1432Sahl /* 180330da1432Sahl * The core file contents may required zero section headers, but if 180430da1432Sahl * we overflow the 16 bits allotted to the program header count in 180530da1432Sahl * the ELF header, we'll need that program header at index zero. 180630da1432Sahl */ 180730da1432Sahl if (nshdrs == 0 && nphdrs >= PN_XNUM) 180830da1432Sahl nshdrs = 1; 180930da1432Sahl 18107c478bd9Sstevel@tonic-gate phdrsz = nphdrs * sizeof (Phdr); 18117c478bd9Sstevel@tonic-gate shdrsz = nshdrs * sizeof (Shdr); 18127c478bd9Sstevel@tonic-gate 18137c478bd9Sstevel@tonic-gate bigsize = MAX(sizeof (*bigwad), MAX(phdrsz, shdrsz)); 18147c478bd9Sstevel@tonic-gate bigwad = kmem_alloc(bigsize, KM_SLEEP); 18157c478bd9Sstevel@tonic-gate 18167c478bd9Sstevel@tonic-gate ehdr = &bigwad->ehdr; 18177c478bd9Sstevel@tonic-gate bzero(ehdr, sizeof (*ehdr)); 18187c478bd9Sstevel@tonic-gate 18197c478bd9Sstevel@tonic-gate ehdr->e_ident[EI_MAG0] = ELFMAG0; 18207c478bd9Sstevel@tonic-gate ehdr->e_ident[EI_MAG1] = ELFMAG1; 18217c478bd9Sstevel@tonic-gate ehdr->e_ident[EI_MAG2] = ELFMAG2; 18227c478bd9Sstevel@tonic-gate ehdr->e_ident[EI_MAG3] = ELFMAG3; 18237c478bd9Sstevel@tonic-gate ehdr->e_ident[EI_CLASS] = ELFCLASS; 18247c478bd9Sstevel@tonic-gate ehdr->e_type = ET_CORE; 18257c478bd9Sstevel@tonic-gate 18267c478bd9Sstevel@tonic-gate #if !defined(_LP64) || defined(_ELF32_COMPAT) 18277c478bd9Sstevel@tonic-gate 18287c478bd9Sstevel@tonic-gate #if defined(__sparc) 18297c478bd9Sstevel@tonic-gate ehdr->e_ident[EI_DATA] = ELFDATA2MSB; 18307c478bd9Sstevel@tonic-gate ehdr->e_machine = EM_SPARC; 18317c478bd9Sstevel@tonic-gate #elif defined(__i386) || defined(__i386_COMPAT) 18327c478bd9Sstevel@tonic-gate ehdr->e_ident[EI_DATA] = ELFDATA2LSB; 18337c478bd9Sstevel@tonic-gate ehdr->e_machine = EM_386; 18347c478bd9Sstevel@tonic-gate #else 18357c478bd9Sstevel@tonic-gate #error "no recognized machine type is defined" 18367c478bd9Sstevel@tonic-gate #endif 18377c478bd9Sstevel@tonic-gate 18387c478bd9Sstevel@tonic-gate #else /* !defined(_LP64) || defined(_ELF32_COMPAT) */ 18397c478bd9Sstevel@tonic-gate 18407c478bd9Sstevel@tonic-gate #if defined(__sparc) 18417c478bd9Sstevel@tonic-gate ehdr->e_ident[EI_DATA] = ELFDATA2MSB; 18427c478bd9Sstevel@tonic-gate ehdr->e_machine = EM_SPARCV9; 18437c478bd9Sstevel@tonic-gate #elif defined(__amd64) 18447c478bd9Sstevel@tonic-gate ehdr->e_ident[EI_DATA] = ELFDATA2LSB; 18457c478bd9Sstevel@tonic-gate ehdr->e_machine = EM_AMD64; 18467c478bd9Sstevel@tonic-gate #else 18477c478bd9Sstevel@tonic-gate #error "no recognized 64-bit machine type is defined" 18487c478bd9Sstevel@tonic-gate #endif 18497c478bd9Sstevel@tonic-gate 18507c478bd9Sstevel@tonic-gate #endif /* !defined(_LP64) || defined(_ELF32_COMPAT) */ 18517c478bd9Sstevel@tonic-gate 185230da1432Sahl /* 185330da1432Sahl * If the count of program headers or section headers or the index 185430da1432Sahl * of the section string table can't fit in the mere 16 bits 185530da1432Sahl * shortsightedly allotted to them in the ELF header, we use the 185630da1432Sahl * extended formats and put the real values in the section header 185730da1432Sahl * as index 0. 185830da1432Sahl */ 18597c478bd9Sstevel@tonic-gate ehdr->e_version = EV_CURRENT; 18607c478bd9Sstevel@tonic-gate ehdr->e_ehsize = sizeof (Ehdr); 186130da1432Sahl 186230da1432Sahl if (nphdrs >= PN_XNUM) 186330da1432Sahl ehdr->e_phnum = PN_XNUM; 186430da1432Sahl else 18657c478bd9Sstevel@tonic-gate ehdr->e_phnum = (unsigned short)nphdrs; 18667c478bd9Sstevel@tonic-gate 186730da1432Sahl ehdr->e_phoff = sizeof (Ehdr); 186830da1432Sahl ehdr->e_phentsize = sizeof (Phdr); 186930da1432Sahl 18707c478bd9Sstevel@tonic-gate if (nshdrs > 0) { 187130da1432Sahl if (nshdrs >= SHN_LORESERVE) 187230da1432Sahl ehdr->e_shnum = 0; 187330da1432Sahl else 18747c478bd9Sstevel@tonic-gate ehdr->e_shnum = (unsigned short)nshdrs; 187530da1432Sahl 187630da1432Sahl if (nshdrs - 1 >= SHN_LORESERVE) 187730da1432Sahl ehdr->e_shstrndx = SHN_XINDEX; 187830da1432Sahl else 187930da1432Sahl ehdr->e_shstrndx = (unsigned short)(nshdrs - 1); 188030da1432Sahl 188130da1432Sahl ehdr->e_shoff = ehdr->e_phoff + ehdr->e_phentsize * nphdrs; 188230da1432Sahl ehdr->e_shentsize = sizeof (Shdr); 18837c478bd9Sstevel@tonic-gate } 18847c478bd9Sstevel@tonic-gate 18857c478bd9Sstevel@tonic-gate if (error = core_write(vp, UIO_SYSSPACE, (offset_t)0, ehdr, 18867c478bd9Sstevel@tonic-gate sizeof (Ehdr), rlimit, credp)) 18877c478bd9Sstevel@tonic-gate goto done; 18887c478bd9Sstevel@tonic-gate 18897c478bd9Sstevel@tonic-gate poffset = sizeof (Ehdr); 18907c478bd9Sstevel@tonic-gate soffset = sizeof (Ehdr) + phdrsz; 18917c478bd9Sstevel@tonic-gate doffset = sizeof (Ehdr) + phdrsz + shdrsz; 18927c478bd9Sstevel@tonic-gate 18937c478bd9Sstevel@tonic-gate v = &bigwad->phdr[0]; 18947c478bd9Sstevel@tonic-gate bzero(v, phdrsz); 18957c478bd9Sstevel@tonic-gate 18967c478bd9Sstevel@tonic-gate setup_old_note_header(&v[0], p); 18977c478bd9Sstevel@tonic-gate v[0].p_offset = doffset = roundup(doffset, sizeof (Word)); 18987c478bd9Sstevel@tonic-gate doffset += v[0].p_filesz; 18997c478bd9Sstevel@tonic-gate 19007c478bd9Sstevel@tonic-gate setup_note_header(&v[1], p); 19017c478bd9Sstevel@tonic-gate v[1].p_offset = doffset = roundup(doffset, sizeof (Word)); 19027c478bd9Sstevel@tonic-gate doffset += v[1].p_filesz; 19037c478bd9Sstevel@tonic-gate 19047c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock); 19057c478bd9Sstevel@tonic-gate 19067c478bd9Sstevel@tonic-gate brkbase = p->p_brkbase; 19077c478bd9Sstevel@tonic-gate brksize = p->p_brksize; 19087c478bd9Sstevel@tonic-gate 19097c478bd9Sstevel@tonic-gate stkbase = p->p_usrstack - p->p_stksize; 19107c478bd9Sstevel@tonic-gate stksize = p->p_stksize; 19117c478bd9Sstevel@tonic-gate 19127c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 19137c478bd9Sstevel@tonic-gate 1914dc32d872SJosef 'Jeff' Sipek AS_LOCK_ENTER(as, RW_WRITER); 19157c478bd9Sstevel@tonic-gate i = 2; 19167c478bd9Sstevel@tonic-gate for (seg = AS_SEGFIRST(as); seg != NULL; seg = AS_SEGNEXT(as, seg)) { 19177c478bd9Sstevel@tonic-gate caddr_t eaddr = seg->s_base + pr_getsegsize(seg, 0); 19187c478bd9Sstevel@tonic-gate caddr_t saddr, naddr; 19197c478bd9Sstevel@tonic-gate void *tmp = NULL; 19207c478bd9Sstevel@tonic-gate extern struct seg_ops segspt_shmops; 19217c478bd9Sstevel@tonic-gate 19227c478bd9Sstevel@tonic-gate for (saddr = seg->s_base; saddr < eaddr; saddr = naddr) { 19237c478bd9Sstevel@tonic-gate uint_t prot; 19247c478bd9Sstevel@tonic-gate size_t size; 19257c478bd9Sstevel@tonic-gate int type; 19267c478bd9Sstevel@tonic-gate vnode_t *mvp; 19277c478bd9Sstevel@tonic-gate 19287c478bd9Sstevel@tonic-gate prot = pr_getprot(seg, 0, &tmp, &saddr, &naddr, eaddr); 19297c478bd9Sstevel@tonic-gate prot &= PROT_READ | PROT_WRITE | PROT_EXEC; 19307c478bd9Sstevel@tonic-gate if ((size = (size_t)(naddr - saddr)) == 0) 19317c478bd9Sstevel@tonic-gate continue; 19327c478bd9Sstevel@tonic-gate if (i == nphdrs) { 19337c478bd9Sstevel@tonic-gate overflow++; 19347c478bd9Sstevel@tonic-gate continue; 19357c478bd9Sstevel@tonic-gate } 19367c478bd9Sstevel@tonic-gate v[i].p_type = PT_LOAD; 19377c478bd9Sstevel@tonic-gate v[i].p_vaddr = (Addr)(uintptr_t)saddr; 19387c478bd9Sstevel@tonic-gate v[i].p_memsz = size; 19397c478bd9Sstevel@tonic-gate if (prot & PROT_READ) 19407c478bd9Sstevel@tonic-gate v[i].p_flags |= PF_R; 19417c478bd9Sstevel@tonic-gate if (prot & PROT_WRITE) 19427c478bd9Sstevel@tonic-gate v[i].p_flags |= PF_W; 19437c478bd9Sstevel@tonic-gate if (prot & PROT_EXEC) 19447c478bd9Sstevel@tonic-gate v[i].p_flags |= PF_X; 19457c478bd9Sstevel@tonic-gate 19467c478bd9Sstevel@tonic-gate /* 19477c478bd9Sstevel@tonic-gate * Figure out which mappings to include in the core. 19487c478bd9Sstevel@tonic-gate */ 19497c478bd9Sstevel@tonic-gate type = SEGOP_GETTYPE(seg, saddr); 19507c478bd9Sstevel@tonic-gate 19517c478bd9Sstevel@tonic-gate if (saddr == stkbase && size == stksize) { 19527c478bd9Sstevel@tonic-gate if (!(content & CC_CONTENT_STACK)) 19537c478bd9Sstevel@tonic-gate goto exclude; 19547c478bd9Sstevel@tonic-gate 19557c478bd9Sstevel@tonic-gate } else if (saddr == brkbase && size == brksize) { 19567c478bd9Sstevel@tonic-gate if (!(content & CC_CONTENT_HEAP)) 19577c478bd9Sstevel@tonic-gate goto exclude; 19587c478bd9Sstevel@tonic-gate 19597c478bd9Sstevel@tonic-gate } else if (seg->s_ops == &segspt_shmops) { 19607c478bd9Sstevel@tonic-gate if (type & MAP_NORESERVE) { 19617c478bd9Sstevel@tonic-gate if (!(content & CC_CONTENT_DISM)) 19627c478bd9Sstevel@tonic-gate goto exclude; 19637c478bd9Sstevel@tonic-gate } else { 19647c478bd9Sstevel@tonic-gate if (!(content & CC_CONTENT_ISM)) 19657c478bd9Sstevel@tonic-gate goto exclude; 19667c478bd9Sstevel@tonic-gate } 19677c478bd9Sstevel@tonic-gate 19687c478bd9Sstevel@tonic-gate } else if (seg->s_ops != &segvn_ops) { 19697c478bd9Sstevel@tonic-gate goto exclude; 19707c478bd9Sstevel@tonic-gate 19717c478bd9Sstevel@tonic-gate } else if (type & MAP_SHARED) { 19727c478bd9Sstevel@tonic-gate if (shmgetid(p, saddr) != SHMID_NONE) { 19737c478bd9Sstevel@tonic-gate if (!(content & CC_CONTENT_SHM)) 19747c478bd9Sstevel@tonic-gate goto exclude; 19757c478bd9Sstevel@tonic-gate 19767c478bd9Sstevel@tonic-gate } else if (SEGOP_GETVP(seg, seg->s_base, 19777c478bd9Sstevel@tonic-gate &mvp) != 0 || mvp == NULL || 19787c478bd9Sstevel@tonic-gate mvp->v_type != VREG) { 19797c478bd9Sstevel@tonic-gate if (!(content & CC_CONTENT_SHANON)) 19807c478bd9Sstevel@tonic-gate goto exclude; 19817c478bd9Sstevel@tonic-gate 19827c478bd9Sstevel@tonic-gate } else { 19837c478bd9Sstevel@tonic-gate if (!(content & CC_CONTENT_SHFILE)) 19847c478bd9Sstevel@tonic-gate goto exclude; 19857c478bd9Sstevel@tonic-gate } 19867c478bd9Sstevel@tonic-gate 19877c478bd9Sstevel@tonic-gate } else if (SEGOP_GETVP(seg, seg->s_base, &mvp) != 0 || 19887c478bd9Sstevel@tonic-gate mvp == NULL || mvp->v_type != VREG) { 19897c478bd9Sstevel@tonic-gate if (!(content & CC_CONTENT_ANON)) 19907c478bd9Sstevel@tonic-gate goto exclude; 19917c478bd9Sstevel@tonic-gate 19927c478bd9Sstevel@tonic-gate } else if (prot == (PROT_READ | PROT_EXEC)) { 19937c478bd9Sstevel@tonic-gate if (!(content & CC_CONTENT_TEXT)) 19947c478bd9Sstevel@tonic-gate goto exclude; 19957c478bd9Sstevel@tonic-gate 19967c478bd9Sstevel@tonic-gate } else if (prot == PROT_READ) { 19977c478bd9Sstevel@tonic-gate if (!(content & CC_CONTENT_RODATA)) 19987c478bd9Sstevel@tonic-gate goto exclude; 19997c478bd9Sstevel@tonic-gate 20007c478bd9Sstevel@tonic-gate } else { 20017c478bd9Sstevel@tonic-gate if (!(content & CC_CONTENT_DATA)) 20027c478bd9Sstevel@tonic-gate goto exclude; 20037c478bd9Sstevel@tonic-gate } 20047c478bd9Sstevel@tonic-gate 20057c478bd9Sstevel@tonic-gate doffset = roundup(doffset, sizeof (Word)); 20067c478bd9Sstevel@tonic-gate v[i].p_offset = doffset; 20077c478bd9Sstevel@tonic-gate v[i].p_filesz = size; 20087c478bd9Sstevel@tonic-gate doffset += size; 20097c478bd9Sstevel@tonic-gate exclude: 20107c478bd9Sstevel@tonic-gate i++; 20117c478bd9Sstevel@tonic-gate } 20127c478bd9Sstevel@tonic-gate ASSERT(tmp == NULL); 20137c478bd9Sstevel@tonic-gate } 2014dc32d872SJosef 'Jeff' Sipek AS_LOCK_EXIT(as); 20157c478bd9Sstevel@tonic-gate 20167c478bd9Sstevel@tonic-gate if (overflow || i != nphdrs) { 20177c478bd9Sstevel@tonic-gate if (ntries++ == 0) { 20187c478bd9Sstevel@tonic-gate kmem_free(bigwad, bigsize); 201914c26162SMita Solanky overflow = 0; 20207c478bd9Sstevel@tonic-gate goto top; 20217c478bd9Sstevel@tonic-gate } 20227c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "elfcore: core dump failed for " 20237c478bd9Sstevel@tonic-gate "process %d; address space is changing", p->p_pid); 20247c478bd9Sstevel@tonic-gate error = EIO; 20257c478bd9Sstevel@tonic-gate goto done; 20267c478bd9Sstevel@tonic-gate } 20277c478bd9Sstevel@tonic-gate 20287c478bd9Sstevel@tonic-gate if ((error = core_write(vp, UIO_SYSSPACE, poffset, 20297c478bd9Sstevel@tonic-gate v, phdrsz, rlimit, credp)) != 0) 20307c478bd9Sstevel@tonic-gate goto done; 20317c478bd9Sstevel@tonic-gate 20327c478bd9Sstevel@tonic-gate if ((error = write_old_elfnotes(p, sig, vp, v[0].p_offset, rlimit, 20337c478bd9Sstevel@tonic-gate credp)) != 0) 20347c478bd9Sstevel@tonic-gate goto done; 20357c478bd9Sstevel@tonic-gate 20367c478bd9Sstevel@tonic-gate if ((error = write_elfnotes(p, sig, vp, v[1].p_offset, rlimit, 20377c478bd9Sstevel@tonic-gate credp, content)) != 0) 20387c478bd9Sstevel@tonic-gate goto done; 20397c478bd9Sstevel@tonic-gate 20407c478bd9Sstevel@tonic-gate for (i = 2; i < nphdrs; i++) { 2041f971a346SBryan Cantrill prkillinfo_t killinfo; 2042f971a346SBryan Cantrill sigqueue_t *sq; 2043f971a346SBryan Cantrill int sig, j; 2044f971a346SBryan Cantrill 20457c478bd9Sstevel@tonic-gate if (v[i].p_filesz == 0) 20467c478bd9Sstevel@tonic-gate continue; 20477c478bd9Sstevel@tonic-gate 20487c478bd9Sstevel@tonic-gate /* 20497c478bd9Sstevel@tonic-gate * If dumping out this segment fails, rather than failing 20507c478bd9Sstevel@tonic-gate * the core dump entirely, we reset the size of the mapping 20517c478bd9Sstevel@tonic-gate * to zero to indicate that the data is absent from the core 20527c478bd9Sstevel@tonic-gate * file and or in the PF_SUNW_FAILURE flag to differentiate 20537c478bd9Sstevel@tonic-gate * this from mappings that were excluded due to the core file 20547c478bd9Sstevel@tonic-gate * content settings. 20557c478bd9Sstevel@tonic-gate */ 20567c478bd9Sstevel@tonic-gate if ((error = core_seg(p, vp, v[i].p_offset, 20577c478bd9Sstevel@tonic-gate (caddr_t)(uintptr_t)v[i].p_vaddr, v[i].p_filesz, 2058f971a346SBryan Cantrill rlimit, credp)) == 0) { 2059f971a346SBryan Cantrill continue; 2060f971a346SBryan Cantrill } 20617c478bd9Sstevel@tonic-gate 2062f971a346SBryan Cantrill if ((sig = lwp->lwp_cursig) == 0) { 20637c478bd9Sstevel@tonic-gate /* 2064f971a346SBryan Cantrill * We failed due to something other than a signal. 20657c478bd9Sstevel@tonic-gate * Since the space reserved for the segment is now 20667c478bd9Sstevel@tonic-gate * unused, we stash the errno in the first four 20677c478bd9Sstevel@tonic-gate * bytes. This undocumented interface will let us 20687c478bd9Sstevel@tonic-gate * understand the nature of the failure. 20697c478bd9Sstevel@tonic-gate */ 20707c478bd9Sstevel@tonic-gate (void) core_write(vp, UIO_SYSSPACE, v[i].p_offset, 20717c478bd9Sstevel@tonic-gate &error, sizeof (error), rlimit, credp); 20727c478bd9Sstevel@tonic-gate 20737c478bd9Sstevel@tonic-gate v[i].p_filesz = 0; 20747c478bd9Sstevel@tonic-gate v[i].p_flags |= PF_SUNW_FAILURE; 20757c478bd9Sstevel@tonic-gate if ((error = core_write(vp, UIO_SYSSPACE, 20767c478bd9Sstevel@tonic-gate poffset + sizeof (v[i]) * i, &v[i], sizeof (v[i]), 20777c478bd9Sstevel@tonic-gate rlimit, credp)) != 0) 20787c478bd9Sstevel@tonic-gate goto done; 2079f971a346SBryan Cantrill 2080f971a346SBryan Cantrill continue; 20817c478bd9Sstevel@tonic-gate } 2082f971a346SBryan Cantrill 2083f971a346SBryan Cantrill /* 2084f971a346SBryan Cantrill * We took a signal. We want to abort the dump entirely, but 2085f971a346SBryan Cantrill * we also want to indicate what failed and why. We therefore 2086f971a346SBryan Cantrill * use the space reserved for the first failing segment to 2087f971a346SBryan Cantrill * write our error (which, for purposes of compatability with 2088f971a346SBryan Cantrill * older core dump readers, we set to EINTR) followed by any 2089f971a346SBryan Cantrill * siginfo associated with the signal. 2090f971a346SBryan Cantrill */ 2091f971a346SBryan Cantrill bzero(&killinfo, sizeof (killinfo)); 2092f971a346SBryan Cantrill killinfo.prk_error = EINTR; 2093f971a346SBryan Cantrill 2094f971a346SBryan Cantrill sq = sig == SIGKILL ? curproc->p_killsqp : lwp->lwp_curinfo; 2095f971a346SBryan Cantrill 2096f971a346SBryan Cantrill if (sq != NULL) { 2097f971a346SBryan Cantrill bcopy(&sq->sq_info, &killinfo.prk_info, 2098ea260350SBryan Cantrill sizeof (sq->sq_info)); 2099f971a346SBryan Cantrill } else { 2100f971a346SBryan Cantrill killinfo.prk_info.si_signo = lwp->lwp_cursig; 2101f971a346SBryan Cantrill killinfo.prk_info.si_code = SI_NOINFO; 2102f971a346SBryan Cantrill } 2103f971a346SBryan Cantrill 2104f971a346SBryan Cantrill #if (defined(_SYSCALL32_IMPL) || defined(_LP64)) 2105f971a346SBryan Cantrill /* 2106f971a346SBryan Cantrill * If this is a 32-bit process, we need to translate from the 2107f971a346SBryan Cantrill * native siginfo to the 32-bit variant. (Core readers must 2108f971a346SBryan Cantrill * always have the same data model as their target or must 2109f971a346SBryan Cantrill * be aware of -- and compensate for -- data model differences.) 2110f971a346SBryan Cantrill */ 2111f971a346SBryan Cantrill if (curproc->p_model == DATAMODEL_ILP32) { 2112f971a346SBryan Cantrill siginfo32_t si32; 2113f971a346SBryan Cantrill 2114f971a346SBryan Cantrill siginfo_kto32((k_siginfo_t *)&killinfo.prk_info, &si32); 2115f971a346SBryan Cantrill bcopy(&si32, &killinfo.prk_info, sizeof (si32)); 2116f971a346SBryan Cantrill } 2117f971a346SBryan Cantrill #endif 2118f971a346SBryan Cantrill 2119f971a346SBryan Cantrill (void) core_write(vp, UIO_SYSSPACE, v[i].p_offset, 2120f971a346SBryan Cantrill &killinfo, sizeof (killinfo), rlimit, credp); 2121f971a346SBryan Cantrill 2122f971a346SBryan Cantrill /* 2123f971a346SBryan Cantrill * For the segment on which we took the signal, indicate that 2124f971a346SBryan Cantrill * its data now refers to a siginfo. 2125f971a346SBryan Cantrill */ 2126f971a346SBryan Cantrill v[i].p_filesz = 0; 2127f971a346SBryan Cantrill v[i].p_flags |= PF_SUNW_FAILURE | PF_SUNW_KILLED | 2128f971a346SBryan Cantrill PF_SUNW_SIGINFO; 2129f971a346SBryan Cantrill 2130f971a346SBryan Cantrill /* 2131f971a346SBryan Cantrill * And for every other segment, indicate that its absence 2132f971a346SBryan Cantrill * is due to a signal. 2133f971a346SBryan Cantrill */ 2134f971a346SBryan Cantrill for (j = i + 1; j < nphdrs; j++) { 2135f971a346SBryan Cantrill v[j].p_filesz = 0; 2136f971a346SBryan Cantrill v[j].p_flags |= PF_SUNW_FAILURE | PF_SUNW_KILLED; 2137f971a346SBryan Cantrill } 2138f971a346SBryan Cantrill 2139f971a346SBryan Cantrill /* 2140f971a346SBryan Cantrill * Finally, write out our modified program headers. 2141f971a346SBryan Cantrill */ 2142f971a346SBryan Cantrill if ((error = core_write(vp, UIO_SYSSPACE, 2143f971a346SBryan Cantrill poffset + sizeof (v[i]) * i, &v[i], 2144f971a346SBryan Cantrill sizeof (v[i]) * (nphdrs - i), rlimit, credp)) != 0) 2145f971a346SBryan Cantrill goto done; 2146f971a346SBryan Cantrill 2147f971a346SBryan Cantrill break; 21487c478bd9Sstevel@tonic-gate } 21497c478bd9Sstevel@tonic-gate 21507c478bd9Sstevel@tonic-gate if (nshdrs > 0) { 21517c478bd9Sstevel@tonic-gate bzero(&bigwad->shdr[0], shdrsz); 21527c478bd9Sstevel@tonic-gate 215330da1432Sahl if (nshdrs >= SHN_LORESERVE) 215430da1432Sahl bigwad->shdr[0].sh_size = nshdrs; 215530da1432Sahl 215630da1432Sahl if (nshdrs - 1 >= SHN_LORESERVE) 215730da1432Sahl bigwad->shdr[0].sh_link = nshdrs - 1; 215830da1432Sahl 215930da1432Sahl if (nphdrs >= PN_XNUM) 216030da1432Sahl bigwad->shdr[0].sh_info = nphdrs; 216130da1432Sahl 216230da1432Sahl if (nshdrs > 1) { 2163dc32d872SJosef 'Jeff' Sipek AS_LOCK_ENTER(as, RW_WRITER); 21647c478bd9Sstevel@tonic-gate if ((error = process_scns(content, p, credp, vp, 216530da1432Sahl &bigwad->shdr[0], nshdrs, rlimit, &doffset, 216630da1432Sahl NULL)) != 0) { 2167dc32d872SJosef 'Jeff' Sipek AS_LOCK_EXIT(as); 21687c478bd9Sstevel@tonic-gate goto done; 21697c478bd9Sstevel@tonic-gate } 2170dc32d872SJosef 'Jeff' Sipek AS_LOCK_EXIT(as); 217130da1432Sahl } 21727c478bd9Sstevel@tonic-gate 21737c478bd9Sstevel@tonic-gate if ((error = core_write(vp, UIO_SYSSPACE, soffset, 21747c478bd9Sstevel@tonic-gate &bigwad->shdr[0], shdrsz, rlimit, credp)) != 0) 21757c478bd9Sstevel@tonic-gate goto done; 21767c478bd9Sstevel@tonic-gate } 21777c478bd9Sstevel@tonic-gate 21787c478bd9Sstevel@tonic-gate done: 21797c478bd9Sstevel@tonic-gate kmem_free(bigwad, bigsize); 21807c478bd9Sstevel@tonic-gate return (error); 21817c478bd9Sstevel@tonic-gate } 21827c478bd9Sstevel@tonic-gate 21837c478bd9Sstevel@tonic-gate #ifndef _ELF32_COMPAT 21847c478bd9Sstevel@tonic-gate 21857c478bd9Sstevel@tonic-gate static struct execsw esw = { 21867c478bd9Sstevel@tonic-gate #ifdef _LP64 21877c478bd9Sstevel@tonic-gate elf64magicstr, 21887c478bd9Sstevel@tonic-gate #else /* _LP64 */ 21897c478bd9Sstevel@tonic-gate elf32magicstr, 21907c478bd9Sstevel@tonic-gate #endif /* _LP64 */ 21917c478bd9Sstevel@tonic-gate 0, 21927c478bd9Sstevel@tonic-gate 5, 21937c478bd9Sstevel@tonic-gate elfexec, 21947c478bd9Sstevel@tonic-gate elfcore 21957c478bd9Sstevel@tonic-gate }; 21967c478bd9Sstevel@tonic-gate 21977c478bd9Sstevel@tonic-gate static struct modlexec modlexec = { 2198a0de58d6SRoger A. Faulkner &mod_execops, "exec module for elf", &esw 21997c478bd9Sstevel@tonic-gate }; 22007c478bd9Sstevel@tonic-gate 22017c478bd9Sstevel@tonic-gate #ifdef _LP64 22027c478bd9Sstevel@tonic-gate extern int elf32exec(vnode_t *vp, execa_t *uap, uarg_t *args, 22037c478bd9Sstevel@tonic-gate intpdata_t *idatap, int level, long *execsz, 22049acbbeafSnn35248 int setid, caddr_t exec_file, cred_t *cred, 22059acbbeafSnn35248 int brand_action); 22067c478bd9Sstevel@tonic-gate extern int elf32core(vnode_t *vp, proc_t *p, cred_t *credp, 22077c478bd9Sstevel@tonic-gate rlim64_t rlimit, int sig, core_content_t content); 22087c478bd9Sstevel@tonic-gate 22097c478bd9Sstevel@tonic-gate static struct execsw esw32 = { 22107c478bd9Sstevel@tonic-gate elf32magicstr, 22117c478bd9Sstevel@tonic-gate 0, 22127c478bd9Sstevel@tonic-gate 5, 22137c478bd9Sstevel@tonic-gate elf32exec, 22147c478bd9Sstevel@tonic-gate elf32core 22157c478bd9Sstevel@tonic-gate }; 22167c478bd9Sstevel@tonic-gate 22177c478bd9Sstevel@tonic-gate static struct modlexec modlexec32 = { 22187c478bd9Sstevel@tonic-gate &mod_execops, "32-bit exec module for elf", &esw32 22197c478bd9Sstevel@tonic-gate }; 22207c478bd9Sstevel@tonic-gate #endif /* _LP64 */ 22217c478bd9Sstevel@tonic-gate 22227c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = { 22237c478bd9Sstevel@tonic-gate MODREV_1, 22247c478bd9Sstevel@tonic-gate (void *)&modlexec, 22257c478bd9Sstevel@tonic-gate #ifdef _LP64 22267c478bd9Sstevel@tonic-gate (void *)&modlexec32, 22277c478bd9Sstevel@tonic-gate #endif /* _LP64 */ 22287c478bd9Sstevel@tonic-gate NULL 22297c478bd9Sstevel@tonic-gate }; 22307c478bd9Sstevel@tonic-gate 22317c478bd9Sstevel@tonic-gate int 22327c478bd9Sstevel@tonic-gate _init(void) 22337c478bd9Sstevel@tonic-gate { 22347c478bd9Sstevel@tonic-gate return (mod_install(&modlinkage)); 22357c478bd9Sstevel@tonic-gate } 22367c478bd9Sstevel@tonic-gate 22377c478bd9Sstevel@tonic-gate int 22387c478bd9Sstevel@tonic-gate _fini(void) 22397c478bd9Sstevel@tonic-gate { 22407c478bd9Sstevel@tonic-gate return (mod_remove(&modlinkage)); 22417c478bd9Sstevel@tonic-gate } 22427c478bd9Sstevel@tonic-gate 22437c478bd9Sstevel@tonic-gate int 22447c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop) 22457c478bd9Sstevel@tonic-gate { 22467c478bd9Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 22477c478bd9Sstevel@tonic-gate } 22487c478bd9Sstevel@tonic-gate 22497c478bd9Sstevel@tonic-gate #endif /* !_ELF32_COMPAT */ 2250