xref: /netbsd-src/sys/compat/linux/common/linux_exec_elf32.c (revision 6cc149625b38b60c738bd6e57a404b82bcf276e8)
1*6cc14962Schristos /*	$NetBSD: linux_exec_elf32.c,v 1.57 2002/09/05 14:32:49 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 
44dab6ef8bSlukem #include <sys/cdefs.h>
45*6cc14962Schristos __KERNEL_RCSID(0, "$NetBSD: linux_exec_elf32.c,v 1.57 2002/09/05 14:32:49 christos Exp $");
46dab6ef8bSlukem 
47f7ac1bd3Serh #ifndef ELFSIZE
487c325577Scgd #define	ELFSIZE		32				/* XXX should die */
49f7ac1bd3Serh #endif
509c3e274cScgd 
513bf459f3Sfvdl #include <sys/param.h>
523bf459f3Sfvdl #include <sys/systm.h>
533bf459f3Sfvdl #include <sys/kernel.h>
543bf459f3Sfvdl #include <sys/proc.h>
553bf459f3Sfvdl #include <sys/malloc.h>
563bf459f3Sfvdl #include <sys/namei.h>
573bf459f3Sfvdl #include <sys/vnode.h>
58151fa70fSchristos #include <sys/mount.h>
59d551a4edSchristos #include <sys/exec.h>
60c4aaa600Sfvdl #include <sys/exec_elf.h>
613bf459f3Sfvdl 
623bf459f3Sfvdl #include <sys/mman.h>
63151fa70fSchristos #include <sys/syscallargs.h>
64151fa70fSchristos 
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>
733bf459f3Sfvdl 
74908291d2Schristos #include <compat/linux/linux_syscallargs.h>
75908291d2Schristos #include <compat/linux/linux_syscall.h>
76fc7cfb5fSfvdl 
77f7ac1bd3Serh static int ELFNAME2(linux,signature) __P((struct proc *, struct exec_package *,
78b29180b2Smycroft 	Elf_Ehdr *, char *));
79f7ac1bd3Serh #ifdef LINUX_GCC_SIGNATURE
80f7ac1bd3Serh static int ELFNAME2(linux,gcc_signature) __P((struct proc *p,
81f7ac1bd3Serh 	struct exec_package *, Elf_Ehdr *));
82f7ac1bd3Serh #endif
83ac10cf69Smanu #ifdef LINUX_ATEXIT_SIGNATURE
84ac10cf69Smanu static int ELFNAME2(linux,atexit_signature) __P((struct proc *p,
85ac10cf69Smanu 	struct exec_package *, Elf_Ehdr *));
86ac10cf69Smanu #endif
87ac10cf69Smanu 
8865fc8539Schristos #ifdef DEBUG_LINUX
8965fc8539Schristos #define DPRINTF(a)	uprintf a
9065fc8539Schristos #else
9165fc8539Schristos #define DPRINTF(a)
9265fc8539Schristos #endif
9365fc8539Schristos 
94ac10cf69Smanu #ifdef LINUX_ATEXIT_SIGNATURE
95ac10cf69Smanu /*
96ac10cf69Smanu  * On the PowerPC, statically linked Linux binaries are not recognized
97ac10cf69Smanu  * by linux_signature nor by linux_gcc_signature. Fortunately, thoses
98ac10cf69Smanu  * binaries features a __libc_atexit ELF section. We therefore assume we
99ac10cf69Smanu  * have a Linux binary if we find this section.
100ac10cf69Smanu  */
101ac10cf69Smanu static int
102ac10cf69Smanu ELFNAME2(linux,atexit_signature)(p, epp, eh)
103ac10cf69Smanu 	struct proc *p;
104ac10cf69Smanu 	struct exec_package *epp;
105ac10cf69Smanu 	Elf_Ehdr *eh;
106ac10cf69Smanu {
107ac10cf69Smanu 	size_t shsize;
108ac10cf69Smanu 	int	strndx;
109ac10cf69Smanu 	size_t i;
110ac10cf69Smanu 	static const char signature[] = "__libc_atexit";
111ac10cf69Smanu 	char* strtable;
112ac10cf69Smanu 	Elf_Shdr *sh;
113ac10cf69Smanu 
114ac10cf69Smanu 	int error;
115ac10cf69Smanu 
116ac10cf69Smanu 	/*
117ac10cf69Smanu 	 * load the section header table
118ac10cf69Smanu 	 */
119ac10cf69Smanu 	shsize = eh->e_shnum * sizeof(Elf_Shdr);
120ac10cf69Smanu 	sh = (Elf_Shdr *) malloc(shsize, M_TEMP, M_WAITOK);
12197c9d7a9Schristos 	error = exec_read_from(p, epp->ep_vp, eh->e_shoff, sh, shsize);
122ac10cf69Smanu 	if (error)
123ac10cf69Smanu 		goto out;
124ac10cf69Smanu 
125ac10cf69Smanu 	/*
126ac10cf69Smanu 	 * Now let's find the string table. If it does not exists, give up.
127ac10cf69Smanu 	 */
128ac10cf69Smanu 	strndx = (int)(eh->e_shstrndx);
129ac10cf69Smanu 	if (strndx == SHN_UNDEF) {
130ac10cf69Smanu 		error = ENOEXEC;
131ac10cf69Smanu 		goto out;
132ac10cf69Smanu 	}
133ac10cf69Smanu 
134ac10cf69Smanu 	/*
13597c9d7a9Schristos 	 * strndx is the index in section header table of the string table
13697c9d7a9Schristos 	 * section get the whole string table in strtable, and then we get access to the names
137ac10cf69Smanu 	 * s->sh_name is the offset of the section name in strtable.
138ac10cf69Smanu 	 */
139ac10cf69Smanu 	strtable = malloc(sh[strndx].sh_size, M_TEMP, M_WAITOK);
14097c9d7a9Schristos 	error = exec_read_from(p, epp->ep_vp, sh[strndx].sh_offset, strtable,
14197c9d7a9Schristos 	    sh[strndx].sh_size);
142ac10cf69Smanu 	if (error)
143ac10cf69Smanu 		goto out;
144ac10cf69Smanu 
145ac10cf69Smanu 	for (i = 0; i < eh->e_shnum; i++) {
146ac10cf69Smanu 		Elf_Shdr *s = &sh[i];
147ac10cf69Smanu 		if (!memcmp((void*)(&(strtable[s->sh_name])), signature,
148ac10cf69Smanu 				sizeof(signature))) {
14965fc8539Schristos 			DPRINTF(("linux_atexit_sig=%s\n",
15065fc8539Schristos 			    &(strtable[s->sh_name])));
151ac10cf69Smanu 			error = 0;
152ac10cf69Smanu 			goto out;
153ac10cf69Smanu 		}
154ac10cf69Smanu 	}
155ac10cf69Smanu 	error = ENOEXEC;
156ac10cf69Smanu 
157ac10cf69Smanu out:
158ac10cf69Smanu 	free(sh, M_TEMP);
159ac10cf69Smanu 	free(strtable, M_TEMP);
160ac10cf69Smanu 	return (error);
161ac10cf69Smanu }
162ac10cf69Smanu #endif
163f7ac1bd3Serh 
164f7ac1bd3Serh #ifdef LINUX_GCC_SIGNATURE
1654d9a6e09Schristos /*
1664d9a6e09Schristos  * Take advantage of the fact that all the linux binaries are compiled
1674d9a6e09Schristos  * with gcc, and gcc sticks in the comment field a signature. Note that
1684d9a6e09Schristos  * on SVR4 binaries, the gcc signature will follow the OS name signature,
1694d9a6e09Schristos  * that will not be a problem. We don't bother to read in the string table,
1704d9a6e09Schristos  * but we check all the progbits headers.
171f7ac1bd3Serh  *
172f7ac1bd3Serh  * XXX This only works in the i386.  On the alpha (at least)
173f7ac1bd3Serh  * XXX we have the same gcc signature which incorrectly identifies
174f7ac1bd3Serh  * XXX NetBSD binaries as Linux.
1754d9a6e09Schristos  */
1764d9a6e09Schristos static int
177f7ac1bd3Serh ELFNAME2(linux,gcc_signature)(p, epp, eh)
178fc7cfb5fSfvdl 	struct proc *p;
179fc7cfb5fSfvdl 	struct exec_package *epp;
180f7ac1bd3Serh 	Elf_Ehdr *eh;
1814d9a6e09Schristos {
182b29180b2Smycroft 	size_t shsize;
1834d9a6e09Schristos 	size_t i;
1844d9a6e09Schristos 	static const char signature[] = "\0GCC: (GNU) ";
1854d9a6e09Schristos 	char buf[sizeof(signature) - 1];
186f7ac1bd3Serh 	Elf_Shdr *sh;
1874d9a6e09Schristos 	int error;
1884d9a6e09Schristos 
189b29180b2Smycroft 	shsize = eh->e_shnum * sizeof(Elf_Shdr);
190f7ac1bd3Serh 	sh = (Elf_Shdr *) malloc(shsize, M_TEMP, M_WAITOK);
19197c9d7a9Schristos 	error = exec_read_from(p, epp->ep_vp, eh->e_shoff, sh, shsize);
192b29180b2Smycroft 	if (error)
1934d9a6e09Schristos 		goto out;
1944d9a6e09Schristos 
1954d9a6e09Schristos 	for (i = 0; i < eh->e_shnum; i++) {
196f7ac1bd3Serh 		Elf_Shdr *s = &sh[i];
1974d9a6e09Schristos 
1984d9a6e09Schristos 		/*
1994d9a6e09Schristos 		 * Identify candidates for the comment header;
200d83602c1Schristos 		 * Header cannot have a load address, or flags and
2014d9a6e09Schristos 		 * it must be large enough.
2024d9a6e09Schristos 		 */
203522cbf02Skleink 		if (s->sh_type != SHT_PROGBITS ||
2044d9a6e09Schristos 		    s->sh_addr != 0 ||
2054d9a6e09Schristos 		    s->sh_flags != 0 ||
2064d9a6e09Schristos 		    s->sh_size < sizeof(signature) - 1)
2074d9a6e09Schristos 			continue;
2084d9a6e09Schristos 
20997c9d7a9Schristos 		error = exec_read_from(p, epp->ep_vp, s->sh_offset, buf,
21097c9d7a9Schristos 		    sizeof(signature) - 1);
211b29180b2Smycroft 		if (error)
212b29180b2Smycroft 			continue;
2134d9a6e09Schristos 
214d83602c1Schristos 		/*
215d83602c1Schristos 		 * error is 0, if the signatures match we are done.
216d83602c1Schristos 		 */
21765fc8539Schristos 		DPRINTF(("linux_gcc_sig: sig=%s\n", buf));
218b29180b2Smycroft 		if (!memcmp(buf, signature, sizeof(signature) - 1)) {
219b29180b2Smycroft 			error = 0;
2204d9a6e09Schristos 			goto out;
2214d9a6e09Schristos 		}
222b29180b2Smycroft 	}
223b29180b2Smycroft 	error = ENOEXEC;
2244d9a6e09Schristos 
2254d9a6e09Schristos out:
2264d9a6e09Schristos 	free(sh, M_TEMP);
227b29180b2Smycroft 	return (error);
2284d9a6e09Schristos }
229f7ac1bd3Serh #endif
2304d9a6e09Schristos 
231f7ac1bd3Serh static int
232b29180b2Smycroft ELFNAME2(linux,signature)(p, epp, eh, itp)
2334d9a6e09Schristos 	struct proc *p;
2344d9a6e09Schristos 	struct exec_package *epp;
235f7ac1bd3Serh 	Elf_Ehdr *eh;
236b29180b2Smycroft 	char *itp;
237f7ac1bd3Serh {
238f7ac1bd3Serh 	size_t i;
239f7ac1bd3Serh 	Elf_Phdr *ph;
240f7ac1bd3Serh 	size_t phsize;
241b29180b2Smycroft 	int error;
242*6cc14962Schristos 	static const char linux[] = "Linux";
243*6cc14962Schristos 
244*6cc14962Schristos 	if (eh->e_ident[EI_OSABI] == 3 ||
245*6cc14962Schristos 	    memcmp(&eh->e_ident[EI_ABIVERSION], linux, sizeof(linux)) == 0)
246*6cc14962Schristos 		return 0;
247f7ac1bd3Serh 
248f7ac1bd3Serh 	phsize = eh->e_phnum * sizeof(Elf_Phdr);
249f7ac1bd3Serh 	ph = (Elf_Phdr *)malloc(phsize, M_TEMP, M_WAITOK);
25097c9d7a9Schristos 	error = exec_read_from(p, epp->ep_vp, eh->e_phoff, ph, phsize);
251b29180b2Smycroft 	if (error)
252b29180b2Smycroft 		goto out;
253f7ac1bd3Serh 
254f7ac1bd3Serh 	for (i = 0; i < eh->e_phnum; i++) {
255f7ac1bd3Serh 		Elf_Phdr *ephp = &ph[i];
256b29180b2Smycroft 		Elf_Nhdr *np;
257b29180b2Smycroft 		u_int32_t *abi;
258f7ac1bd3Serh 
259b29180b2Smycroft 		if (ephp->p_type != PT_NOTE ||
260b29180b2Smycroft 		    ephp->p_filesz > 1024 ||
261b29180b2Smycroft 		    ephp->p_filesz < sizeof(Elf_Nhdr) + 20)
262f7ac1bd3Serh 			continue;
263f7ac1bd3Serh 
264b29180b2Smycroft 		np = (Elf_Nhdr *)malloc(ephp->p_filesz, M_TEMP, M_WAITOK);
26597c9d7a9Schristos 		error = exec_read_from(p, epp->ep_vp, ephp->p_offset, np,
26697c9d7a9Schristos 		    ephp->p_filesz);
267b29180b2Smycroft 		if (error)
268b29180b2Smycroft 			goto next;
269f7ac1bd3Serh 
270b29180b2Smycroft 		if (np->n_type != ELF_NOTE_TYPE_ABI_TAG ||
271b29180b2Smycroft 		    np->n_namesz != ELF_NOTE_ABI_NAMESZ ||
272b29180b2Smycroft 		    np->n_descsz != ELF_NOTE_ABI_DESCSZ ||
273b29180b2Smycroft 		    memcmp((caddr_t)(np + 1), ELF_NOTE_ABI_NAME,
274b29180b2Smycroft 		    ELF_NOTE_ABI_NAMESZ))
275b29180b2Smycroft 			goto next;
276b29180b2Smycroft 
277b29180b2Smycroft 		/* Make sure the OS is Linux. */
278b29180b2Smycroft 		abi = (u_int32_t *)((caddr_t)np + sizeof(Elf_Nhdr) +
279b29180b2Smycroft 		    np->n_namesz);
280b29180b2Smycroft 		if (abi[0] == ELF_NOTE_ABI_OS_LINUX)
281f7ac1bd3Serh 			error = 0;
282b29180b2Smycroft 		else
283b29180b2Smycroft 			error = ENOEXEC;
284b29180b2Smycroft 		free(np, M_TEMP);
285b29180b2Smycroft 		goto out;
286f7ac1bd3Serh 
287b29180b2Smycroft 	next:
288b29180b2Smycroft 		free(np, M_TEMP);
289f7ac1bd3Serh 		continue;
290f7ac1bd3Serh 	}
291f7ac1bd3Serh 
292b29180b2Smycroft 	/* Check for certain intepreter names. */
293b29180b2Smycroft 	if (itp[0]) {
294b29180b2Smycroft 		if (!strncmp(itp, "/lib/ld-linux", 13) ||
295b29180b2Smycroft 		    !strncmp(itp, "/lib/ld.so.", 11))
296f7ac1bd3Serh 			error = 0;
297b29180b2Smycroft 		else
298b29180b2Smycroft 			error = ENOEXEC;
299b29180b2Smycroft 		goto out;
300f7ac1bd3Serh 	}
301f7ac1bd3Serh 
302f7ac1bd3Serh 	error = ENOEXEC;
303b29180b2Smycroft out:
304f7ac1bd3Serh 	free(ph, M_TEMP);
305b29180b2Smycroft 	return (error);
306f7ac1bd3Serh }
307f7ac1bd3Serh 
308f7ac1bd3Serh int
309f7ac1bd3Serh ELFNAME2(linux,probe)(p, epp, eh, itp, pos)
310f7ac1bd3Serh 	struct proc *p;
311f7ac1bd3Serh 	struct exec_package *epp;
312baae0324Sjdolecek 	void *eh;
313c4aaa600Sfvdl 	char *itp;
314baae0324Sjdolecek 	vaddr_t *pos;
315fc7cfb5fSfvdl {
316c8216580Schristos 	const char *bp;
317fc7cfb5fSfvdl 	int error;
318c4aaa600Sfvdl 	size_t len;
319fc7cfb5fSfvdl 
3208537f76cSmanu 	if (((error = ELFNAME2(linux,signature)(p, epp, eh, itp)) != 0) &&
321f7ac1bd3Serh #ifdef LINUX_GCC_SIGNATURE
3228537f76cSmanu 	    ((error = ELFNAME2(linux,gcc_signature)(p, epp, eh)) != 0) &&
3238537f76cSmanu #endif
324ac10cf69Smanu #ifdef LINUX_ATEXIT_SIGNATURE
3258537f76cSmanu 	    ((error = ELFNAME2(linux,atexit_signature)(p, epp, eh)) != 0) &&
326ac10cf69Smanu #endif
3278537f76cSmanu 	    1)
3288537f76cSmanu 			return error;
3294d9a6e09Schristos 
330c4aaa600Sfvdl 	if (itp[0]) {
33101040d97Sjdolecek 		if ((error = emul_find(p, NULL, epp->ep_esch->es_emul->e_path,
33201040d97Sjdolecek 		    itp, &bp, 0)))
333c4aaa600Sfvdl 			return error;
334c4aaa600Sfvdl 		if ((error = copystr(bp, itp, MAXPATHLEN, &len)))
335c4aaa600Sfvdl 			return error;
336c8216580Schristos 		free((void *)bp, M_TEMP);
337fc7cfb5fSfvdl 	}
338f7ac1bd3Serh 	*pos = ELF_NO_ADDR;
33965fc8539Schristos 	DPRINTF(("linux_probe: returning 0\n"));
340c4aaa600Sfvdl 	return 0;
341fc7cfb5fSfvdl }
342c4aaa600Sfvdl 
343