1*97c9d7a9Schristos /* $NetBSD: linux_exec_elf32.c,v 1.52 2001/07/14 02:05:06 christos Exp $ */ 28fb507a3Schristos 38fb507a3Schristos /*- 4ac10cf69Smanu * Copyright (c) 1995, 1998, 2000, 2001 The NetBSD Foundation, Inc. 58fb507a3Schristos * All rights reserved. 68fb507a3Schristos * 78fb507a3Schristos * This code is derived from software contributed to The NetBSD Foundation 8ac10cf69Smanu * by Christos Zoulas, Frank van der Linden, Eric Haszlakiewicz and 9ac10cf69Smanu * Emmanuel Dreyfus. 108fb507a3Schristos * 118fb507a3Schristos * Redistribution and use in source and binary forms, with or without 128fb507a3Schristos * modification, are permitted provided that the following conditions 138fb507a3Schristos * are met: 148fb507a3Schristos * 1. Redistributions of source code must retain the above copyright 158fb507a3Schristos * notice, this list of conditions and the following disclaimer. 168fb507a3Schristos * 2. Redistributions in binary form must reproduce the above copyright 178fb507a3Schristos * notice, this list of conditions and the following disclaimer in the 188fb507a3Schristos * documentation and/or other materials provided with the distribution. 198fb507a3Schristos * 3. All advertising materials mentioning features or use of this software 208fb507a3Schristos * must display the following acknowledgement: 218fb507a3Schristos * This product includes software developed by the NetBSD 228fb507a3Schristos * Foundation, Inc. and its contributors. 238fb507a3Schristos * 4. Neither the name of The NetBSD Foundation nor the names of its 248fb507a3Schristos * contributors may be used to endorse or promote products derived 258fb507a3Schristos * from this software without specific prior written permission. 268fb507a3Schristos * 278fb507a3Schristos * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 288fb507a3Schristos * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 298fb507a3Schristos * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 308fb507a3Schristos * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 318fb507a3Schristos * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 328fb507a3Schristos * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 338fb507a3Schristos * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 348fb507a3Schristos * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 358fb507a3Schristos * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 368fb507a3Schristos * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 378fb507a3Schristos * POSSIBILITY OF SUCH DAMAGE. 388fb507a3Schristos */ 393bf459f3Sfvdl 403bf459f3Sfvdl /* 41fb777788Sfvdl * based on exec_aout.c, sunos_exec.c and svr4_exec.c 423bf459f3Sfvdl */ 433bf459f3Sfvdl 44f7ac1bd3Serh #ifndef ELFSIZE 457c325577Scgd #define ELFSIZE 32 /* XXX should die */ 46f7ac1bd3Serh #endif 479c3e274cScgd 483bf459f3Sfvdl #include <sys/param.h> 493bf459f3Sfvdl #include <sys/systm.h> 503bf459f3Sfvdl #include <sys/kernel.h> 513bf459f3Sfvdl #include <sys/proc.h> 523bf459f3Sfvdl #include <sys/malloc.h> 533bf459f3Sfvdl #include <sys/namei.h> 543bf459f3Sfvdl #include <sys/vnode.h> 55151fa70fSchristos #include <sys/mount.h> 56d551a4edSchristos #include <sys/exec.h> 57c4aaa600Sfvdl #include <sys/exec_elf.h> 583bf459f3Sfvdl 593bf459f3Sfvdl #include <sys/mman.h> 60151fa70fSchristos #include <sys/syscallargs.h> 61151fa70fSchristos 623bf459f3Sfvdl #include <machine/cpu.h> 633bf459f3Sfvdl #include <machine/reg.h> 643bf459f3Sfvdl 65908291d2Schristos #include <compat/linux/common/linux_types.h> 66908291d2Schristos #include <compat/linux/common/linux_signal.h> 67908291d2Schristos #include <compat/linux/common/linux_util.h> 68908291d2Schristos #include <compat/linux/common/linux_exec.h> 69908291d2Schristos #include <compat/linux/common/linux_machdep.h> 703bf459f3Sfvdl 71908291d2Schristos #include <compat/linux/linux_syscallargs.h> 72908291d2Schristos #include <compat/linux/linux_syscall.h> 73fc7cfb5fSfvdl 74f7ac1bd3Serh static int ELFNAME2(linux,signature) __P((struct proc *, struct exec_package *, 75b29180b2Smycroft Elf_Ehdr *, char *)); 76f7ac1bd3Serh #ifdef LINUX_GCC_SIGNATURE 77f7ac1bd3Serh static int ELFNAME2(linux,gcc_signature) __P((struct proc *p, 78f7ac1bd3Serh struct exec_package *, Elf_Ehdr *)); 79f7ac1bd3Serh #endif 80ac10cf69Smanu #ifdef LINUX_ATEXIT_SIGNATURE 81ac10cf69Smanu static int ELFNAME2(linux,atexit_signature) __P((struct proc *p, 82ac10cf69Smanu struct exec_package *, Elf_Ehdr *)); 83ac10cf69Smanu #endif 84ac10cf69Smanu 85ac10cf69Smanu #ifdef LINUX_ATEXIT_SIGNATURE 86ac10cf69Smanu /* 87ac10cf69Smanu * On the PowerPC, statically linked Linux binaries are not recognized 88ac10cf69Smanu * by linux_signature nor by linux_gcc_signature. Fortunately, thoses 89ac10cf69Smanu * binaries features a __libc_atexit ELF section. We therefore assume we 90ac10cf69Smanu * have a Linux binary if we find this section. 91ac10cf69Smanu */ 92ac10cf69Smanu static int 93ac10cf69Smanu ELFNAME2(linux,atexit_signature)(p, epp, eh) 94ac10cf69Smanu struct proc *p; 95ac10cf69Smanu struct exec_package *epp; 96ac10cf69Smanu Elf_Ehdr *eh; 97ac10cf69Smanu { 98ac10cf69Smanu size_t shsize; 99ac10cf69Smanu int strndx; 100ac10cf69Smanu size_t i; 101ac10cf69Smanu static const char signature[] = "__libc_atexit"; 102ac10cf69Smanu char* strtable; 103ac10cf69Smanu Elf_Shdr *sh; 104ac10cf69Smanu 105ac10cf69Smanu int error; 106ac10cf69Smanu 107ac10cf69Smanu /* 108ac10cf69Smanu * load the section header table 109ac10cf69Smanu */ 110ac10cf69Smanu shsize = eh->e_shnum * sizeof(Elf_Shdr); 111ac10cf69Smanu sh = (Elf_Shdr *) malloc(shsize, M_TEMP, M_WAITOK); 112*97c9d7a9Schristos error = exec_read_from(p, epp->ep_vp, eh->e_shoff, sh, shsize); 113ac10cf69Smanu if (error) 114ac10cf69Smanu goto out; 115ac10cf69Smanu 116ac10cf69Smanu /* 117ac10cf69Smanu * Now let's find the string table. If it does not exists, give up. 118ac10cf69Smanu */ 119ac10cf69Smanu strndx = (int)(eh->e_shstrndx); 120ac10cf69Smanu if (strndx == SHN_UNDEF) { 121ac10cf69Smanu error = ENOEXEC; 122ac10cf69Smanu goto out; 123ac10cf69Smanu } 124ac10cf69Smanu 125ac10cf69Smanu /* 126*97c9d7a9Schristos * strndx is the index in section header table of the string table 127*97c9d7a9Schristos * section get the whole string table in strtable, and then we get access to the names 128ac10cf69Smanu * s->sh_name is the offset of the section name in strtable. 129ac10cf69Smanu */ 130ac10cf69Smanu strtable = malloc(sh[strndx].sh_size, M_TEMP, M_WAITOK); 131*97c9d7a9Schristos error = exec_read_from(p, epp->ep_vp, sh[strndx].sh_offset, strtable, 132*97c9d7a9Schristos sh[strndx].sh_size); 133ac10cf69Smanu if (error) 134ac10cf69Smanu goto out; 135ac10cf69Smanu 136ac10cf69Smanu for (i = 0; i < eh->e_shnum; i++) { 137ac10cf69Smanu Elf_Shdr *s = &sh[i]; 138ac10cf69Smanu if (!memcmp((void*)(&(strtable[s->sh_name])), signature, 139ac10cf69Smanu sizeof(signature))) { 140ac10cf69Smanu #ifdef DEBUG_LINUX 141ac10cf69Smanu printf("linux_atexit_sig=%s\n",&(strtable[s->sh_name])); 142ac10cf69Smanu #endif 143ac10cf69Smanu error = 0; 144ac10cf69Smanu goto out; 145ac10cf69Smanu } 146ac10cf69Smanu } 147ac10cf69Smanu error = ENOEXEC; 148ac10cf69Smanu 149ac10cf69Smanu out: 150ac10cf69Smanu free(sh, M_TEMP); 151ac10cf69Smanu free(strtable, M_TEMP); 152ac10cf69Smanu return (error); 153ac10cf69Smanu } 154ac10cf69Smanu #endif 155f7ac1bd3Serh 156f7ac1bd3Serh #ifdef LINUX_GCC_SIGNATURE 1574d9a6e09Schristos /* 1584d9a6e09Schristos * Take advantage of the fact that all the linux binaries are compiled 1594d9a6e09Schristos * with gcc, and gcc sticks in the comment field a signature. Note that 1604d9a6e09Schristos * on SVR4 binaries, the gcc signature will follow the OS name signature, 1614d9a6e09Schristos * that will not be a problem. We don't bother to read in the string table, 1624d9a6e09Schristos * but we check all the progbits headers. 163f7ac1bd3Serh * 164f7ac1bd3Serh * XXX This only works in the i386. On the alpha (at least) 165f7ac1bd3Serh * XXX we have the same gcc signature which incorrectly identifies 166f7ac1bd3Serh * XXX NetBSD binaries as Linux. 1674d9a6e09Schristos */ 1684d9a6e09Schristos static int 169f7ac1bd3Serh ELFNAME2(linux,gcc_signature)(p, epp, eh) 170fc7cfb5fSfvdl struct proc *p; 171fc7cfb5fSfvdl struct exec_package *epp; 172f7ac1bd3Serh Elf_Ehdr *eh; 1734d9a6e09Schristos { 174b29180b2Smycroft size_t shsize; 1754d9a6e09Schristos size_t i; 1764d9a6e09Schristos static const char signature[] = "\0GCC: (GNU) "; 1774d9a6e09Schristos char buf[sizeof(signature) - 1]; 178f7ac1bd3Serh Elf_Shdr *sh; 1794d9a6e09Schristos int error; 1804d9a6e09Schristos 181b29180b2Smycroft shsize = eh->e_shnum * sizeof(Elf_Shdr); 182f7ac1bd3Serh sh = (Elf_Shdr *) malloc(shsize, M_TEMP, M_WAITOK); 183*97c9d7a9Schristos error = exec_read_from(p, epp->ep_vp, eh->e_shoff, sh, shsize); 184b29180b2Smycroft if (error) 1854d9a6e09Schristos goto out; 1864d9a6e09Schristos 1874d9a6e09Schristos for (i = 0; i < eh->e_shnum; i++) { 188f7ac1bd3Serh Elf_Shdr *s = &sh[i]; 1894d9a6e09Schristos 1904d9a6e09Schristos /* 1914d9a6e09Schristos * Identify candidates for the comment header; 192d83602c1Schristos * Header cannot have a load address, or flags and 1934d9a6e09Schristos * it must be large enough. 1944d9a6e09Schristos */ 195522cbf02Skleink if (s->sh_type != SHT_PROGBITS || 1964d9a6e09Schristos s->sh_addr != 0 || 1974d9a6e09Schristos s->sh_flags != 0 || 1984d9a6e09Schristos s->sh_size < sizeof(signature) - 1) 1994d9a6e09Schristos continue; 2004d9a6e09Schristos 201*97c9d7a9Schristos error = exec_read_from(p, epp->ep_vp, s->sh_offset, buf, 202*97c9d7a9Schristos sizeof(signature) - 1); 203b29180b2Smycroft if (error) 204b29180b2Smycroft continue; 2054d9a6e09Schristos 206d83602c1Schristos /* 207d83602c1Schristos * error is 0, if the signatures match we are done. 208d83602c1Schristos */ 2098b351f01Serh #ifdef DEBUG_LINUX 2108b351f01Serh printf("linux_gcc_sig: sig=%s\n", buf); 2118b351f01Serh #endif 212b29180b2Smycroft if (!memcmp(buf, signature, sizeof(signature) - 1)) { 213b29180b2Smycroft error = 0; 2144d9a6e09Schristos goto out; 2154d9a6e09Schristos } 216b29180b2Smycroft } 217b29180b2Smycroft error = ENOEXEC; 2184d9a6e09Schristos 2194d9a6e09Schristos out: 2204d9a6e09Schristos free(sh, M_TEMP); 221b29180b2Smycroft return (error); 2224d9a6e09Schristos } 223f7ac1bd3Serh #endif 2244d9a6e09Schristos 225f7ac1bd3Serh static int 226b29180b2Smycroft ELFNAME2(linux,signature)(p, epp, eh, itp) 2274d9a6e09Schristos struct proc *p; 2284d9a6e09Schristos struct exec_package *epp; 229f7ac1bd3Serh Elf_Ehdr *eh; 230b29180b2Smycroft char *itp; 231f7ac1bd3Serh { 232f7ac1bd3Serh size_t i; 233f7ac1bd3Serh Elf_Phdr *ph; 234f7ac1bd3Serh size_t phsize; 235b29180b2Smycroft int error; 236f7ac1bd3Serh 237f7ac1bd3Serh phsize = eh->e_phnum * sizeof(Elf_Phdr); 238f7ac1bd3Serh ph = (Elf_Phdr *)malloc(phsize, M_TEMP, M_WAITOK); 239*97c9d7a9Schristos error = exec_read_from(p, epp->ep_vp, eh->e_phoff, ph, phsize); 240b29180b2Smycroft if (error) 241b29180b2Smycroft goto out; 242f7ac1bd3Serh 243f7ac1bd3Serh for (i = 0; i < eh->e_phnum; i++) { 244f7ac1bd3Serh Elf_Phdr *ephp = &ph[i]; 245b29180b2Smycroft Elf_Nhdr *np; 246b29180b2Smycroft u_int32_t *abi; 247f7ac1bd3Serh 248b29180b2Smycroft if (ephp->p_type != PT_NOTE || 249b29180b2Smycroft ephp->p_filesz > 1024 || 250b29180b2Smycroft ephp->p_filesz < sizeof(Elf_Nhdr) + 20) 251f7ac1bd3Serh continue; 252f7ac1bd3Serh 253b29180b2Smycroft np = (Elf_Nhdr *)malloc(ephp->p_filesz, M_TEMP, M_WAITOK); 254*97c9d7a9Schristos error = exec_read_from(p, epp->ep_vp, ephp->p_offset, np, 255*97c9d7a9Schristos ephp->p_filesz); 256b29180b2Smycroft if (error) 257b29180b2Smycroft goto next; 258f7ac1bd3Serh 259b29180b2Smycroft if (np->n_type != ELF_NOTE_TYPE_ABI_TAG || 260b29180b2Smycroft np->n_namesz != ELF_NOTE_ABI_NAMESZ || 261b29180b2Smycroft np->n_descsz != ELF_NOTE_ABI_DESCSZ || 262b29180b2Smycroft memcmp((caddr_t)(np + 1), ELF_NOTE_ABI_NAME, 263b29180b2Smycroft ELF_NOTE_ABI_NAMESZ)) 264b29180b2Smycroft goto next; 265b29180b2Smycroft 266b29180b2Smycroft /* Make sure the OS is Linux. */ 267b29180b2Smycroft abi = (u_int32_t *)((caddr_t)np + sizeof(Elf_Nhdr) + 268b29180b2Smycroft np->n_namesz); 269b29180b2Smycroft if (abi[0] == ELF_NOTE_ABI_OS_LINUX) 270f7ac1bd3Serh error = 0; 271b29180b2Smycroft else 272b29180b2Smycroft error = ENOEXEC; 273b29180b2Smycroft free(np, M_TEMP); 274b29180b2Smycroft goto out; 275f7ac1bd3Serh 276b29180b2Smycroft next: 277b29180b2Smycroft free(np, M_TEMP); 278f7ac1bd3Serh continue; 279f7ac1bd3Serh } 280f7ac1bd3Serh 281b29180b2Smycroft /* Check for certain intepreter names. */ 282b29180b2Smycroft if (itp[0]) { 283b29180b2Smycroft if (!strncmp(itp, "/lib/ld-linux", 13) || 284b29180b2Smycroft !strncmp(itp, "/lib/ld.so.", 11)) 285f7ac1bd3Serh error = 0; 286b29180b2Smycroft else 287b29180b2Smycroft error = ENOEXEC; 288b29180b2Smycroft goto out; 289f7ac1bd3Serh } 290f7ac1bd3Serh 291f7ac1bd3Serh error = ENOEXEC; 292b29180b2Smycroft out: 293f7ac1bd3Serh free(ph, M_TEMP); 294b29180b2Smycroft return (error); 295f7ac1bd3Serh } 296f7ac1bd3Serh 297f7ac1bd3Serh int 298f7ac1bd3Serh ELFNAME2(linux,probe)(p, epp, eh, itp, pos) 299f7ac1bd3Serh struct proc *p; 300f7ac1bd3Serh struct exec_package *epp; 301baae0324Sjdolecek void *eh; 302c4aaa600Sfvdl char *itp; 303baae0324Sjdolecek vaddr_t *pos; 304fc7cfb5fSfvdl { 305c8216580Schristos const char *bp; 306fc7cfb5fSfvdl int error; 307c4aaa600Sfvdl size_t len; 308fc7cfb5fSfvdl 309f7ac1bd3Serh #ifdef LINUX_GCC_SIGNATURE 310ac10cf69Smanu if ((error = ELFNAME2(linux,signature)(p, epp, eh, itp)) != 0) 311f7ac1bd3Serh if ((error = ELFNAME2(linux,gcc_signature)(p, epp, eh)) != 0) 3124d9a6e09Schristos return error; 313f7ac1bd3Serh #else 314ac10cf69Smanu #ifdef LINUX_ATEXIT_SIGNATURE 315ac10cf69Smanu if ((error = ELFNAME2(linux,signature)(p, epp, eh, itp)) != 0) 316ac10cf69Smanu if ((error = ELFNAME2(linux,atexit_signature)(p, epp, eh)) != 0) 317f7ac1bd3Serh return error; 318ac10cf69Smanu #else 319ac10cf69Smanu if ((error = ELFNAME2(linux,signature)(p, epp, eh, itp)) != 0) 320ac10cf69Smanu return error; 321ac10cf69Smanu #endif 322f7ac1bd3Serh #endif 3234d9a6e09Schristos 324c4aaa600Sfvdl if (itp[0]) { 32501040d97Sjdolecek if ((error = emul_find(p, NULL, epp->ep_esch->es_emul->e_path, 32601040d97Sjdolecek itp, &bp, 0))) 327c4aaa600Sfvdl return error; 328c4aaa600Sfvdl if ((error = copystr(bp, itp, MAXPATHLEN, &len))) 329c4aaa600Sfvdl return error; 330c8216580Schristos free((void *)bp, M_TEMP); 331fc7cfb5fSfvdl } 332f7ac1bd3Serh *pos = ELF_NO_ADDR; 3338b351f01Serh #ifdef DEBUG_LINUX 3348b351f01Serh printf("linux_probe: returning 0\n"); 3358b351f01Serh #endif 336c4aaa600Sfvdl return 0; 337fc7cfb5fSfvdl } 338c4aaa600Sfvdl 339