1*b29180b2Smycroft /* $NetBSD: linux_exec_elf32.c,v 1.50 2000/12/15 06:14:21 mycroft Exp $ */ 28fb507a3Schristos 38fb507a3Schristos /*- 4*b29180b2Smycroft * Copyright (c) 1995, 1998, 2000 The NetBSD Foundation, Inc. 58fb507a3Schristos * All rights reserved. 68fb507a3Schristos * 78fb507a3Schristos * This code is derived from software contributed to The NetBSD Foundation 88096c25aSfvdl * by Christos Zoulas, Frank van der Linden and Eric Haszlakiewicz. 98fb507a3Schristos * 108fb507a3Schristos * Redistribution and use in source and binary forms, with or without 118fb507a3Schristos * modification, are permitted provided that the following conditions 128fb507a3Schristos * are met: 138fb507a3Schristos * 1. Redistributions of source code must retain the above copyright 148fb507a3Schristos * notice, this list of conditions and the following disclaimer. 158fb507a3Schristos * 2. Redistributions in binary form must reproduce the above copyright 168fb507a3Schristos * notice, this list of conditions and the following disclaimer in the 178fb507a3Schristos * documentation and/or other materials provided with the distribution. 188fb507a3Schristos * 3. All advertising materials mentioning features or use of this software 198fb507a3Schristos * must display the following acknowledgement: 208fb507a3Schristos * This product includes software developed by the NetBSD 218fb507a3Schristos * Foundation, Inc. and its contributors. 228fb507a3Schristos * 4. Neither the name of The NetBSD Foundation nor the names of its 238fb507a3Schristos * contributors may be used to endorse or promote products derived 248fb507a3Schristos * from this software without specific prior written permission. 258fb507a3Schristos * 268fb507a3Schristos * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 278fb507a3Schristos * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 288fb507a3Schristos * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 298fb507a3Schristos * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 308fb507a3Schristos * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 318fb507a3Schristos * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 328fb507a3Schristos * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 338fb507a3Schristos * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 348fb507a3Schristos * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 358fb507a3Schristos * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 368fb507a3Schristos * POSSIBILITY OF SUCH DAMAGE. 378fb507a3Schristos */ 383bf459f3Sfvdl 393bf459f3Sfvdl /* 40fb777788Sfvdl * based on exec_aout.c, sunos_exec.c and svr4_exec.c 413bf459f3Sfvdl */ 423bf459f3Sfvdl 43f7ac1bd3Serh #ifndef ELFSIZE 447c325577Scgd #define ELFSIZE 32 /* XXX should die */ 45f7ac1bd3Serh #endif 469c3e274cScgd 473bf459f3Sfvdl #include <sys/param.h> 483bf459f3Sfvdl #include <sys/systm.h> 493bf459f3Sfvdl #include <sys/kernel.h> 503bf459f3Sfvdl #include <sys/proc.h> 513bf459f3Sfvdl #include <sys/malloc.h> 523bf459f3Sfvdl #include <sys/namei.h> 533bf459f3Sfvdl #include <sys/vnode.h> 54151fa70fSchristos #include <sys/mount.h> 55d551a4edSchristos #include <sys/exec.h> 56c4aaa600Sfvdl #include <sys/exec_elf.h> 573bf459f3Sfvdl 583bf459f3Sfvdl #include <sys/mman.h> 59151fa70fSchristos #include <sys/syscallargs.h> 60151fa70fSchristos 613bf459f3Sfvdl #include <machine/cpu.h> 623bf459f3Sfvdl #include <machine/reg.h> 633bf459f3Sfvdl 64908291d2Schristos #include <compat/linux/common/linux_types.h> 65908291d2Schristos #include <compat/linux/common/linux_signal.h> 66908291d2Schristos #include <compat/linux/common/linux_util.h> 67908291d2Schristos #include <compat/linux/common/linux_exec.h> 68908291d2Schristos #include <compat/linux/common/linux_machdep.h> 693bf459f3Sfvdl 70908291d2Schristos #include <compat/linux/linux_syscallargs.h> 71908291d2Schristos #include <compat/linux/linux_syscall.h> 72fc7cfb5fSfvdl 73f7ac1bd3Serh static int ELFNAME2(linux,signature) __P((struct proc *, struct exec_package *, 74*b29180b2Smycroft Elf_Ehdr *, char *)); 75f7ac1bd3Serh #ifdef LINUX_GCC_SIGNATURE 76f7ac1bd3Serh static int ELFNAME2(linux,gcc_signature) __P((struct proc *p, 77f7ac1bd3Serh struct exec_package *, Elf_Ehdr *)); 78f7ac1bd3Serh #endif 79f7ac1bd3Serh 80f7ac1bd3Serh #ifdef LINUX_GCC_SIGNATURE 814d9a6e09Schristos /* 824d9a6e09Schristos * Take advantage of the fact that all the linux binaries are compiled 834d9a6e09Schristos * with gcc, and gcc sticks in the comment field a signature. Note that 844d9a6e09Schristos * on SVR4 binaries, the gcc signature will follow the OS name signature, 854d9a6e09Schristos * that will not be a problem. We don't bother to read in the string table, 864d9a6e09Schristos * but we check all the progbits headers. 87f7ac1bd3Serh * 88f7ac1bd3Serh * XXX This only works in the i386. On the alpha (at least) 89f7ac1bd3Serh * XXX we have the same gcc signature which incorrectly identifies 90f7ac1bd3Serh * XXX NetBSD binaries as Linux. 914d9a6e09Schristos */ 924d9a6e09Schristos static int 93f7ac1bd3Serh ELFNAME2(linux,gcc_signature)(p, epp, eh) 94fc7cfb5fSfvdl struct proc *p; 95fc7cfb5fSfvdl struct exec_package *epp; 96f7ac1bd3Serh Elf_Ehdr *eh; 974d9a6e09Schristos { 98*b29180b2Smycroft size_t shsize; 994d9a6e09Schristos size_t i; 1004d9a6e09Schristos static const char signature[] = "\0GCC: (GNU) "; 1014d9a6e09Schristos char buf[sizeof(signature) - 1]; 102f7ac1bd3Serh Elf_Shdr *sh; 1034d9a6e09Schristos int error; 1044d9a6e09Schristos 105*b29180b2Smycroft shsize = eh->e_shnum * sizeof(Elf_Shdr); 106f7ac1bd3Serh sh = (Elf_Shdr *) malloc(shsize, M_TEMP, M_WAITOK); 107*b29180b2Smycroft error = ELFNAME(read_from)(p, epp->ep_vp, eh->e_shoff, (caddr_t)sh, 108*b29180b2Smycroft shsize); 109*b29180b2Smycroft if (error) 1104d9a6e09Schristos goto out; 1114d9a6e09Schristos 1124d9a6e09Schristos for (i = 0; i < eh->e_shnum; i++) { 113f7ac1bd3Serh Elf_Shdr *s = &sh[i]; 1144d9a6e09Schristos 1154d9a6e09Schristos /* 1164d9a6e09Schristos * Identify candidates for the comment header; 117d83602c1Schristos * Header cannot have a load address, or flags and 1184d9a6e09Schristos * it must be large enough. 1194d9a6e09Schristos */ 120522cbf02Skleink if (s->sh_type != SHT_PROGBITS || 1214d9a6e09Schristos s->sh_addr != 0 || 1224d9a6e09Schristos s->sh_flags != 0 || 1234d9a6e09Schristos s->sh_size < sizeof(signature) - 1) 1244d9a6e09Schristos continue; 1254d9a6e09Schristos 126*b29180b2Smycroft error = ELFNAME(read_from)(p, epp->ep_vp, s->sh_offset, 127*b29180b2Smycroft (caddr_t)buf, sizeof(signature) - 1); 128*b29180b2Smycroft if (error) 129*b29180b2Smycroft continue; 1304d9a6e09Schristos 131d83602c1Schristos /* 132d83602c1Schristos * error is 0, if the signatures match we are done. 133d83602c1Schristos */ 1348b351f01Serh #ifdef DEBUG_LINUX 1358b351f01Serh printf("linux_gcc_sig: sig=%s\n", buf); 1368b351f01Serh #endif 137*b29180b2Smycroft if (!memcmp(buf, signature, sizeof(signature) - 1)) { 138*b29180b2Smycroft error = 0; 1394d9a6e09Schristos goto out; 1404d9a6e09Schristos } 141*b29180b2Smycroft } 142*b29180b2Smycroft error = ENOEXEC; 1434d9a6e09Schristos 1444d9a6e09Schristos out: 1454d9a6e09Schristos free(sh, M_TEMP); 146*b29180b2Smycroft return (error); 1474d9a6e09Schristos } 148f7ac1bd3Serh #endif 1494d9a6e09Schristos 150f7ac1bd3Serh static int 151*b29180b2Smycroft ELFNAME2(linux,signature)(p, epp, eh, itp) 1524d9a6e09Schristos struct proc *p; 1534d9a6e09Schristos struct exec_package *epp; 154f7ac1bd3Serh Elf_Ehdr *eh; 155*b29180b2Smycroft char *itp; 156f7ac1bd3Serh { 157f7ac1bd3Serh size_t i; 158f7ac1bd3Serh Elf_Phdr *ph; 159f7ac1bd3Serh size_t phsize; 160*b29180b2Smycroft int error; 161f7ac1bd3Serh 162f7ac1bd3Serh phsize = eh->e_phnum * sizeof(Elf_Phdr); 163f7ac1bd3Serh ph = (Elf_Phdr *)malloc(phsize, M_TEMP, M_WAITOK); 164*b29180b2Smycroft error = ELFNAME(read_from)(p, epp->ep_vp, eh->e_phoff, (caddr_t)ph, 165*b29180b2Smycroft phsize); 166*b29180b2Smycroft if (error) 167*b29180b2Smycroft goto out; 168f7ac1bd3Serh 169f7ac1bd3Serh for (i = 0; i < eh->e_phnum; i++) { 170f7ac1bd3Serh Elf_Phdr *ephp = &ph[i]; 171*b29180b2Smycroft Elf_Nhdr *np; 172*b29180b2Smycroft u_int32_t *abi; 173f7ac1bd3Serh 174*b29180b2Smycroft if (ephp->p_type != PT_NOTE || 175*b29180b2Smycroft ephp->p_filesz > 1024 || 176*b29180b2Smycroft ephp->p_filesz < sizeof(Elf_Nhdr) + 20) 177f7ac1bd3Serh continue; 178f7ac1bd3Serh 179*b29180b2Smycroft np = (Elf_Nhdr *)malloc(ephp->p_filesz, M_TEMP, M_WAITOK); 180*b29180b2Smycroft error = ELFNAME(read_from)(p, epp->ep_vp, ephp->p_offset, 181*b29180b2Smycroft (caddr_t)np, ephp->p_filesz); 182*b29180b2Smycroft if (error) 183*b29180b2Smycroft goto next; 184f7ac1bd3Serh 185*b29180b2Smycroft if (np->n_type != ELF_NOTE_TYPE_ABI_TAG || 186*b29180b2Smycroft np->n_namesz != ELF_NOTE_ABI_NAMESZ || 187*b29180b2Smycroft np->n_descsz != ELF_NOTE_ABI_DESCSZ || 188*b29180b2Smycroft memcmp((caddr_t)(np + 1), ELF_NOTE_ABI_NAME, 189*b29180b2Smycroft ELF_NOTE_ABI_NAMESZ)) 190*b29180b2Smycroft goto next; 191*b29180b2Smycroft 192*b29180b2Smycroft /* Make sure the OS is Linux. */ 193*b29180b2Smycroft abi = (u_int32_t *)((caddr_t)np + sizeof(Elf_Nhdr) + 194*b29180b2Smycroft np->n_namesz); 195*b29180b2Smycroft if (abi[0] == ELF_NOTE_ABI_OS_LINUX) 196f7ac1bd3Serh error = 0; 197*b29180b2Smycroft else 198*b29180b2Smycroft error = ENOEXEC; 199*b29180b2Smycroft free(np, M_TEMP); 200*b29180b2Smycroft goto out; 201f7ac1bd3Serh 202*b29180b2Smycroft next: 203*b29180b2Smycroft free(np, M_TEMP); 204f7ac1bd3Serh continue; 205f7ac1bd3Serh } 206f7ac1bd3Serh 207*b29180b2Smycroft /* Check for certain intepreter names. */ 208*b29180b2Smycroft if (itp[0]) { 209*b29180b2Smycroft if (!strncmp(itp, "/lib/ld-linux", 13) || 210*b29180b2Smycroft !strncmp(itp, "/lib/ld.so.", 11)) 211f7ac1bd3Serh error = 0; 212*b29180b2Smycroft else 213*b29180b2Smycroft error = ENOEXEC; 214*b29180b2Smycroft goto out; 215f7ac1bd3Serh } 216f7ac1bd3Serh 217f7ac1bd3Serh error = ENOEXEC; 218*b29180b2Smycroft out: 219f7ac1bd3Serh free(ph, M_TEMP); 220*b29180b2Smycroft return (error); 221f7ac1bd3Serh } 222f7ac1bd3Serh 223f7ac1bd3Serh int 224f7ac1bd3Serh ELFNAME2(linux,probe)(p, epp, eh, itp, pos) 225f7ac1bd3Serh struct proc *p; 226f7ac1bd3Serh struct exec_package *epp; 227baae0324Sjdolecek void *eh; 228c4aaa600Sfvdl char *itp; 229baae0324Sjdolecek vaddr_t *pos; 230fc7cfb5fSfvdl { 231c8216580Schristos const char *bp; 232fc7cfb5fSfvdl int error; 233c4aaa600Sfvdl size_t len; 234fc7cfb5fSfvdl 235*b29180b2Smycroft if ((error = ELFNAME2(linux,signature)(p, epp, eh, itp)) != 0) 236f7ac1bd3Serh #ifdef LINUX_GCC_SIGNATURE 237f7ac1bd3Serh if ((error = ELFNAME2(linux,gcc_signature)(p, epp, eh)) != 0) 2384d9a6e09Schristos return error; 239f7ac1bd3Serh #else 240f7ac1bd3Serh return error; 241f7ac1bd3Serh #endif 2424d9a6e09Schristos 243c4aaa600Sfvdl if (itp[0]) { 24401040d97Sjdolecek if ((error = emul_find(p, NULL, epp->ep_esch->es_emul->e_path, 24501040d97Sjdolecek itp, &bp, 0))) 246c4aaa600Sfvdl return error; 247c4aaa600Sfvdl if ((error = copystr(bp, itp, MAXPATHLEN, &len))) 248c4aaa600Sfvdl return error; 249c8216580Schristos free((void *)bp, M_TEMP); 250fc7cfb5fSfvdl } 251f7ac1bd3Serh *pos = ELF_NO_ADDR; 2528b351f01Serh #ifdef DEBUG_LINUX 2538b351f01Serh printf("linux_probe: returning 0\n"); 2548b351f01Serh #endif 255c4aaa600Sfvdl return 0; 256fc7cfb5fSfvdl } 257c4aaa600Sfvdl 258