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