exec_elf32.c revision 1.46
11.65.14.6Sskrll/* $NetBSD: exec_elf32.c,v 1.46 1999/10/25 13:55:07 kleink Exp $ */ 21.65.14.6Sskrll 31.1Stshiozak/*- 41.65.14.6Sskrll * Copyright (c) 1994 The NetBSD Foundation, Inc. 51.1Stshiozak * All rights reserved. 61.1Stshiozak * 71.1Stshiozak * This code is derived from software contributed to The NetBSD Foundation 81.61Smrg * by Christos Zoulas. 91.61Smrg * 101.61Smrg * Redistribution and use in source and binary forms, with or without 111.1Stshiozak * modification, are permitted provided that the following conditions 121.1Stshiozak * are met: 131.1Stshiozak * 1. Redistributions of source code must retain the above copyright 141.1Stshiozak * notice, this list of conditions and the following disclaimer. 151.1Stshiozak * 2. Redistributions in binary form must reproduce the above copyright 161.1Stshiozak * notice, this list of conditions and the following disclaimer in the 171.1Stshiozak * documentation and/or other materials provided with the distribution. 181.1Stshiozak * 3. All advertising materials mentioning features or use of this software 191.1Stshiozak * must display the following acknowledgement: 201.1Stshiozak * This product includes software developed by the NetBSD 211.1Stshiozak * Foundation, Inc. and its contributors. 221.1Stshiozak * 4. Neither the name of The NetBSD Foundation nor the names of its 231.1Stshiozak * contributors may be used to endorse or promote products derived 241.1Stshiozak * from this software without specific prior written permission. 251.1Stshiozak * 261.1Stshiozak * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 271.1Stshiozak * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 281.1Stshiozak * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 291.1Stshiozak * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 301.1Stshiozak * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 311.1Stshiozak * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 321.1Stshiozak * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 331.10Slukem * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 341.10Slukem * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 351.65.14.6Sskrll * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 361.1Stshiozak * POSSIBILITY OF SUCH DAMAGE. 371.26Schap */ 381.1Stshiozak 391.1Stshiozak/* 401.1Stshiozak * Copyright (c) 1996 Christopher G. Demetriou 411.52Smrg * All rights reserved. 421.1Stshiozak * 431.1Stshiozak * Redistribution and use in source and binary forms, with or without 441.1Stshiozak * modification, are permitted provided that the following conditions 451.1Stshiozak * are met: 461.1Stshiozak * 1. Redistributions of source code must retain the above copyright 471.1Stshiozak * notice, this list of conditions and the following disclaimer. 481.1Stshiozak * 2. Redistributions in binary form must reproduce the above copyright 491.1Stshiozak * notice, this list of conditions and the following disclaimer in the 501.32Sad * documentation and/or other materials provided with the distribution. 511.26Schap * 3. The name of the author may not be used to endorse or promote products 521.1Stshiozak * derived from this software without specific prior written permission 531.1Stshiozak * 541.1Stshiozak * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 551.1Stshiozak * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 561.62Sjdc * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 571.1Stshiozak * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 581.1Stshiozak * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 591.1Stshiozak * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 601.1Stshiozak * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 611.65.14.6Sskrll * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 621.65.14.6Sskrll * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 631.65.14.6Sskrll * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 641.65.14.6Sskrll */ 651.65.14.6Sskrll 661.65.14.6Sskrll/* If not included by exec_elf64.c, ELFSIZE won't be defined. */ 671.65.14.6Sskrll#ifndef ELFSIZE 681.65.14.6Sskrll#define ELFSIZE 32 691.65.14.6Sskrll#endif 701.65.14.6Sskrll 711.65.14.6Sskrll#include "opt_compat_linux.h" 721.65.14.6Sskrll#include "opt_compat_ibcs2.h" 731.65.14.6Sskrll#include "opt_compat_svr4.h" 741.65.14.6Sskrll#include "opt_compat_freebsd.h" 751.65.14.6Sskrll 761.65.14.6Sskrll#include <sys/param.h> 771.65.14.6Sskrll#include <sys/systm.h> 781.65.14.6Sskrll#include <sys/kernel.h> 791.65.14.6Sskrll#include <sys/proc.h> 801.65.14.6Sskrll#include <sys/malloc.h> 811.65.14.6Sskrll#include <sys/namei.h> 821.65.14.6Sskrll#include <sys/vnode.h> 831.65.14.6Sskrll#include <sys/exec.h> 841.65.14.6Sskrll#include <sys/exec_elf.h> 851.65.14.6Sskrll#include <sys/fcntl.h> 861.65.14.6Sskrll#include <sys/syscall.h> 871.65.14.6Sskrll#include <sys/signalvar.h> 881.65.14.6Sskrll#include <sys/mount.h> 891.65.14.6Sskrll#include <sys/stat.h> 901.65.14.6Sskrll 911.65.14.6Sskrll#include <sys/mman.h> 921.65.14.6Sskrll#include <vm/vm.h> 931.65.14.6Sskrll#include <vm/vm_param.h> 941.65.14.6Sskrll#include <vm/vm_map.h> 951.65.14.6Sskrll 961.65.14.6Sskrll#include <machine/cpu.h> 971.65.14.6Sskrll#include <machine/reg.h> 981.65.14.6Sskrll 991.65.14.6Sskrll#ifdef COMPAT_LINUX 1001.65.14.6Sskrll#include <compat/linux/common/linux_exec.h> 1011.65.14.6Sskrll#endif 1021.65.14.6Sskrll 1031.65.14.6Sskrll#ifdef COMPAT_SVR4 1041.65.14.6Sskrll#include <compat/svr4/svr4_exec.h> 1051.65.14.6Sskrll#endif 1061.65.14.6Sskrll 1071.65.14.6Sskrll#ifdef COMPAT_IBCS2 1081.65.14.6Sskrll#include <compat/ibcs2/ibcs2_exec.h> 1091.65.14.6Sskrll#endif 1101.65.14.6Sskrll 1111.65.14.6Sskrll#ifdef COMPAT_FREEBSD 1121.65.14.6Sskrll#include <compat/freebsd/freebsd_exec.h> 1131.65.14.6Sskrll#endif 1141.65.14.6Sskrll 1151.65.14.6Sskrllint ELFNAME(check_header) __P((Elf_Ehdr *, int)); 1161.65.14.6Sskrllint ELFNAME(load_file) __P((struct proc *, struct exec_package *, char *, 1171.65.14.6Sskrll struct exec_vmcmd_set *, u_long *, struct elf_args *, Elf_Addr *)); 1181.65.14.6Sskrllvoid ELFNAME(load_psection) __P((struct exec_vmcmd_set *, struct vnode *, 1191.65.14.6Sskrll Elf_Phdr *, Elf_Addr *, u_long *, int *)); 1201.65.14.6Sskrll 1211.65.14.6Sskrllstatic int ELFNAME2(netbsd,signature) __P((struct proc *, struct exec_package *, 1221.65.14.6Sskrll Elf_Ehdr *)); 1231.65.14.6Sskrllstatic int ELFNAME2(netbsd,probe) __P((struct proc *, struct exec_package *, 1241.65.14.6Sskrll Elf_Ehdr *, char *, Elf_Addr *)); 1251.65.14.6Sskrll 1261.65.14.6Sskrllextern char sigcode[], esigcode[]; 1271.65.14.6Sskrll#ifdef SYSCALL_DEBUG 1281.65.14.6Sskrllextern char *syscallnames[]; 1291.65.14.6Sskrll#endif 1301.65.14.6Sskrll 1311.65.14.6Sskrllstruct emul ELFNAMEEND(emul_netbsd) = { 1321.65.14.6Sskrll "netbsd", 1331.65.14.6Sskrll NULL, 1341.65.14.6Sskrll sendsig, 1351.65.14.6Sskrll SYS_syscall, 1361.65.14.6Sskrll SYS_MAXSYSCALL, 1371.65.14.6Sskrll sysent, 1381.65.14.6Sskrll#ifdef SYSCALL_DEBUG 1391.65.14.6Sskrll syscallnames, 1401.65.14.6Sskrll#else 1411.65.14.6Sskrll NULL, 1421.65.14.6Sskrll#endif 1431.65.14.6Sskrll howmany(ELF_AUX_ENTRIES * sizeof(AuxInfo), sizeof (char *)), 1441.65.14.6Sskrll ELFNAME(copyargs), 1451.65.14.6Sskrll setregs, 1461.65.14.6Sskrll sigcode, 1471.65.14.6Sskrll esigcode, 1481.65.14.6Sskrll}; 1491.65.14.6Sskrll 1501.65.14.6Sskrllint (*ELFNAME(probe_funcs)[]) __P((struct proc *, struct exec_package *, 1511.65.14.6Sskrll Elf_Ehdr *, char *, Elf_Addr *)) = { 1521.65.14.6Sskrll ELFNAME2(netbsd,probe), 1531.65.14.6Sskrll#if defined(COMPAT_FREEBSD) && (ELFSIZE == 32) 1541.65.14.6Sskrll ELFNAME2(freebsd,probe), /* XXX not 64-bit safe */ 1551.65.14.6Sskrll#endif 1561.65.14.6Sskrll#if defined(COMPAT_LINUX) 1571.65.14.6Sskrll ELFNAME2(linux,probe), 1581.65.14.6Sskrll#endif 1591.65.14.6Sskrll#if defined(COMPAT_SVR4) && (ELFSIZE == 32) 1601.65.14.6Sskrll ELFNAME2(svr4,probe), /* XXX not 64-bit safe */ 1611.65.14.6Sskrll#endif 1621.65.14.6Sskrll#if defined(COMPAT_IBCS2) && (ELFSIZE == 32) 1631.65.14.6Sskrll ELFNAME2(ibcs2,probe), /* XXX not 64-bit safe */ 1641.65.14.6Sskrll#endif 1651.65.14.6Sskrll}; 1661.65.14.6Sskrll 1671.65.14.6Sskrll/* round up and down to page boundaries. */ 1681.65.14.6Sskrll#define ELF_ROUND(a, b) (((a) + (b) - 1) & ~((b) - 1)) 1691.65.14.6Sskrll#define ELF_TRUNC(a, b) ((a) & ~((b) - 1)) 1701.65.14.6Sskrll 1711.65.14.6Sskrll/* 1721.65.14.6Sskrll * Copy arguments onto the stack in the normal way, but add some 1731.65.14.6Sskrll * extra information in case of dynamic binding. 1741.65.14.6Sskrll */ 1751.65.14.6Sskrllvoid * 1761.65.14.6SskrllELFNAME(copyargs)(pack, arginfo, stack, argp) 1771.65.14.6Sskrll struct exec_package *pack; 1781.65.14.6Sskrll struct ps_strings *arginfo; 1791.65.14.6Sskrll void *stack; 1801.65.14.6Sskrll void *argp; 1811.65.14.6Sskrll{ 1821.65.14.6Sskrll size_t len; 1831.65.14.6Sskrll AuxInfo ai[ELF_AUX_ENTRIES], *a; 1841.65.14.6Sskrll struct elf_args *ap; 1851.65.14.6Sskrll 1861.65.14.6Sskrll stack = copyargs(pack, arginfo, stack, argp); 1871.65.14.6Sskrll if (!stack) 1881.65.14.6Sskrll return NULL; 1891.65.14.6Sskrll 1901.65.14.6Sskrll a = ai; 1911.65.14.6Sskrll 1921.65.14.6Sskrll /* 1931.65.14.6Sskrll * Push extra arguments on the stack needed by dynamically 1941.65.14.6Sskrll * linked binaries 1951.65.14.6Sskrll */ 1961.65.14.6Sskrll if ((ap = (struct elf_args *)pack->ep_emul_arg)) { 1971.65.14.6Sskrll 1981.65.14.6Sskrll a->a_type = AT_PHDR; 1991.65.14.6Sskrll a->a_v = ap->arg_phaddr; 2001.65.14.6Sskrll a++; 2011.65.14.6Sskrll 2021.65.14.6Sskrll a->a_type = AT_PHENT; 2031.65.14.6Sskrll a->a_v = ap->arg_phentsize; 2041.65.14.6Sskrll a++; 2051.65.14.6Sskrll 2061.65.14.6Sskrll a->a_type = AT_PHNUM; 2071.65.14.6Sskrll a->a_v = ap->arg_phnum; 2081.65.14.6Sskrll a++; 2091.65.14.6Sskrll 2101.65.14.6Sskrll a->a_type = AT_PAGESZ; 2111.65.14.6Sskrll a->a_v = NBPG; 2121.65.14.6Sskrll a++; 2131.65.14.6Sskrll 2141.1Stshiozak a->a_type = AT_BASE; 2151.1Stshiozak a->a_v = ap->arg_interp; 2161.1Stshiozak a++; 2171.26Schap 2181.26Schap a->a_type = AT_FLAGS; 2191.1Stshiozak a->a_v = 0; 2201.1Stshiozak a++; 2211.1Stshiozak 2221.1Stshiozak a->a_type = AT_ENTRY; 2231.1Stshiozak a->a_v = ap->arg_entry; 2241.1Stshiozak a++; 2251.52Smrg 2261.52Smrg free((char *)ap, M_TEMP); 2271.52Smrg pack->ep_emul_arg = NULL; 2281.52Smrg } 2291.1Stshiozak 2301.1Stshiozak a->a_type = AT_NULL; 2311.1Stshiozak a->a_v = 0; 2321.1Stshiozak a++; 2331.26Schap 2341.26Schap len = (a - ai) * sizeof(AuxInfo); 2351.26Schap if (copyout(ai, stack, len)) 2361.26Schap return NULL; 2371.1Stshiozak stack = (caddr_t)stack + len; 2381.45Sjmcneill 2391.1Stshiozak return stack; 2401.3Stshiozak} 2411.3Stshiozak 2421.1Stshiozak/* 2431.1Stshiozak * elf_check_header(): 2441.1Stshiozak * 2451.1Stshiozak * Check header for validity; return 0 of ok ENOEXEC if error 2461.1Stshiozak */ 2471.1Stshiozakint 2481.1StshiozakELFNAME(check_header)(eh, type) 2491.1Stshiozak Elf_Ehdr *eh; 2501.1Stshiozak int type; 2511.1Stshiozak{ 2521.4Stshiozak 2531.4Stshiozak if (memcmp(eh->e_ident, ELFMAG, SELFMAG) != 0 || 2541.1Stshiozak eh->e_ident[EI_CLASS] != ELFCLASS) 2551.4Stshiozak 2561.4Stshiozak switch (eh->e_machine) { 2571.4Stshiozak 2581.4Stshiozak ELFDEFNNAME(MACHDEP_ID_CASES) 2591.4Stshiozak 2601.4Stshiozak default: 2611.1Stshiozak return ENOEXEC; 2621.26Schap } 2631.1Stshiozak 2641.40Sdyoung if (eh->e_type != type) 2651.1Stshiozak return ENOEXEC; 2661.1Stshiozak 2671.1Stshiozak return 0; 2681.1Stshiozak} 2691.40Sdyoung 2701.52Smrg/* 2711.1Stshiozak * elf_load_psection(): 2721.1Stshiozak * 2731.1Stshiozak * Load a psection at the appropriate address 2741.1Stshiozak */ 2751.1Stshiozakvoid 2761.1StshiozakELFNAME(load_psection)(vcset, vp, ph, addr, size, prot) 2771.1Stshiozak struct exec_vmcmd_set *vcset; 2781.1Stshiozak struct vnode *vp; 2791.1Stshiozak Elf_Phdr *ph; 2801.26Schap Elf_Addr *addr; 2811.65.14.4Sskrll u_long *size; 2821.65.14.4Sskrll int *prot; 2831.26Schap{ 2841.47Smrg u_long uaddr, msize, psize, rm, rf; 2851.1Stshiozak long diff, offset; 2861.1Stshiozak 2871.22Syamt /* 2881.45Sjmcneill * If the user specified an address, then we load there. 2891.45Sjmcneill */ 2901.45Sjmcneill if (*addr != ELFDEFNNAME(NO_ADDR)) { 2911.45Sjmcneill if (ph->p_align > 1) { 2921.45Sjmcneill *addr = ELF_ROUND(*addr, ph->p_align); 2931.1Stshiozak uaddr = ELF_TRUNC(ph->p_vaddr, ph->p_align); 2941.1Stshiozak } else 2951.26Schap uaddr = ph->p_vaddr; 2961.26Schap diff = ph->p_vaddr - uaddr; 2971.26Schap } else { 2981.26Schap *addr = uaddr = ph->p_vaddr; 2991.26Schap if (ph->p_align > 1) 3001.26Schap *addr = ELF_TRUNC(uaddr, ph->p_align); 3011.26Schap diff = uaddr - *addr; 3021.26Schap } 3031.26Schap 3041.26Schap *prot |= (ph->p_flags & PF_R) ? VM_PROT_READ : 0; 3051.26Schap *prot |= (ph->p_flags & PF_W) ? VM_PROT_WRITE : 0; 3061.26Schap *prot |= (ph->p_flags & PF_X) ? VM_PROT_EXECUTE : 0; 3071.26Schap 3081.37Scube offset = ph->p_offset - diff; 3091.34Sdyoung *size = ph->p_filesz + diff; 3101.34Sdyoung msize = ph->p_memsz + diff; 3111.34Sdyoung psize = round_page(*size); 3121.34Sdyoung 3131.34Sdyoung if ((ph->p_flags & PF_W) != 0) { 3141.37Scube /* 3151.34Sdyoung * Because the pagedvn pager can't handle zero fill of the last 3161.1Stshiozak * data page if it's not page aligned we map the last page 3171.65.14.1Sskrll * readvn. 3181.42Sdyoung */ 3191.1Stshiozak psize = trunc_page(*size); 3201.65.14.5Sskrll NEW_VMCMD(vcset, vmcmd_map_pagedvn, psize, *addr, vp, 3211.1Stshiozak offset, *prot); 3221.1Stshiozak if(psize != *size) 3231.1Stshiozak NEW_VMCMD(vcset, vmcmd_map_readvn, *size - psize, 3241.65.14.5Sskrll *addr + psize, vp, offset + psize, *prot); 3251.65.14.5Sskrll } else 3261.3Stshiozak NEW_VMCMD(vcset, vmcmd_map_pagedvn, psize, *addr, vp, 3271.1Stshiozak offset, *prot); 3281.65.14.5Sskrll 3291.65.14.5Sskrll /* 3301.3Stshiozak * Check if we need to extend the size of the segment 3311.1Stshiozak */ 3321.3Stshiozak rm = round_page(*addr + msize); 3331.1Stshiozak rf = round_page(*addr + *size); 3341.1Stshiozak 3351.65.14.1Sskrll if (rm != rf) { 3361.42Sdyoung NEW_VMCMD(vcset, vmcmd_map_zero, rm - rf, rf, NULLVP, 3371.1Stshiozak 0, *prot); 3381.42Sdyoung *size = msize; 3391.42Sdyoung } 3401.65.14.5Sskrll} 3411.23Saugustss 3421.1Stshiozak/* 3431.1Stshiozak * elf_read_from(): 3441.1Stshiozak * 3451.37Scube * Read from vnode into buffer at offset. 3461.37Scube */ 3471.44Sjakllschint 3481.44SjakllschELFNAME(read_from)(p, vp, off, buf, size) 3491.44Sjakllsch struct vnode *vp; 3501.65.14.5Sskrll u_long off; 3511.44Sjakllsch struct proc *p; 3521.23Saugustss caddr_t buf; 3531.1Stshiozak int size; 3541.65.14.5Sskrll{ 3551.65.14.5Sskrll int error; 3561.65.14.5Sskrll size_t resid; 3571.65.14.5Sskrll 3581.65.14.5Sskrll if ((error = vn_rdwr(UIO_READ, vp, buf, size, off, UIO_SYSSPACE, 3591.1Stshiozak 0, p->p_ucred, &resid, p)) != 0) 3601.37Scube return error; 3611.1Stshiozak /* 3621.1Stshiozak * See if we got all of it 3631.47Smrg */ 3641.47Smrg if (resid != 0) 3651.65.14.6Sskrll return ENOEXEC; 3661.65.14.6Sskrll return 0; 3671.1Stshiozak} 3681.1Stshiozak 3691.47Smrg/* 3701.37Scube * elf_load_file(): 3711.37Scube * 3721.65.14.6Sskrll * Load a file (interpreter/library) pointed to by path 3731.1Stshiozak * [stolen from coff_load_shlib()]. Made slightly generic 3741.1Stshiozak * so it might be used externally. 3751.47Smrg */ 3761.37Scubeint 3771.37ScubeELFNAME(load_file)(p, epp, path, vcset, entry, ap, last) 3781.65.14.6Sskrll struct proc *p; 3791.1Stshiozak struct exec_package *epp; 3801.37Scube char *path; 3811.1Stshiozak struct exec_vmcmd_set *vcset; 3821.1Stshiozak u_long *entry; 3831.1Stshiozak struct elf_args *ap; 3841.47Smrg Elf_Addr *last; 3851.37Scube{ 3861.37Scube int error, i; 3871.65.14.6Sskrll struct nameidata nd; 3881.1Stshiozak struct vnode *vp; 3891.1Stshiozak struct vattr attr; 3901.47Smrg Elf_Ehdr eh; 3911.37Scube Elf_Phdr *ph = NULL; 3921.37Scube u_long phsize; 3931.65.14.6Sskrll char *bp = NULL; 3941.1Stshiozak Elf_Addr addr = *last; 3951.1Stshiozak 3961.1Stshiozak bp = path; 3971.1Stshiozak /* 3981.1Stshiozak * 1. open file 3991.1Stshiozak * 2. read filehdr 4001.1Stshiozak * 3. map text, data, and bss out of it using VM_* 4011.42Sdyoung */ 4021.16Saugustss NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, path, p); 4031.42Sdyoung if ((error = namei(&nd)) != 0) 4041.65.14.6Sskrll return error; 4051.65.14.6Sskrll vp = nd.ni_vp; 4061.65.14.6Sskrll 4071.65.14.6Sskrll /* 4081.65.14.6Sskrll * Similarly, if it's not marked as executable, or it's not a regular 4091.65.14.6Sskrll * file, we don't allow it to be used. 4101.65.14.6Sskrll */ 4111.65.14.6Sskrll if (vp->v_type != VREG) { 4121.65.14.6Sskrll error = EACCES; 4131.37Scube goto badunlock; 4141.1Stshiozak } 4151.56Splunky if ((error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p)) != 0) 4161.42Sdyoung goto badunlock; 4171.1Stshiozak 4181.1Stshiozak /* get attributes */ 4191.34Sdyoung if ((error = VOP_GETATTR(vp, &attr, p->p_ucred, p)) != 0) 4201.34Sdyoung goto badunlock; 4211.34Sdyoung 4221.34Sdyoung /* 4231.34Sdyoung * Check mount point. Though we're not trying to exec this binary, 4241.34Sdyoung * we will be executing code from it, so if the mount point 4251.34Sdyoung * disallows execution or set-id-ness, we punt or kill the set-id. 4261.34Sdyoung */ 4271.34Sdyoung if (vp->v_mount->mnt_flag & MNT_NOEXEC) { 4281.34Sdyoung error = EACCES; 4291.34Sdyoung goto badunlock; 4301.34Sdyoung } 4311.34Sdyoung if (vp->v_mount->mnt_flag & MNT_NOSUID) 4321.34Sdyoung epp->ep_vap->va_mode &= ~(S_ISUID | S_ISGID); 4331.34Sdyoung 4341.34Sdyoung#ifdef notyet /* XXX cgd 960926 */ 4351.1Stshiozak XXX cgd 960926: (maybe) VOP_OPEN it (and VOP_CLOSE in copyargs?) 4361.34Sdyoung#endif 4371.1Stshiozak VOP_UNLOCK(vp, 0); 4381.34Sdyoung 4391.1Stshiozak if ((error = ELFNAME(read_from)(p, vp, 0, (caddr_t) &eh, 4401.1Stshiozak sizeof(eh))) != 0) 4411.1Stshiozak goto bad; 4421.1Stshiozak 4431.1Stshiozak if ((error = ELFNAME(check_header)(&eh, ET_DYN)) != 0) 4441.1Stshiozak goto bad; 4451.40Sdyoung 4461.40Sdyoung phsize = eh.e_phnum * sizeof(Elf_Phdr); 4471.40Sdyoung ph = (Elf_Phdr *)malloc(phsize, M_TEMP, M_WAITOK); 4481.40Sdyoung 4491.1Stshiozak if ((error = ELFNAME(read_from)(p, vp, eh.e_phoff, 4501.1Stshiozak (caddr_t) ph, phsize)) != 0) 4511.1Stshiozak goto bad; 4521.65.14.1Sskrll 4531.42Sdyoung /* 4541.1Stshiozak * Load all the necessary sections 4551.42Sdyoung */ 4561.1Stshiozak for (i = 0; i < eh.e_phnum; i++) { 4571.1Stshiozak u_long size = 0; 4581.1Stshiozak int prot = 0; 4591.65.14.6Sskrll 4601.1Stshiozak switch (ph[i].p_type) { 4611.65.14.6Sskrll case PT_LOAD: 4621.65.14.6Sskrll ELFNAME(load_psection)(vcset, vp, &ph[i], &addr, 4631.65.14.6Sskrll &size, &prot); 4641.65.14.6Sskrll /* If entry is within this section it must be text */ 4651.1Stshiozak if (eh.e_entry >= ph[i].p_vaddr && 4661.1Stshiozak eh.e_entry < (ph[i].p_vaddr + size)) { 4671.1Stshiozak /* XXX */ 4681.1Stshiozak *entry = addr + eh.e_entry; 4691.1Stshiozak#ifdef mips 4701.3Stshiozak *entry -= ph[i].p_vaddr; 4711.42Sdyoung#endif 4721.1Stshiozak ap->arg_interp = addr; 4731.45Sjmcneill } 4741.65.14.6Sskrll addr += size; 4751.47Smrg break; 4761.45Sjmcneill 4771.1Stshiozak case PT_DYNAMIC: 4781.1Stshiozak case PT_PHDR: 4791.1Stshiozak case PT_NOTE: 4801.1Stshiozak break; 4811.4Stshiozak 4821.4Stshiozak default: 4831.4Stshiozak break; 4841.1Stshiozak } 4851.1Stshiozak } 4861.1Stshiozak 4871.12Saugustss free((char *)ph, M_TEMP); 4881.12Saugustss *last = addr; 4891.1Stshiozak vrele(vp); 4901.1Stshiozak return 0; 4911.3Stshiozak 4921.3Stshiozakbadunlock: 4931.26Schap VOP_UNLOCK(vp, 0); 4941.1Stshiozak 4951.65.14.6Sskrllbad: 4961.1Stshiozak if (ph != NULL) 4971.1Stshiozak free((char *)ph, M_TEMP); 4981.1Stshiozak#ifdef notyet /* XXX cgd 960926 */ 4991.1Stshiozak (maybe) VOP_CLOSE it 5001.4Stshiozak#endif 5011.1Stshiozak vrele(vp); 5021.1Stshiozak return error; 5031.4Stshiozak} 5041.1Stshiozak 5051.26Schap/* 5061.26Schap * exec_elf_makecmds(): Prepare an Elf binary's exec package 5071.65.14.6Sskrll * 5081.26Schap * First, set of the various offsets/lengths in the exec package. 5091.26Schap * 5101.3Stshiozak * Then, mark the text image busy (so it can be demand paged) or error 5111.26Schap * out if this is not possible. Finally, set up vmcmds for the 5121.65.14.6Sskrll * text, data, bss, and stack segments. 5131.65.14.6Sskrll */ 5141.65.14.6Sskrllint 5151.65.14.6SskrllELFNAME2(exec,makecmds)(p, epp) 5161.65.14.6Sskrll struct proc *p; 5171.26Schap struct exec_package *epp; 5181.65.14.6Sskrll{ 5191.3Stshiozak Elf_Ehdr *eh = epp->ep_hdr; 5201.1Stshiozak Elf_Phdr *ph, *pp; 5211.1Stshiozak Elf_Addr phdr = 0, pos = 0; 5221.26Schap int error, i, n, nload; 5231.26Schap char interp[MAXPATHLEN]; 5241.26Schap u_long phsize; 5251.65.14.6Sskrll 5261.26Schap if (epp->ep_hdrvalid < sizeof(Elf_Ehdr)) 5271.1Stshiozak return ENOEXEC; 5281.1Stshiozak 5291.1Stshiozak /* 5301.1Stshiozak * XXX allow for executing shared objects. It seems silly 5311.1Stshiozak * but other ELF-based systems allow it as well. 5321.3Stshiozak */ 5331.65.14.6Sskrll if (ELFNAME(check_header)(eh, ET_EXEC) != 0 && 5341.65.14.6Sskrll ELFNAME(check_header)(eh, ET_DYN) != 0) 5351.65.14.6Sskrll return ENOEXEC; 5361.65.14.6Sskrll 5371.65.14.6Sskrll /* 5381.65.14.6Sskrll * check if vnode is in open for writing, because we want to 5391.1Stshiozak * demand-page out of it. if it is, don't do it, for various 5401.59Smrg * reasons 5411.59Smrg */ 5421.65.14.6Sskrll if (epp->ep_vp->v_writecount != 0) { 5431.57Smrg#ifdef DIAGNOSTIC 5441.1Stshiozak if (epp->ep_vp->v_flag & VTEXT) 5451.4Stshiozak panic("exec: a VTEXT vnode has writecount != 0\n"); 5461.1Stshiozak#endif 5471.4Stshiozak return ETXTBSY; 5481.57Smrg } 5491.65.14.6Sskrll /* 5501.65.14.6Sskrll * Allocate space to hold all the program headers, and read them 5511.59Smrg * from the file 5521.59Smrg */ 5531.65.14.6Sskrll phsize = eh->e_phnum * sizeof(Elf_Phdr); 5541.1Stshiozak ph = (Elf_Phdr *)malloc(phsize, M_TEMP, M_WAITOK); 5551.1Stshiozak 5561.1Stshiozak if ((error = ELFNAME(read_from)(p, epp->ep_vp, eh->e_phoff, 5571.28Schristos (caddr_t) ph, phsize)) != 0) 5581.27Schristos goto bad; 5591.26Schap 5601.26Schap epp->ep_taddr = epp->ep_tsize = ELFDEFNNAME(NO_ADDR); 5611.26Schap epp->ep_daddr = epp->ep_dsize = ELFDEFNNAME(NO_ADDR); 5621.65.14.6Sskrll 5631.65.14.6Sskrll interp[0] = '\0'; 5641.60Smrg 5651.26Schap for (i = 0; i < eh->e_phnum; i++) { 5661.65.14.1Sskrll pp = &ph[i]; 5671.26Schap if (pp->p_type == PT_INTERP) { 5681.26Schap if (pp->p_filesz >= sizeof(interp)) 5691.26Schap goto bad; 5701.26Schap if ((error = ELFNAME(read_from)(p, epp->ep_vp, 5711.28Schristos pp->p_offset, (caddr_t) interp, 5721.1Stshiozak pp->p_filesz)) != 0) 5731.3Stshiozak goto bad; 5741.26Schap break; 5751.1Stshiozak } 5761.65.14.6Sskrll } 5771.65.14.6Sskrll 5781.60Smrg /* 5791.1Stshiozak * Setup things for native emulation. 5801.1Stshiozak */ 5811.26Schap epp->ep_emul = &ELFNAMEEND(emul_netbsd); 5821.26Schap pos = ELFDEFNNAME(NO_ADDR); 5831.26Schap 5841.26Schap /* 5851.26Schap * On the same architecture, we may be emulating different systems. 5861.26Schap * See which one will accept this executable. This currently only 5871.65.14.1Sskrll * applies to SVR4, and IBCS2 on the i386 and Linux on the i386 5881.26Schap * and the Alpha. 5891.26Schap * 5901.26Schap * Probe functions would normally see if the interpreter (if any) 5911.26Schap * exists. Emulation packages may possibly replace the interpreter in 5921.26Schap * interp[] with a changed path (/emul/xxx/<path>), and also 5931.26Schap * set the ep_emul field in the exec package structure. 5941.26Schap */ 5951.26Schap n = sizeof(ELFNAME(probe_funcs)) / sizeof(ELFNAME(probe_funcs)[0]); 5961.26Schap if (n != 0) { 5971.65.14.6Sskrll error = ENOEXEC; 5981.65.14.6Sskrll for (i = 0; i < n && error; i++) 5991.60Smrg error = ELFNAME(probe_funcs)[i](p, epp, eh, 6001.26Schap interp, &pos); 6011.26Schap#ifdef notyet 6021.26Schap /* 6031.26Schap * We should really use a signature in our native binaries 6041.26Schap * and have our own probe function for matching binaries, 6051.26Schap * before trying the emulations. For now, if the emulation 6061.26Schap * probes failed we default to native. 6071.26Schap */ 6081.65.14.1Sskrll if (error) 6091.26Schap goto bad; 6101.26Schap#endif 6111.26Schap } 6121.26Schap 6131.26Schap /* 6141.26Schap * Load all the necessary sections 6151.26Schap */ 6161.26Schap for (i = nload = 0; i < eh->e_phnum; i++) { 6171.26Schap Elf_Addr addr = ELFDEFNNAME(NO_ADDR); 6181.65.14.6Sskrll u_long size = 0; 6191.65.14.6Sskrll int prot = 0; 6201.60Smrg 6211.26Schap pp = &ph[i]; 6221.26Schap 6231.26Schap switch (ph[i].p_type) { 6241.1Stshiozak case PT_LOAD: 6251.1Stshiozak /* 6261.1Stshiozak * XXX 6271.1Stshiozak * Can handle only 2 sections: text and data 6281.1Stshiozak */ 6291.3Stshiozak if (nload++ == 2) 6301.26Schap goto bad; 6311.26Schap ELFNAME(load_psection)(&epp->ep_vmcmds, epp->ep_vp, 6321.1Stshiozak &ph[i], &addr, &size, &prot); 6331.65.14.6Sskrll 6341.65.14.6Sskrll /* 6351.26Schap * Decide whether it's text or data by looking 6361.3Stshiozak * at the entry point. 6371.1Stshiozak */ 6381.1Stshiozak if (eh->e_entry >= addr && 6391.26Schap eh->e_entry < (addr + size)) { 6401.1Stshiozak epp->ep_taddr = addr; 6411.1Stshiozak epp->ep_tsize = size; 6421.45Sjmcneill if (epp->ep_daddr == ELFDEFNNAME(NO_ADDR)) { 6431.47Smrg epp->ep_daddr = addr; 6441.45Sjmcneill epp->ep_dsize = size; 6451.45Sjmcneill } 6461.45Sjmcneill } else { 6471.45Sjmcneill epp->ep_daddr = addr; 6481.47Smrg epp->ep_dsize = size; 6491.45Sjmcneill } 6501.45Sjmcneill break; 6511.1Stshiozak 6521.4Stshiozak case PT_SHLIB: 6531.4Stshiozak#ifndef COMPAT_IBCS2 /* SCO has these sections */ 6541.4Stshiozak error = ENOEXEC; 6551.1Stshiozak goto bad; 6561.3Stshiozak#endif 6571.1Stshiozak 6581.3Stshiozak case PT_INTERP: 6591.1Stshiozak /* Already did this one */ 6601.1Stshiozak case PT_DYNAMIC: 6611.1Stshiozak case PT_NOTE: 6621.26Schap break; 6631.65.14.1Sskrll 6641.26Schap case PT_PHDR: 6651.26Schap /* Note address of program headers (in text segment) */ 6661.26Schap phdr = pp->p_vaddr; 6671.26Schap break; 6681.26Schap 6691.26Schap default: 6701.26Schap /* 6711.26Schap * Not fatal; we don't need to understand everything. 6721.26Schap */ 6731.26Schap break; 6741.26Schap } 6751.26Schap } 6761.26Schap 6771.26Schap /* this breaks on, e.g., OpenBSD-compatible mips shared binaries. */ 6781.26Schap#ifndef ELF_INTERP_NON_RELOCATABLE 6791.26Schap /* 6801.26Schap * If no position to load the interpreter was set by a probe 6811.26Schap * function, pick the same address that a non-fixed mmap(0, ..) 6821.65.14.2Sskrll * would (i.e. something safely out of the way). 6831.26Schap */ 6841.26Schap if (pos == ELFDEFNNAME(NO_ADDR)) 6851.26Schap pos = round_page(epp->ep_daddr + MAXDSIZ); 6861.26Schap#endif /* !ELF_INTERP_NON_RELOCATABLE */ 6871.26Schap 6881.3Stshiozak /* 6891.11Saugustss * Check if we found a dynamically linked binary and arrange to load 6901.3Stshiozak * it's interpreter 6911.3Stshiozak */ 6921.3Stshiozak if (interp[0]) { 6931.26Schap struct elf_args *ap; 6941.11Saugustss 6951.3Stshiozak ap = (struct elf_args *)malloc(sizeof(struct elf_args), 6961.3Stshiozak M_TEMP, M_WAITOK); 6971.3Stshiozak if ((error = ELFNAME(load_file)(p, epp, interp, 6981.3Stshiozak &epp->ep_vmcmds, &epp->ep_entry, ap, &pos)) != 0) { 6991.26Schap free((char *)ap, M_TEMP); 7001.64Sjmcneill goto bad; 7011.3Stshiozak } 7021.3Stshiozak pos += phsize; 7031.65Sjmcneill ap->arg_phaddr = phdr; 7041.1Stshiozak 7051.1Stshiozak ap->arg_phentsize = eh->e_phentsize; 7061.1Stshiozak ap->arg_phnum = eh->e_phnum; 7071.1Stshiozak ap->arg_entry = eh->e_entry; 7081.1Stshiozak 7091.3Stshiozak epp->ep_emul_arg = ap; 7101.1Stshiozak } else 7111.42Sdyoung epp->ep_entry = eh->e_entry; 7121.3Stshiozak 7131.3Stshiozak#ifdef ELF_MAP_PAGE_ZERO 7141.3Stshiozak /* Dell SVR4 maps page zero, yeuch! */ 7151.32Sad NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_readvn, NBPG, 0, epp->ep_vp, 0, 7161.1Stshiozak VM_PROT_READ); 7171.1Stshiozak#endif 7181.1Stshiozak free((char *)ph, M_TEMP); 7191.1Stshiozak epp->ep_vp->v_flag |= VTEXT; 7201.1Stshiozak return exec_elf_setup_stack(p, epp); 7211.1Stshiozak 7221.1Stshiozakbad: 7231.1Stshiozak free((char *)ph, M_TEMP); 7241.1Stshiozak kill_vmcmds(&epp->ep_vmcmds); 7251.1Stshiozak return ENOEXEC; 7261.1Stshiozak} 7271.1Stshiozak 7281.3Stshiozakstatic int 7291.3StshiozakELFNAME2(netbsd,signature)(p, epp, eh) 7301.3Stshiozak struct proc *p; 7311.9Stshiozak struct exec_package *epp; 7321.3Stshiozak Elf_Ehdr *eh; 7331.3Stshiozak{ 7341.3Stshiozak Elf_Phdr *hph, *ph; 7351.3Stshiozak Elf_Nhdr *np = NULL; 7361.1Stshiozak size_t phsize; 7371.3Stshiozak int error; 7381.1Stshiozak 7391.46Smrg phsize = eh->e_phnum * sizeof(Elf_Phdr); 7401.3Stshiozak hph = (Elf_Phdr *)malloc(phsize, M_TEMP, M_WAITOK); 7411.3Stshiozak if ((error = ELFNAME(read_from)(p, epp->ep_vp, eh->e_phoff, 7421.3Stshiozak (caddr_t)hph, phsize)) != 0) 7431.52Smrg goto out1; 7441.3Stshiozak 7451.52Smrg for (ph = hph; ph < &hph[eh->e_phnum]; ph++) { 7461.52Smrg if (ph->p_type != PT_NOTE || 7471.3Stshiozak ph->p_filesz < sizeof(Elf_Nhdr) + ELF_NOTE_NETBSD_NAMESZ) 7481.52Smrg continue; 7491.3Stshiozak 7501.3Stshiozak np = (Elf_Nhdr *)malloc(ph->p_filesz, M_TEMP, M_WAITOK); 7511.3Stshiozak if ((error = ELFNAME(read_from)(p, epp->ep_vp, ph->p_offset, 7521.3Stshiozak (caddr_t)np, ph->p_filesz)) != 0) 7531.3Stshiozak goto out2; 7541.1Stshiozak 7551.1Stshiozak if (np->n_type != ELF_NOTE_TYPE_OSVERSION) { 7561.1Stshiozak free(np, M_TEMP); 7571.1Stshiozak np = NULL; 7581.1Stshiozak continue; 7591.3Stshiozak } 7601.46Smrg 7611.8Stshiozak /* Check the name and description sizes. */ 7621.46Smrg if (np->n_namesz != ELF_NOTE_NETBSD_NAMESZ || 7631.14Skent np->n_descsz != ELF_NOTE_NETBSD_DESCSZ) 7641.52Smrg goto out3; 7651.1Stshiozak 7661.1Stshiozak /* Is the name "NetBSD\0\0"? */ 7671.1Stshiozak if (memcmp((np + 1), ELF_NOTE_NETBSD_NAME, 7681.1Stshiozak ELF_NOTE_NETBSD_NAMESZ)) 7691.1Stshiozak goto out3; 7701.1Stshiozak 7711.3Stshiozak /* XXX: We could check for the specific emulation here */ 7721.38Sgmcgarry /* All checks succeeded. */ 7731.3Stshiozak error = 0; 7741.1Stshiozak goto out2; 7751.1Stshiozak } 7761.1Stshiozak 7771.1Stshiozakout3: 7781.1Stshiozak error = ENOEXEC; 7791.1Stshiozakout2: 7801.1Stshiozak if (np) 7811.1Stshiozak free(np, M_TEMP); 7821.1Stshiozakout1: 7831.52Smrg free(hph, M_TEMP); 7841.52Smrg return error; 7851.52Smrg} 7861.1Stshiozak 7871.52Smrgstatic int 7881.1StshiozakELFNAME2(netbsd,probe)(p, epp, eh, itp, pos) 7891.1Stshiozak struct proc *p; 7901.1Stshiozak struct exec_package *epp; 7911.1Stshiozak Elf_Ehdr *eh; 7921.3Stshiozak char *itp; 7931.3Stshiozak Elf_Addr *pos; 7941.52Smrg{ 7951.1Stshiozak int error; 7961.1Stshiozak 7971.1Stshiozak if ((error = ELFNAME2(netbsd,signature)(p, epp, eh)) != 0) 7981.1Stshiozak return error; 7991.37Scube 8001.37Scube epp->ep_emul = &ELFNAMEEND(emul_netbsd); 8011.37Scube *pos = ELFDEFNNAME(NO_ADDR); 8021.3Stshiozak return 0; 8031.1Stshiozak} 8041.1Stshiozak