1*96dc2f3cSchristos /* $NetBSD: linux_exec_elf32.c,v 1.33 1998/10/03 20:28:03 christos Exp $ */ 28fb507a3Schristos 38fb507a3Schristos /*- 4f7ac1bd3Serh * Copyright (c) 1998 The NetBSD Foundation, Inc. 58fb507a3Schristos * All rights reserved. 68fb507a3Schristos * 78fb507a3Schristos * This code is derived from software contributed to The NetBSD Foundation 8f7ac1bd3Serh * by Eric Haszlakiewicz. 9f7ac1bd3Serh * 10f7ac1bd3Serh * This code is derived from software contributed to The NetBSD Foundation 118fb507a3Schristos * by Christos Zoulas. 128fb507a3Schristos * 138fb507a3Schristos * Redistribution and use in source and binary forms, with or without 148fb507a3Schristos * modification, are permitted provided that the following conditions 158fb507a3Schristos * are met: 168fb507a3Schristos * 1. Redistributions of source code must retain the above copyright 178fb507a3Schristos * notice, this list of conditions and the following disclaimer. 188fb507a3Schristos * 2. Redistributions in binary form must reproduce the above copyright 198fb507a3Schristos * notice, this list of conditions and the following disclaimer in the 208fb507a3Schristos * documentation and/or other materials provided with the distribution. 218fb507a3Schristos * 3. All advertising materials mentioning features or use of this software 228fb507a3Schristos * must display the following acknowledgement: 238fb507a3Schristos * This product includes software developed by the NetBSD 248fb507a3Schristos * Foundation, Inc. and its contributors. 258fb507a3Schristos * 4. Neither the name of The NetBSD Foundation nor the names of its 268fb507a3Schristos * contributors may be used to endorse or promote products derived 278fb507a3Schristos * from this software without specific prior written permission. 288fb507a3Schristos * 298fb507a3Schristos * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 308fb507a3Schristos * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 318fb507a3Schristos * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 328fb507a3Schristos * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 338fb507a3Schristos * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 348fb507a3Schristos * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 358fb507a3Schristos * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 368fb507a3Schristos * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 378fb507a3Schristos * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 388fb507a3Schristos * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 398fb507a3Schristos * POSSIBILITY OF SUCH DAMAGE. 408fb507a3Schristos */ 413bf459f3Sfvdl 423bf459f3Sfvdl /* 433bf459f3Sfvdl * Copyright (c) 1995 Frank van der Linden 443bf459f3Sfvdl * All rights reserved. 453bf459f3Sfvdl * 463bf459f3Sfvdl * Redistribution and use in source and binary forms, with or without 473bf459f3Sfvdl * modification, are permitted provided that the following conditions 483bf459f3Sfvdl * are met: 493bf459f3Sfvdl * 1. Redistributions of source code must retain the above copyright 503bf459f3Sfvdl * notice, this list of conditions and the following disclaimer. 513bf459f3Sfvdl * 2. Redistributions in binary form must reproduce the above copyright 523bf459f3Sfvdl * notice, this list of conditions and the following disclaimer in the 533bf459f3Sfvdl * documentation and/or other materials provided with the distribution. 54fb777788Sfvdl * 3. The name of the author may not be used to endorse or promote products 553bf459f3Sfvdl * derived from this software without specific prior written permission 563bf459f3Sfvdl * 573bf459f3Sfvdl * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 583bf459f3Sfvdl * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 593bf459f3Sfvdl * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 603bf459f3Sfvdl * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 613bf459f3Sfvdl * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 623bf459f3Sfvdl * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 633bf459f3Sfvdl * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 643bf459f3Sfvdl * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 653bf459f3Sfvdl * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 663bf459f3Sfvdl * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 673bf459f3Sfvdl * 68fb777788Sfvdl * based on exec_aout.c, sunos_exec.c and svr4_exec.c 693bf459f3Sfvdl */ 703bf459f3Sfvdl 71f7ac1bd3Serh #ifndef ELFSIZE 727c325577Scgd #define ELFSIZE 32 /* XXX should die */ 73f7ac1bd3Serh #endif 749c3e274cScgd 753bf459f3Sfvdl #include <sys/param.h> 763bf459f3Sfvdl #include <sys/systm.h> 773bf459f3Sfvdl #include <sys/kernel.h> 783bf459f3Sfvdl #include <sys/proc.h> 793bf459f3Sfvdl #include <sys/malloc.h> 803bf459f3Sfvdl #include <sys/namei.h> 813bf459f3Sfvdl #include <sys/vnode.h> 82151fa70fSchristos #include <sys/mount.h> 83d551a4edSchristos #include <sys/exec.h> 84c4aaa600Sfvdl #include <sys/exec_elf.h> 853bf459f3Sfvdl 863bf459f3Sfvdl #include <sys/mman.h> 87151fa70fSchristos #include <sys/syscallargs.h> 88151fa70fSchristos 893bf459f3Sfvdl #include <vm/vm.h> 903bf459f3Sfvdl #include <vm/vm_param.h> 913bf459f3Sfvdl #include <vm/vm_map.h> 923bf459f3Sfvdl 933bf459f3Sfvdl #include <machine/cpu.h> 943bf459f3Sfvdl #include <machine/reg.h> 953bf459f3Sfvdl 96908291d2Schristos #include <compat/linux/common/linux_types.h> 97908291d2Schristos #include <compat/linux/common/linux_signal.h> 98908291d2Schristos #include <compat/linux/common/linux_siginfo.h> 99908291d2Schristos #include <compat/linux/common/linux_util.h> 100908291d2Schristos #include <compat/linux/common/linux_exec.h> 101908291d2Schristos #include <compat/linux/common/linux_machdep.h> 1023bf459f3Sfvdl 103908291d2Schristos #include <compat/linux/linux_syscallargs.h> 104908291d2Schristos #include <compat/linux/linux_syscall.h> 105fc7cfb5fSfvdl 106f7ac1bd3Serh static int ELFNAME2(linux,signature) __P((struct proc *, struct exec_package *, 107f7ac1bd3Serh Elf_Ehdr *)); 108f7ac1bd3Serh #ifdef LINUX_GCC_SIGNATURE 109f7ac1bd3Serh static int ELFNAME2(linux,gcc_signature) __P((struct proc *p, 110f7ac1bd3Serh struct exec_package *, Elf_Ehdr *)); 111f7ac1bd3Serh #endif 112f7ac1bd3Serh 113c4aaa600Sfvdl #define LINUX_ELF_AUX_ARGSIZ (sizeof(AuxInfo) * 8 / sizeof(char *)) 114c4aaa600Sfvdl 11544eef7c2Schristos 11644eef7c2Schristos extern int linux_error[]; 117245f292fSmycroft extern char linux_sigcode[], linux_esigcode[]; 11844eef7c2Schristos extern struct sysent linux_sysent[]; 11944eef7c2Schristos extern char *linux_syscallnames[]; 12044eef7c2Schristos 121f7ac1bd3Serh struct emul ELFNAMEEND(emul_linux) = { 122fc7cfb5fSfvdl "linux", 123fc7cfb5fSfvdl linux_error, 124fc7cfb5fSfvdl linux_sendsig, 125fc7cfb5fSfvdl LINUX_SYS_syscall, 126fc7cfb5fSfvdl LINUX_SYS_MAXSYSCALL, 127fc7cfb5fSfvdl linux_sysent, 128fc7cfb5fSfvdl linux_syscallnames, 129fc7cfb5fSfvdl LINUX_ELF_AUX_ARGSIZ, 130f7ac1bd3Serh ELFNAME(copyargs), 13172623d84Smycroft linux_setregs, 13244eef7c2Schristos linux_sigcode, 13344eef7c2Schristos linux_esigcode, 13444eef7c2Schristos }; 13544eef7c2Schristos 13644eef7c2Schristos 137f7ac1bd3Serh #ifdef LINUX_GCC_SIGNATURE 1384d9a6e09Schristos /* 1394d9a6e09Schristos * Take advantage of the fact that all the linux binaries are compiled 1404d9a6e09Schristos * with gcc, and gcc sticks in the comment field a signature. Note that 1414d9a6e09Schristos * on SVR4 binaries, the gcc signature will follow the OS name signature, 1424d9a6e09Schristos * that will not be a problem. We don't bother to read in the string table, 1434d9a6e09Schristos * but we check all the progbits headers. 144f7ac1bd3Serh * 145f7ac1bd3Serh * XXX This only works in the i386. On the alpha (at least) 146f7ac1bd3Serh * XXX we have the same gcc signature which incorrectly identifies 147f7ac1bd3Serh * XXX NetBSD binaries as Linux. 1484d9a6e09Schristos */ 1494d9a6e09Schristos static int 150f7ac1bd3Serh ELFNAME2(linux,gcc_signature)(p, epp, eh) 151fc7cfb5fSfvdl struct proc *p; 152fc7cfb5fSfvdl struct exec_package *epp; 153f7ac1bd3Serh Elf_Ehdr *eh; 1544d9a6e09Schristos { 155f7ac1bd3Serh size_t shsize = sizeof(Elf_Shdr) * eh->e_shnum; 1564d9a6e09Schristos size_t i; 1574d9a6e09Schristos static const char signature[] = "\0GCC: (GNU) "; 1584d9a6e09Schristos char buf[sizeof(signature) - 1]; 159f7ac1bd3Serh Elf_Shdr *sh; 1604d9a6e09Schristos int error; 1614d9a6e09Schristos 162f7ac1bd3Serh error = ENOEXEC; 163f7ac1bd3Serh sh = (Elf_Shdr *) malloc(shsize, M_TEMP, M_WAITOK); 1644d9a6e09Schristos 165f7ac1bd3Serh if ((error = ELFNAME(read_from)(p, epp->ep_vp, eh->e_shoff, 1664d9a6e09Schristos (caddr_t) sh, shsize)) != 0) 1674d9a6e09Schristos goto out; 1684d9a6e09Schristos 1694d9a6e09Schristos for (i = 0; i < eh->e_shnum; i++) { 170f7ac1bd3Serh Elf_Shdr *s = &sh[i]; 1714d9a6e09Schristos 1724d9a6e09Schristos /* 1734d9a6e09Schristos * Identify candidates for the comment header; 174d83602c1Schristos * Header cannot have a load address, or flags and 1754d9a6e09Schristos * it must be large enough. 1764d9a6e09Schristos */ 177fb2727b7Sjtk if (s->sh_type != Elf_sht_progbits || 1784d9a6e09Schristos s->sh_addr != 0 || 1794d9a6e09Schristos s->sh_flags != 0 || 1804d9a6e09Schristos s->sh_size < sizeof(signature) - 1) 1814d9a6e09Schristos continue; 1824d9a6e09Schristos 183f7ac1bd3Serh if ((error = ELFNAME(read_from)(p, epp->ep_vp, s->sh_offset, 184d83602c1Schristos (caddr_t) buf, sizeof(signature) - 1)) != 0) 1854d9a6e09Schristos goto out; 1864d9a6e09Schristos 187d83602c1Schristos /* 188d83602c1Schristos * error is 0, if the signatures match we are done. 189d83602c1Schristos */ 190e1601dc2Sperry if (memcmp(buf, signature, sizeof(signature) - 1) == 0) 1914d9a6e09Schristos goto out; 1924d9a6e09Schristos } 1934d9a6e09Schristos 1944d9a6e09Schristos out: 1954d9a6e09Schristos free(sh, M_TEMP); 1964d9a6e09Schristos return error; 1974d9a6e09Schristos } 198f7ac1bd3Serh #endif 1994d9a6e09Schristos 200f7ac1bd3Serh static int 201f7ac1bd3Serh ELFNAME2(linux,signature)(p, epp, eh) 2024d9a6e09Schristos struct proc *p; 2034d9a6e09Schristos struct exec_package *epp; 204f7ac1bd3Serh Elf_Ehdr *eh; 205f7ac1bd3Serh { 206f7ac1bd3Serh size_t i; 207f7ac1bd3Serh Elf_Phdr *ph; 208f7ac1bd3Serh Elf_Note *notep; 209f7ac1bd3Serh char *testp; 210f7ac1bd3Serh size_t phsize; 211f7ac1bd3Serh int error = ENOEXEC; 212f7ac1bd3Serh 213f7ac1bd3Serh phsize = eh->e_phnum * sizeof(Elf_Phdr); 214f7ac1bd3Serh ph = (Elf_Phdr *)malloc(phsize, M_TEMP, M_WAITOK); 215f7ac1bd3Serh if ((error = ELFNAME(read_from)(p, epp->ep_vp, eh->e_phoff, 216f7ac1bd3Serh (caddr_t) ph, phsize)) != 0) 217f7ac1bd3Serh goto out1; 218f7ac1bd3Serh 219f7ac1bd3Serh for (i = 0; i < eh->e_phnum; i++) { 220f7ac1bd3Serh Elf_Phdr *ephp = &ph[i]; 221f7ac1bd3Serh u_int32_t ostype; 222f7ac1bd3Serh 223f7ac1bd3Serh if (ephp->p_type != Elf_pt_interp /* XAX pt_note */ 224*96dc2f3cSchristos #if 0 225*96dc2f3cSchristos || ephp->p_flags != 0 226*96dc2f3cSchristos || ephp->p_filesz < sizeof(Elf_Note)) 227*96dc2f3cSchristos #endif 228*96dc2f3cSchristos ) 229f7ac1bd3Serh continue; 230f7ac1bd3Serh 231f7ac1bd3Serh notep = (Elf_Note *)malloc(ephp->p_filesz, M_TEMP, M_WAITOK); 232f7ac1bd3Serh if ((error = ELFNAME(read_from)(p, epp->ep_vp, ephp->p_offset, 233f7ac1bd3Serh (caddr_t)notep, ephp->p_filesz)) != 0) 234f7ac1bd3Serh goto out3; 235f7ac1bd3Serh 236f7ac1bd3Serh testp = (char *)notep; 237f7ac1bd3Serh testp[16] = '\0'; 238*96dc2f3cSchristos if (strncmp(&testp[8], "linux", 5) != 0) { 239f7ac1bd3Serh error = 0; 240f7ac1bd3Serh goto out3; 241f7ac1bd3Serh } 242f7ac1bd3Serh 243f7ac1bd3Serh goto out2; 244f7ac1bd3Serh 245f7ac1bd3Serh /* XXX XAX Should handle NETBSD_TYPE_EMULNAME */ 246f7ac1bd3Serh if (notep->type != ELF_NOTE_TYPE_OSVERSION) { 247f7ac1bd3Serh free(notep, M_TEMP); 248f7ac1bd3Serh continue; 249f7ac1bd3Serh } 250f7ac1bd3Serh 251f7ac1bd3Serh /* Check the name and description sizes. */ 252f7ac1bd3Serh if (notep->namesz != ELF_NOTE_GNU_NAMESZ || 253f7ac1bd3Serh notep->descsz != ELF_NOTE_GNU_DESCSZ) 254f7ac1bd3Serh goto out2; 255f7ac1bd3Serh 256f7ac1bd3Serh /* Is the name "GNU\0"? */ 257f7ac1bd3Serh if (memcmp((notep + sizeof(Elf_Note)), 258f7ac1bd3Serh ELF_NOTE_GNU_NAME, ELF_NOTE_GNU_NAMESZ)) 259f7ac1bd3Serh goto out2; 260f7ac1bd3Serh 261f7ac1bd3Serh /* Make sure the OS is Linux */ 262*96dc2f3cSchristos ostype = (u_int32_t)(*((u_int32_t *)notep + sizeof(Elf_Note) + 263*96dc2f3cSchristos notep->namesz)) & ELF_NOTE_GNU_OSMASK; 264f7ac1bd3Serh if (ostype != ELF_NOTE_GNU_OSLINUX) 265f7ac1bd3Serh goto out2; 266f7ac1bd3Serh 267f7ac1bd3Serh /* All checks succeeded. */ 268f7ac1bd3Serh error = 0; 269f7ac1bd3Serh goto out3; 270f7ac1bd3Serh } 271f7ac1bd3Serh 272f7ac1bd3Serh error = ENOEXEC; 273f7ac1bd3Serh 274f7ac1bd3Serh out1: 275f7ac1bd3Serh free(ph, M_TEMP); 276f7ac1bd3Serh return error; 277f7ac1bd3Serh 278f7ac1bd3Serh out2: 279f7ac1bd3Serh error = ENOEXEC; 280f7ac1bd3Serh out3: 281f7ac1bd3Serh free(notep, M_TEMP); 282f7ac1bd3Serh free(ph, M_TEMP); 283f7ac1bd3Serh return error; 284f7ac1bd3Serh } 285f7ac1bd3Serh 286f7ac1bd3Serh int 287f7ac1bd3Serh ELFNAME2(linux,probe)(p, epp, eh, itp, pos) 288f7ac1bd3Serh struct proc *p; 289f7ac1bd3Serh struct exec_package *epp; 290f7ac1bd3Serh Elf_Ehdr *eh; 291c4aaa600Sfvdl char *itp; 292f7ac1bd3Serh Elf_Addr *pos; 293fc7cfb5fSfvdl { 294c4aaa600Sfvdl char *bp; 295fc7cfb5fSfvdl int error; 296c4aaa600Sfvdl size_t len; 297fc7cfb5fSfvdl 298f7ac1bd3Serh if ((error = ELFNAME2(linux,signature)(p, epp, eh)) != 0) 299f7ac1bd3Serh #ifdef LINUX_GCC_SIGNATURE 300f7ac1bd3Serh if ((error = ELFNAME2(linux,gcc_signature)(p, epp, eh)) != 0) 3014d9a6e09Schristos return error; 302f7ac1bd3Serh #else 303f7ac1bd3Serh return error; 304f7ac1bd3Serh #endif 3054d9a6e09Schristos 306c4aaa600Sfvdl if (itp[0]) { 3076b95b513Schristos if ((error = emul_find(p, NULL, linux_emul_path, itp, &bp, 0))) 308c4aaa600Sfvdl return error; 309c4aaa600Sfvdl if ((error = copystr(bp, itp, MAXPATHLEN, &len))) 310c4aaa600Sfvdl return error; 311c4aaa600Sfvdl free(bp, M_TEMP); 312fc7cfb5fSfvdl } 313f7ac1bd3Serh epp->ep_emul = &ELFNAMEEND(emul_linux); 314f7ac1bd3Serh *pos = ELF_NO_ADDR; 315c4aaa600Sfvdl return 0; 316fc7cfb5fSfvdl } 317c4aaa600Sfvdl 318