1*c8216580Schristos /* $NetBSD: linux_exec_elf32.c,v 1.41 1999/02/09 20:37:19 christos Exp $ */ 28fb507a3Schristos 38fb507a3Schristos /*- 48096c25aSfvdl * Copyright (c) 1995, 1998 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 <vm/vm.h> 623bf459f3Sfvdl #include <vm/vm_param.h> 633bf459f3Sfvdl #include <vm/vm_map.h> 643bf459f3Sfvdl 653bf459f3Sfvdl #include <machine/cpu.h> 663bf459f3Sfvdl #include <machine/reg.h> 673bf459f3Sfvdl 68908291d2Schristos #include <compat/linux/common/linux_types.h> 69908291d2Schristos #include <compat/linux/common/linux_signal.h> 70908291d2Schristos #include <compat/linux/common/linux_util.h> 71908291d2Schristos #include <compat/linux/common/linux_exec.h> 72908291d2Schristos #include <compat/linux/common/linux_machdep.h> 734c127bdcSveego #include <compat/linux/common/linux_errno.h> 743bf459f3Sfvdl 75908291d2Schristos #include <compat/linux/linux_syscallargs.h> 76908291d2Schristos #include <compat/linux/linux_syscall.h> 77fc7cfb5fSfvdl 78f7ac1bd3Serh static int ELFNAME2(linux,signature) __P((struct proc *, struct exec_package *, 79f7ac1bd3Serh Elf_Ehdr *)); 80f7ac1bd3Serh #ifdef LINUX_GCC_SIGNATURE 81f7ac1bd3Serh static int ELFNAME2(linux,gcc_signature) __P((struct proc *p, 82f7ac1bd3Serh struct exec_package *, Elf_Ehdr *)); 83f7ac1bd3Serh #endif 84f7ac1bd3Serh 85c4aaa600Sfvdl #define LINUX_ELF_AUX_ARGSIZ (sizeof(AuxInfo) * 8 / sizeof(char *)) 86c4aaa600Sfvdl 8744eef7c2Schristos 88245f292fSmycroft extern char linux_sigcode[], linux_esigcode[]; 8944eef7c2Schristos extern struct sysent linux_sysent[]; 9044eef7c2Schristos extern char *linux_syscallnames[]; 9144eef7c2Schristos 92f7ac1bd3Serh struct emul ELFNAMEEND(emul_linux) = { 93fc7cfb5fSfvdl "linux", 948b351f01Serh native_to_linux_errno, 95fc7cfb5fSfvdl linux_sendsig, 96fc7cfb5fSfvdl LINUX_SYS_syscall, 97fc7cfb5fSfvdl LINUX_SYS_MAXSYSCALL, 98fc7cfb5fSfvdl linux_sysent, 99fc7cfb5fSfvdl linux_syscallnames, 100fc7cfb5fSfvdl LINUX_ELF_AUX_ARGSIZ, 101f7ac1bd3Serh ELFNAME(copyargs), 10272623d84Smycroft linux_setregs, 10344eef7c2Schristos linux_sigcode, 10444eef7c2Schristos linux_esigcode, 10544eef7c2Schristos }; 10644eef7c2Schristos 10744eef7c2Schristos 108f7ac1bd3Serh #ifdef LINUX_GCC_SIGNATURE 1094d9a6e09Schristos /* 1104d9a6e09Schristos * Take advantage of the fact that all the linux binaries are compiled 1114d9a6e09Schristos * with gcc, and gcc sticks in the comment field a signature. Note that 1124d9a6e09Schristos * on SVR4 binaries, the gcc signature will follow the OS name signature, 1134d9a6e09Schristos * that will not be a problem. We don't bother to read in the string table, 1144d9a6e09Schristos * but we check all the progbits headers. 115f7ac1bd3Serh * 116f7ac1bd3Serh * XXX This only works in the i386. On the alpha (at least) 117f7ac1bd3Serh * XXX we have the same gcc signature which incorrectly identifies 118f7ac1bd3Serh * XXX NetBSD binaries as Linux. 1194d9a6e09Schristos */ 1204d9a6e09Schristos static int 121f7ac1bd3Serh ELFNAME2(linux,gcc_signature)(p, epp, eh) 122fc7cfb5fSfvdl struct proc *p; 123fc7cfb5fSfvdl struct exec_package *epp; 124f7ac1bd3Serh Elf_Ehdr *eh; 1254d9a6e09Schristos { 126f7ac1bd3Serh size_t shsize = sizeof(Elf_Shdr) * eh->e_shnum; 1274d9a6e09Schristos size_t i; 1284d9a6e09Schristos static const char signature[] = "\0GCC: (GNU) "; 1294d9a6e09Schristos char buf[sizeof(signature) - 1]; 130f7ac1bd3Serh Elf_Shdr *sh; 1314d9a6e09Schristos int error; 1324d9a6e09Schristos 133f7ac1bd3Serh error = ENOEXEC; 134f7ac1bd3Serh sh = (Elf_Shdr *) malloc(shsize, M_TEMP, M_WAITOK); 1354d9a6e09Schristos 136f7ac1bd3Serh if ((error = ELFNAME(read_from)(p, epp->ep_vp, eh->e_shoff, 1374d9a6e09Schristos (caddr_t) sh, shsize)) != 0) 1384d9a6e09Schristos goto out; 1394d9a6e09Schristos 1404d9a6e09Schristos for (i = 0; i < eh->e_shnum; i++) { 141f7ac1bd3Serh Elf_Shdr *s = &sh[i]; 1424d9a6e09Schristos 1434d9a6e09Schristos /* 1444d9a6e09Schristos * Identify candidates for the comment header; 145d83602c1Schristos * Header cannot have a load address, or flags and 1464d9a6e09Schristos * it must be large enough. 1474d9a6e09Schristos */ 148fb2727b7Sjtk if (s->sh_type != Elf_sht_progbits || 1494d9a6e09Schristos s->sh_addr != 0 || 1504d9a6e09Schristos s->sh_flags != 0 || 1514d9a6e09Schristos s->sh_size < sizeof(signature) - 1) 1524d9a6e09Schristos continue; 1534d9a6e09Schristos 154f7ac1bd3Serh if ((error = ELFNAME(read_from)(p, epp->ep_vp, s->sh_offset, 155d83602c1Schristos (caddr_t) buf, sizeof(signature) - 1)) != 0) 1564d9a6e09Schristos goto out; 1574d9a6e09Schristos 158d83602c1Schristos /* 159d83602c1Schristos * error is 0, if the signatures match we are done. 160d83602c1Schristos */ 1618b351f01Serh #ifdef DEBUG_LINUX 1628b351f01Serh printf("linux_gcc_sig: sig=%s\n", buf); 1638b351f01Serh #endif 164e1601dc2Sperry if (memcmp(buf, signature, sizeof(signature) - 1) == 0) 1654d9a6e09Schristos goto out; 1664d9a6e09Schristos } 1674d9a6e09Schristos 1684d9a6e09Schristos out: 1694d9a6e09Schristos free(sh, M_TEMP); 1708b351f01Serh #ifdef DEBUG_LINUX 1718b351f01Serh printf("linux_gcc_sig: returning %d\n", error); 1728b351f01Serh #endif 1734d9a6e09Schristos return error; 1744d9a6e09Schristos } 175f7ac1bd3Serh #endif 1764d9a6e09Schristos 177f7ac1bd3Serh static int 178f7ac1bd3Serh ELFNAME2(linux,signature)(p, epp, eh) 1794d9a6e09Schristos struct proc *p; 1804d9a6e09Schristos struct exec_package *epp; 181f7ac1bd3Serh Elf_Ehdr *eh; 182f7ac1bd3Serh { 183f7ac1bd3Serh size_t i; 184f7ac1bd3Serh Elf_Phdr *ph; 185f7ac1bd3Serh Elf_Note *notep; 186f7ac1bd3Serh size_t phsize; 187f7ac1bd3Serh int error = ENOEXEC; 188f7ac1bd3Serh 189f7ac1bd3Serh phsize = eh->e_phnum * sizeof(Elf_Phdr); 190f7ac1bd3Serh ph = (Elf_Phdr *)malloc(phsize, M_TEMP, M_WAITOK); 191f7ac1bd3Serh if ((error = ELFNAME(read_from)(p, epp->ep_vp, eh->e_phoff, 192f7ac1bd3Serh (caddr_t) ph, phsize)) != 0) 193f7ac1bd3Serh goto out1; 194f7ac1bd3Serh 195f7ac1bd3Serh for (i = 0; i < eh->e_phnum; i++) { 196f7ac1bd3Serh Elf_Phdr *ephp = &ph[i]; 197f7ac1bd3Serh u_int32_t ostype; 198f7ac1bd3Serh 199f7ac1bd3Serh if (ephp->p_type != Elf_pt_interp /* XAX pt_note */ 20096dc2f3cSchristos #if 0 20196dc2f3cSchristos || ephp->p_flags != 0 20296dc2f3cSchristos || ephp->p_filesz < sizeof(Elf_Note)) 20396dc2f3cSchristos #endif 20496dc2f3cSchristos ) 205f7ac1bd3Serh continue; 206f7ac1bd3Serh 207bda91330Serh notep = (Elf_Note *)malloc(ephp->p_filesz+1, M_TEMP, M_WAITOK); 208f7ac1bd3Serh if ((error = ELFNAME(read_from)(p, epp->ep_vp, ephp->p_offset, 209f7ac1bd3Serh (caddr_t)notep, ephp->p_filesz)) != 0) 210f7ac1bd3Serh goto out3; 211f7ac1bd3Serh 212bda91330Serh /* Check for "linux" in the intepreter name. */ 213bda91330Serh if (ephp->p_filesz < 8 + 5) { 214bda91330Serh error = ENOEXEC; 215bda91330Serh goto out3; 216bda91330Serh } 2178b351f01Serh #ifdef DEBUG_LINUX 218bda91330Serh printf("linux_signature: interp=%s\n", notep); 2198b351f01Serh #endif 220bda91330Serh if (strncmp(&((char *)notep)[8], "linux", 5) == 0 || 221bda91330Serh strncmp((char *)notep, "/lib/ld.so.", 11) == 0) { 222f7ac1bd3Serh error = 0; 223f7ac1bd3Serh goto out3; 224f7ac1bd3Serh } 225f7ac1bd3Serh 226f7ac1bd3Serh goto out2; 227f7ac1bd3Serh 228f7ac1bd3Serh /* XXX XAX Should handle NETBSD_TYPE_EMULNAME */ 229f7ac1bd3Serh if (notep->type != ELF_NOTE_TYPE_OSVERSION) { 230f7ac1bd3Serh free(notep, M_TEMP); 231f7ac1bd3Serh continue; 232f7ac1bd3Serh } 233f7ac1bd3Serh 234f7ac1bd3Serh /* Check the name and description sizes. */ 235f7ac1bd3Serh if (notep->namesz != ELF_NOTE_GNU_NAMESZ || 236f7ac1bd3Serh notep->descsz != ELF_NOTE_GNU_DESCSZ) 237f7ac1bd3Serh goto out2; 238f7ac1bd3Serh 239f7ac1bd3Serh /* Is the name "GNU\0"? */ 240f7ac1bd3Serh if (memcmp((notep + sizeof(Elf_Note)), 241f7ac1bd3Serh ELF_NOTE_GNU_NAME, ELF_NOTE_GNU_NAMESZ)) 242f7ac1bd3Serh goto out2; 243f7ac1bd3Serh 244f7ac1bd3Serh /* Make sure the OS is Linux */ 24596dc2f3cSchristos ostype = (u_int32_t)(*((u_int32_t *)notep + sizeof(Elf_Note) + 24696dc2f3cSchristos notep->namesz)) & ELF_NOTE_GNU_OSMASK; 247f7ac1bd3Serh if (ostype != ELF_NOTE_GNU_OSLINUX) 248f7ac1bd3Serh goto out2; 249f7ac1bd3Serh 250f7ac1bd3Serh /* All checks succeeded. */ 251f7ac1bd3Serh error = 0; 252f7ac1bd3Serh goto out3; 253f7ac1bd3Serh } 254f7ac1bd3Serh 255f7ac1bd3Serh error = ENOEXEC; 256f7ac1bd3Serh 257f7ac1bd3Serh out1: 258f7ac1bd3Serh free(ph, M_TEMP); 2598b351f01Serh #ifdef DEBUG_LINUX 2608b351f01Serh printf("linux_signature: out1=%d\n", error); 2618b351f01Serh #endif 262f7ac1bd3Serh return error; 263f7ac1bd3Serh 264f7ac1bd3Serh out2: 265f7ac1bd3Serh error = ENOEXEC; 266f7ac1bd3Serh out3: 267f7ac1bd3Serh free(notep, M_TEMP); 268f7ac1bd3Serh free(ph, M_TEMP); 2698b351f01Serh #ifdef DEBUG_LINUX 2708b351f01Serh printf("linux_signature: out2,3=%d\n", error); 2718b351f01Serh #endif 272f7ac1bd3Serh return error; 273f7ac1bd3Serh } 274f7ac1bd3Serh 275f7ac1bd3Serh int 276f7ac1bd3Serh ELFNAME2(linux,probe)(p, epp, eh, itp, pos) 277f7ac1bd3Serh struct proc *p; 278f7ac1bd3Serh struct exec_package *epp; 279f7ac1bd3Serh Elf_Ehdr *eh; 280c4aaa600Sfvdl char *itp; 281f7ac1bd3Serh Elf_Addr *pos; 282fc7cfb5fSfvdl { 283*c8216580Schristos const char *bp; 284fc7cfb5fSfvdl int error; 285c4aaa600Sfvdl size_t len; 286fc7cfb5fSfvdl 287f7ac1bd3Serh if ((error = ELFNAME2(linux,signature)(p, epp, eh)) != 0) 288f7ac1bd3Serh #ifdef LINUX_GCC_SIGNATURE 289f7ac1bd3Serh if ((error = ELFNAME2(linux,gcc_signature)(p, epp, eh)) != 0) 2904d9a6e09Schristos return error; 291f7ac1bd3Serh #else 292f7ac1bd3Serh return error; 293f7ac1bd3Serh #endif 2944d9a6e09Schristos 295c4aaa600Sfvdl if (itp[0]) { 2966b95b513Schristos if ((error = emul_find(p, NULL, linux_emul_path, itp, &bp, 0))) 297c4aaa600Sfvdl return error; 298c4aaa600Sfvdl if ((error = copystr(bp, itp, MAXPATHLEN, &len))) 299c4aaa600Sfvdl return error; 300*c8216580Schristos free((void *)bp, M_TEMP); 301fc7cfb5fSfvdl } 302f7ac1bd3Serh epp->ep_emul = &ELFNAMEEND(emul_linux); 303f7ac1bd3Serh *pos = ELF_NO_ADDR; 3048b351f01Serh #ifdef DEBUG_LINUX 3058b351f01Serh printf("linux_probe: returning 0\n"); 3068b351f01Serh #endif 307c4aaa600Sfvdl return 0; 308fc7cfb5fSfvdl } 309c4aaa600Sfvdl 310