xref: /netbsd-src/sys/compat/linux/common/linux_exec_elf32.c (revision 96dc2f3c56dba9cedaa46319e5a4c4170011b449)
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