xref: /netbsd-src/sys/compat/linux/common/linux_exec_elf32.c (revision a2a3828545f06ae25986dcfcd3831f7308c09784)
1*a2a38285Sad /*	$NetBSD: linux_exec_elf32.c,v 1.80 2007/10/19 12:16:39 ad 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*a2a38285Sad __KERNEL_RCSID(0, "$NetBSD: linux_exec_elf32.c,v 1.80 2007/10/19 12:16:39 ad Exp $");
46dab6ef8bSlukem 
47f7ac1bd3Serh #ifndef ELFSIZE
48ea0cda2cSchristos /* XXX should die */
49ea0cda2cSchristos #define	ELFSIZE		32
50f7ac1bd3Serh #endif
519c3e274cScgd 
523bf459f3Sfvdl #include <sys/param.h>
533bf459f3Sfvdl #include <sys/systm.h>
543bf459f3Sfvdl #include <sys/kernel.h>
553bf459f3Sfvdl #include <sys/proc.h>
563bf459f3Sfvdl #include <sys/malloc.h>
573bf459f3Sfvdl #include <sys/namei.h>
583bf459f3Sfvdl #include <sys/vnode.h>
59151fa70fSchristos #include <sys/mount.h>
60d551a4edSchristos #include <sys/exec.h>
61c4aaa600Sfvdl #include <sys/exec_elf.h>
62cee43b67Sjdolecek #include <sys/stat.h>
63874fef37Selad #include <sys/kauth.h>
643bf459f3Sfvdl 
653bf459f3Sfvdl #include <sys/mman.h>
66151fa70fSchristos #include <sys/syscallargs.h>
67151fa70fSchristos 
68*a2a38285Sad #include <sys/cpu.h>
693bf459f3Sfvdl #include <machine/reg.h>
703bf459f3Sfvdl 
71908291d2Schristos #include <compat/linux/common/linux_types.h>
72908291d2Schristos #include <compat/linux/common/linux_signal.h>
73908291d2Schristos #include <compat/linux/common/linux_util.h>
74908291d2Schristos #include <compat/linux/common/linux_exec.h>
75908291d2Schristos #include <compat/linux/common/linux_machdep.h>
763bf459f3Sfvdl 
77908291d2Schristos #include <compat/linux/linux_syscallargs.h>
78908291d2Schristos #include <compat/linux/linux_syscall.h>
79fc7cfb5fSfvdl 
8065fc8539Schristos #ifdef DEBUG_LINUX
8165fc8539Schristos #define DPRINTF(a)	uprintf a
8265fc8539Schristos #else
8365fc8539Schristos #define DPRINTF(a)
8465fc8539Schristos #endif
8565fc8539Schristos 
86ac10cf69Smanu #ifdef LINUX_ATEXIT_SIGNATURE
87ac10cf69Smanu /*
88ac10cf69Smanu  * On the PowerPC, statically linked Linux binaries are not recognized
89ac10cf69Smanu  * by linux_signature nor by linux_gcc_signature. Fortunately, thoses
90ac10cf69Smanu  * binaries features a __libc_atexit ELF section. We therefore assume we
91ac10cf69Smanu  * have a Linux binary if we find this section.
92ac10cf69Smanu  */
93ee0c5b44Smanu int
9495e1ffb1Schristos ELFNAME2(linux,atexit_signature)(l, epp, eh)
9595e1ffb1Schristos 	struct lwp *l;
96ac10cf69Smanu 	struct exec_package *epp;
97ac10cf69Smanu 	Elf_Ehdr *eh;
98ac10cf69Smanu {
99ac10cf69Smanu 	size_t shsize;
100ac10cf69Smanu 	int strndx;
101ac10cf69Smanu 	size_t i;
102ac10cf69Smanu 	static const char signature[] = "__libc_atexit";
1033b6d3c71Schs 	char *strtable = NULL;
104ac10cf69Smanu 	Elf_Shdr *sh;
105ac10cf69Smanu 
106ac10cf69Smanu 	int error;
107ac10cf69Smanu 
108ac10cf69Smanu 	/*
109ac10cf69Smanu 	 * load the section header table
110ac10cf69Smanu 	 */
111ac10cf69Smanu 	shsize = eh->e_shnum * sizeof(Elf_Shdr);
112ac10cf69Smanu 	sh = (Elf_Shdr *) malloc(shsize, M_TEMP, M_WAITOK);
11395e1ffb1Schristos 	error = exec_read_from(l, epp->ep_vp, eh->e_shoff, sh, shsize);
114ac10cf69Smanu 	if (error)
115ac10cf69Smanu 		goto out;
116ac10cf69Smanu 
117ac10cf69Smanu 	/*
118ac10cf69Smanu 	 * Now let's find the string table. If it does not exists, give up.
119ac10cf69Smanu 	 */
120ac10cf69Smanu 	strndx = (int)(eh->e_shstrndx);
121ac10cf69Smanu 	if (strndx == SHN_UNDEF) {
122ac10cf69Smanu 		error = ENOEXEC;
123ac10cf69Smanu 		goto out;
124ac10cf69Smanu 	}
125ac10cf69Smanu 
126ac10cf69Smanu 	/*
12797c9d7a9Schristos 	 * strndx is the index in section header table of the string table
12897c9d7a9Schristos 	 * section get the whole string table in strtable, and then we get access to the names
129ac10cf69Smanu 	 * s->sh_name is the offset of the section name in strtable.
130ac10cf69Smanu 	 */
131ac10cf69Smanu 	strtable = malloc(sh[strndx].sh_size, M_TEMP, M_WAITOK);
13295e1ffb1Schristos 	error = exec_read_from(l, epp->ep_vp, sh[strndx].sh_offset, strtable,
13397c9d7a9Schristos 	    sh[strndx].sh_size);
134ac10cf69Smanu 	if (error)
135ac10cf69Smanu 		goto out;
136ac10cf69Smanu 
137ac10cf69Smanu 	for (i = 0; i < eh->e_shnum; i++) {
138ac10cf69Smanu 		Elf_Shdr *s = &sh[i];
139ac10cf69Smanu 		if (!memcmp((void*)(&(strtable[s->sh_name])), signature,
140ac10cf69Smanu 				sizeof(signature))) {
14165fc8539Schristos 			DPRINTF(("linux_atexit_sig=%s\n",
14265fc8539Schristos 			    &(strtable[s->sh_name])));
143ac10cf69Smanu 			error = 0;
144ac10cf69Smanu 			goto out;
145ac10cf69Smanu 		}
146ac10cf69Smanu 	}
147ac10cf69Smanu 	error = ENOEXEC;
148ac10cf69Smanu 
149ac10cf69Smanu out:
150ac10cf69Smanu 	free(sh, M_TEMP);
1513b6d3c71Schs 	if (strtable)
152ac10cf69Smanu 		free(strtable, M_TEMP);
153ac10cf69Smanu 	return (error);
154ac10cf69Smanu }
155ac10cf69Smanu #endif
156f7ac1bd3Serh 
157f7ac1bd3Serh #ifdef LINUX_GCC_SIGNATURE
1584d9a6e09Schristos /*
1594d9a6e09Schristos  * Take advantage of the fact that all the linux binaries are compiled
1604d9a6e09Schristos  * with gcc, and gcc sticks in the comment field a signature. Note that
1614d9a6e09Schristos  * on SVR4 binaries, the gcc signature will follow the OS name signature,
1624d9a6e09Schristos  * that will not be a problem. We don't bother to read in the string table,
1634d9a6e09Schristos  * but we check all the progbits headers.
164f7ac1bd3Serh  *
165f7ac1bd3Serh  * XXX This only works in the i386.  On the alpha (at least)
166f7ac1bd3Serh  * XXX we have the same gcc signature which incorrectly identifies
167f7ac1bd3Serh  * XXX NetBSD binaries as Linux.
1684d9a6e09Schristos  */
169ee0c5b44Smanu int
17095e1ffb1Schristos ELFNAME2(linux,gcc_signature)(l, epp, eh)
17195e1ffb1Schristos 	struct lwp *l;
172fc7cfb5fSfvdl 	struct exec_package *epp;
173f7ac1bd3Serh 	Elf_Ehdr *eh;
1744d9a6e09Schristos {
175b29180b2Smycroft 	size_t shsize;
1764d9a6e09Schristos 	size_t i;
1774d9a6e09Schristos 	static const char signature[] = "\0GCC: (GNU) ";
178fb4b40b7Schristos 	char tbuf[sizeof(signature) - 1];
179f7ac1bd3Serh 	Elf_Shdr *sh;
1804d9a6e09Schristos 	int error;
1814d9a6e09Schristos 
182b29180b2Smycroft 	shsize = eh->e_shnum * sizeof(Elf_Shdr);
183f7ac1bd3Serh 	sh = (Elf_Shdr *) malloc(shsize, M_TEMP, M_WAITOK);
18495e1ffb1Schristos 	error = exec_read_from(l, epp->ep_vp, eh->e_shoff, sh, shsize);
185b29180b2Smycroft 	if (error)
1864d9a6e09Schristos 		goto out;
1874d9a6e09Schristos 
1884d9a6e09Schristos 	for (i = 0; i < eh->e_shnum; i++) {
189f7ac1bd3Serh 		Elf_Shdr *s = &sh[i];
1904d9a6e09Schristos 
1914d9a6e09Schristos 		/*
1924d9a6e09Schristos 		 * Identify candidates for the comment header;
193d83602c1Schristos 		 * Header cannot have a load address, or flags and
1944d9a6e09Schristos 		 * it must be large enough.
1954d9a6e09Schristos 		 */
196522cbf02Skleink 		if (s->sh_type != SHT_PROGBITS ||
1974d9a6e09Schristos 		    s->sh_addr != 0 ||
1984d9a6e09Schristos 		    s->sh_flags != 0 ||
1994d9a6e09Schristos 		    s->sh_size < sizeof(signature) - 1)
2004d9a6e09Schristos 			continue;
2014d9a6e09Schristos 
20295e1ffb1Schristos 		error = exec_read_from(l, epp->ep_vp, s->sh_offset, tbuf,
20397c9d7a9Schristos 		    sizeof(signature) - 1);
204b29180b2Smycroft 		if (error)
205b29180b2Smycroft 			continue;
2064d9a6e09Schristos 
207d83602c1Schristos 		/*
208d83602c1Schristos 		 * error is 0, if the signatures match we are done.
209d83602c1Schristos 		 */
210fb4b40b7Schristos 		DPRINTF(("linux_gcc_sig: sig=%s\n", tbuf));
211fb4b40b7Schristos 		if (!memcmp(tbuf, signature, sizeof(signature) - 1)) {
212b29180b2Smycroft 			error = 0;
2134d9a6e09Schristos 			goto out;
2144d9a6e09Schristos 		}
215b29180b2Smycroft 	}
216b29180b2Smycroft 	error = ENOEXEC;
2174d9a6e09Schristos 
2184d9a6e09Schristos out:
2194d9a6e09Schristos 	free(sh, M_TEMP);
220b29180b2Smycroft 	return (error);
2214d9a6e09Schristos }
222f7ac1bd3Serh #endif
2234d9a6e09Schristos 
22405c8a1b8Smanu #ifdef LINUX_DEBUGLINK_SIGNATURE
22505c8a1b8Smanu /*
22605c8a1b8Smanu  * Look for a .gnu_debuglink, specific to x86_64 interpeter
22705c8a1b8Smanu  */
22805c8a1b8Smanu int
22905c8a1b8Smanu ELFNAME2(linux,debuglink_signature)(l, epp, eh)
23005c8a1b8Smanu 	struct lwp *l;
23105c8a1b8Smanu 	struct exec_package *epp;
23205c8a1b8Smanu 	Elf_Ehdr *eh;
23305c8a1b8Smanu {
23405c8a1b8Smanu 	size_t shsize;
23505c8a1b8Smanu 	int strndx;
23605c8a1b8Smanu 	size_t i;
23705c8a1b8Smanu 	static const char signature[] = ".gnu_debuglink";
23805c8a1b8Smanu 	char *strtable = NULL;
23905c8a1b8Smanu 	Elf_Shdr *sh;
24005c8a1b8Smanu 
24105c8a1b8Smanu 	int error;
24205c8a1b8Smanu 
24305c8a1b8Smanu 	/*
24405c8a1b8Smanu 	 * load the section header table
24505c8a1b8Smanu 	 */
24605c8a1b8Smanu 	shsize = eh->e_shnum * sizeof(Elf_Shdr);
24705c8a1b8Smanu 	sh = (Elf_Shdr *) malloc(shsize, M_TEMP, M_WAITOK);
24805c8a1b8Smanu 	error = exec_read_from(l, epp->ep_vp, eh->e_shoff, sh, shsize);
24905c8a1b8Smanu 	if (error)
25005c8a1b8Smanu 		goto out;
25105c8a1b8Smanu 
25205c8a1b8Smanu 	/*
25305c8a1b8Smanu 	 * Now let's find the string table. If it does not exists, give up.
25405c8a1b8Smanu 	 */
25505c8a1b8Smanu 	strndx = (int)(eh->e_shstrndx);
25605c8a1b8Smanu 	if (strndx == SHN_UNDEF) {
25705c8a1b8Smanu 		error = ENOEXEC;
25805c8a1b8Smanu 		goto out;
25905c8a1b8Smanu 	}
26005c8a1b8Smanu 
26105c8a1b8Smanu 	/*
26205c8a1b8Smanu 	 * strndx is the index in section header table of the string table
26305c8a1b8Smanu 	 * section get the whole string table in strtable, and then we get access to the names
26405c8a1b8Smanu 	 * s->sh_name is the offset of the section name in strtable.
26505c8a1b8Smanu 	 */
26605c8a1b8Smanu 	strtable = malloc(sh[strndx].sh_size, M_TEMP, M_WAITOK);
26705c8a1b8Smanu 	error = exec_read_from(l, epp->ep_vp, sh[strndx].sh_offset, strtable,
26805c8a1b8Smanu 	    sh[strndx].sh_size);
26905c8a1b8Smanu 	if (error)
27005c8a1b8Smanu 		goto out;
27105c8a1b8Smanu 
27205c8a1b8Smanu 	for (i = 0; i < eh->e_shnum; i++) {
27305c8a1b8Smanu 		Elf_Shdr *s = &sh[i];
27405c8a1b8Smanu 
27505c8a1b8Smanu 		if (!memcmp((void*)(&(strtable[s->sh_name])), signature,
27605c8a1b8Smanu 				sizeof(signature))) {
27705c8a1b8Smanu 			DPRINTF(("linux_debuglink_sig=%s\n",
27805c8a1b8Smanu 			    &(strtable[s->sh_name])));
27905c8a1b8Smanu 			error = 0;
28005c8a1b8Smanu 			goto out;
28105c8a1b8Smanu 		}
28205c8a1b8Smanu 	}
28305c8a1b8Smanu 	error = ENOEXEC;
28405c8a1b8Smanu 
28505c8a1b8Smanu out:
28605c8a1b8Smanu 	free(sh, M_TEMP);
28705c8a1b8Smanu 	if (strtable)
28805c8a1b8Smanu 		free(strtable, M_TEMP);
28905c8a1b8Smanu 	return (error);
29005c8a1b8Smanu }
29105c8a1b8Smanu #endif
29205c8a1b8Smanu 
293ee0c5b44Smanu int
29495e1ffb1Schristos ELFNAME2(linux,signature)(l, epp, eh, itp)
29595e1ffb1Schristos 	struct lwp *l;
2964d9a6e09Schristos 	struct exec_package *epp;
297f7ac1bd3Serh 	Elf_Ehdr *eh;
298b29180b2Smycroft 	char *itp;
299f7ac1bd3Serh {
300f7ac1bd3Serh 	size_t i;
301f7ac1bd3Serh 	Elf_Phdr *ph;
302f7ac1bd3Serh 	size_t phsize;
303b29180b2Smycroft 	int error;
3046cc14962Schristos 	static const char linux[] = "Linux";
3056cc14962Schristos 
3066cc14962Schristos 	if (eh->e_ident[EI_OSABI] == 3 ||
3076cc14962Schristos 	    memcmp(&eh->e_ident[EI_ABIVERSION], linux, sizeof(linux)) == 0)
3086cc14962Schristos 		return 0;
309f7ac1bd3Serh 
310f7ac1bd3Serh 	phsize = eh->e_phnum * sizeof(Elf_Phdr);
311f7ac1bd3Serh 	ph = (Elf_Phdr *)malloc(phsize, M_TEMP, M_WAITOK);
31295e1ffb1Schristos 	error = exec_read_from(l, epp->ep_vp, eh->e_phoff, ph, phsize);
313b29180b2Smycroft 	if (error)
314b29180b2Smycroft 		goto out;
315f7ac1bd3Serh 
316f7ac1bd3Serh 	for (i = 0; i < eh->e_phnum; i++) {
317f7ac1bd3Serh 		Elf_Phdr *ephp = &ph[i];
318b29180b2Smycroft 		Elf_Nhdr *np;
319b29180b2Smycroft 		u_int32_t *abi;
320f7ac1bd3Serh 
321b29180b2Smycroft 		if (ephp->p_type != PT_NOTE ||
322b29180b2Smycroft 		    ephp->p_filesz > 1024 ||
323b29180b2Smycroft 		    ephp->p_filesz < sizeof(Elf_Nhdr) + 20)
324f7ac1bd3Serh 			continue;
325f7ac1bd3Serh 
326b29180b2Smycroft 		np = (Elf_Nhdr *)malloc(ephp->p_filesz, M_TEMP, M_WAITOK);
32795e1ffb1Schristos 		error = exec_read_from(l, epp->ep_vp, ephp->p_offset, np,
32897c9d7a9Schristos 		    ephp->p_filesz);
329b29180b2Smycroft 		if (error)
330b29180b2Smycroft 			goto next;
331f7ac1bd3Serh 
332b29180b2Smycroft 		if (np->n_type != ELF_NOTE_TYPE_ABI_TAG ||
333b29180b2Smycroft 		    np->n_namesz != ELF_NOTE_ABI_NAMESZ ||
334b29180b2Smycroft 		    np->n_descsz != ELF_NOTE_ABI_DESCSZ ||
33553524e44Schristos 		    memcmp((void *)(np + 1), ELF_NOTE_ABI_NAME,
336b29180b2Smycroft 		    ELF_NOTE_ABI_NAMESZ))
337b29180b2Smycroft 			goto next;
338b29180b2Smycroft 
339b29180b2Smycroft 		/* Make sure the OS is Linux. */
34053524e44Schristos 		abi = (u_int32_t *)((char *)np + sizeof(Elf_Nhdr) +
341b29180b2Smycroft 		    np->n_namesz);
342b29180b2Smycroft 		if (abi[0] == ELF_NOTE_ABI_OS_LINUX)
343f7ac1bd3Serh 			error = 0;
344b29180b2Smycroft 		else
345b29180b2Smycroft 			error = ENOEXEC;
346b29180b2Smycroft 		free(np, M_TEMP);
347b29180b2Smycroft 		goto out;
348f7ac1bd3Serh 
349b29180b2Smycroft 	next:
350b29180b2Smycroft 		free(np, M_TEMP);
351f7ac1bd3Serh 		continue;
352f7ac1bd3Serh 	}
353f7ac1bd3Serh 
354b29180b2Smycroft 	/* Check for certain intepreter names. */
355714de045Sdrochner 	if (itp) {
356b29180b2Smycroft 		if (!strncmp(itp, "/lib/ld-linux", 13) ||
35789647c7cSmanu #if (ELFSIZE == 64)
35889647c7cSmanu 		    !strncmp(itp, "/lib64/ld-linux", 15) ||
35989647c7cSmanu #endif
360b29180b2Smycroft 		    !strncmp(itp, "/lib/ld.so.", 11))
361f7ac1bd3Serh 			error = 0;
362b29180b2Smycroft 		else
363b29180b2Smycroft 			error = ENOEXEC;
364b29180b2Smycroft 		goto out;
365f7ac1bd3Serh 	}
366f7ac1bd3Serh 
367f7ac1bd3Serh 	error = ENOEXEC;
368b29180b2Smycroft out:
369f7ac1bd3Serh 	free(ph, M_TEMP);
370b29180b2Smycroft 	return (error);
371f7ac1bd3Serh }
372f7ac1bd3Serh 
373f7ac1bd3Serh int
3744d595fd7Schristos ELFNAME2(linux,probe)(struct lwp *l, struct exec_package *epp, void *eh,
375168cd830Schristos     char *itp, vaddr_t *pos)
376fc7cfb5fSfvdl {
377fc7cfb5fSfvdl 	int error;
378fc7cfb5fSfvdl 
37995e1ffb1Schristos 	if (((error = ELFNAME2(linux,signature)(l, epp, eh, itp)) != 0) &&
380f7ac1bd3Serh #ifdef LINUX_GCC_SIGNATURE
38195e1ffb1Schristos 	    ((error = ELFNAME2(linux,gcc_signature)(l, epp, eh)) != 0) &&
3828537f76cSmanu #endif
383ac10cf69Smanu #ifdef LINUX_ATEXIT_SIGNATURE
38495e1ffb1Schristos 	    ((error = ELFNAME2(linux,atexit_signature)(l, epp, eh)) != 0) &&
385ac10cf69Smanu #endif
38605c8a1b8Smanu #ifdef LINUX_DEBUGLINK_SIGNATURE
38705c8a1b8Smanu 	    ((error = ELFNAME2(linux,debuglink_signature)(l, epp, eh)) != 0) &&
38805c8a1b8Smanu #endif
38905c8a1b8Smanu 	    1) {
39005c8a1b8Smanu 			DPRINTF(("linux_probe: returning %d\n", error));
3918537f76cSmanu 			return error;
39205c8a1b8Smanu 	}
3934d9a6e09Schristos 
394714de045Sdrochner 	if (itp) {
395b8fbaf8cSdsl 		if ((error = emul_find_interp(l, epp, itp)))
39647cd9b85Sjdolecek 			return (error);
397fc7cfb5fSfvdl 	}
39865fc8539Schristos 	DPRINTF(("linux_probe: returning 0\n"));
399c4aaa600Sfvdl 	return 0;
400fc7cfb5fSfvdl }
401c4aaa600Sfvdl 
402cee43b67Sjdolecek #ifndef LINUX_MACHDEP_ELF_COPYARGS
403cee43b67Sjdolecek /*
404cee43b67Sjdolecek  * Copy arguments onto the stack in the normal way, but add some
405cee43b67Sjdolecek  * extra information in case of dynamic binding.
406cee43b67Sjdolecek  */
407cee43b67Sjdolecek int
40895e1ffb1Schristos ELFNAME2(linux,copyargs)(struct lwp *l, struct exec_package *pack,
409cee43b67Sjdolecek     struct ps_strings *arginfo, char **stackp, void *argp)
410cee43b67Sjdolecek {
411cee43b67Sjdolecek 	size_t len;
412cee43b67Sjdolecek 	AuxInfo ai[LINUX_ELF_AUX_ENTRIES], *a;
413cee43b67Sjdolecek 	struct elf_args *ap;
414cee43b67Sjdolecek 	int error;
415cee43b67Sjdolecek 	struct vattr *vap;
416cee43b67Sjdolecek 
41795e1ffb1Schristos 	if ((error = copyargs(l, pack, arginfo, stackp, argp)) != 0)
418cee43b67Sjdolecek 		return error;
419cee43b67Sjdolecek 
420cee43b67Sjdolecek 	a = ai;
421cee43b67Sjdolecek 
422cee43b67Sjdolecek 	/*
423cee43b67Sjdolecek 	 * Push extra arguments used by glibc on the stack.
424cee43b67Sjdolecek 	 */
425cee43b67Sjdolecek 
426cee43b67Sjdolecek 	a->a_type = AT_PAGESZ;
427cee43b67Sjdolecek 	a->a_v = PAGE_SIZE;
428cee43b67Sjdolecek 	a++;
429cee43b67Sjdolecek 
430cee43b67Sjdolecek 	if ((ap = (struct elf_args *)pack->ep_emul_arg)) {
431cee43b67Sjdolecek 
432cee43b67Sjdolecek 		a->a_type = AT_PHDR;
433cee43b67Sjdolecek 		a->a_v = ap->arg_phaddr;
434cee43b67Sjdolecek 		a++;
435cee43b67Sjdolecek 
436cee43b67Sjdolecek 		a->a_type = AT_PHENT;
437cee43b67Sjdolecek 		a->a_v = ap->arg_phentsize;
438cee43b67Sjdolecek 		a++;
439cee43b67Sjdolecek 
440cee43b67Sjdolecek 		a->a_type = AT_PHNUM;
441cee43b67Sjdolecek 		a->a_v = ap->arg_phnum;
442cee43b67Sjdolecek 		a++;
443cee43b67Sjdolecek 
444cee43b67Sjdolecek 		a->a_type = AT_BASE;
445cee43b67Sjdolecek 		a->a_v = ap->arg_interp;
446cee43b67Sjdolecek 		a++;
447cee43b67Sjdolecek 
448cee43b67Sjdolecek 		a->a_type = AT_FLAGS;
449cee43b67Sjdolecek 		a->a_v = 0;
450cee43b67Sjdolecek 		a++;
451cee43b67Sjdolecek 
452cee43b67Sjdolecek 		a->a_type = AT_ENTRY;
453cee43b67Sjdolecek 		a->a_v = ap->arg_entry;
454cee43b67Sjdolecek 		a++;
455cee43b67Sjdolecek 
456cee43b67Sjdolecek 		free(pack->ep_emul_arg, M_TEMP);
457cee43b67Sjdolecek 		pack->ep_emul_arg = NULL;
458cee43b67Sjdolecek 	}
459cee43b67Sjdolecek 
460cee43b67Sjdolecek 	/* Linux-specific items */
461cee43b67Sjdolecek 	a->a_type = LINUX_AT_CLKTCK;
462cee43b67Sjdolecek 	a->a_v = hz;
463cee43b67Sjdolecek 	a++;
464cee43b67Sjdolecek 
465cee43b67Sjdolecek 	vap = pack->ep_vap;
466cee43b67Sjdolecek 
467cee43b67Sjdolecek 	a->a_type = LINUX_AT_UID;
468f474dcebSad 	a->a_v = kauth_cred_getuid(l->l_cred);
469cee43b67Sjdolecek 	a++;
470cee43b67Sjdolecek 
471cee43b67Sjdolecek 	a->a_type = LINUX_AT_EUID;
472cee43b67Sjdolecek 	if (vap->va_mode & S_ISUID)
473cee43b67Sjdolecek 		a->a_v = vap->va_uid;
474cee43b67Sjdolecek 	else
475f474dcebSad 		a->a_v = kauth_cred_geteuid(l->l_cred);
476cee43b67Sjdolecek 	a++;
477cee43b67Sjdolecek 
478cee43b67Sjdolecek 	a->a_type = LINUX_AT_GID;
479f474dcebSad 	a->a_v = kauth_cred_getgid(l->l_cred);
480cee43b67Sjdolecek 	a++;
481cee43b67Sjdolecek 
482cee43b67Sjdolecek 	a->a_type = LINUX_AT_EGID;
483cee43b67Sjdolecek 	if (vap->va_mode & S_ISGID)
484cee43b67Sjdolecek 		a->a_v = vap->va_gid;
485cee43b67Sjdolecek 	else
486f474dcebSad 		a->a_v = kauth_cred_getegid(l->l_cred);
487cee43b67Sjdolecek 	a++;
488cee43b67Sjdolecek 
489cee43b67Sjdolecek 	a->a_type = AT_NULL;
490cee43b67Sjdolecek 	a->a_v = 0;
491cee43b67Sjdolecek 	a++;
492cee43b67Sjdolecek 
493cee43b67Sjdolecek 	len = (a - ai) * sizeof(AuxInfo);
494cee43b67Sjdolecek 	if ((error = copyout(ai, *stackp, len)) != 0)
495cee43b67Sjdolecek 		return error;
496cee43b67Sjdolecek 	*stackp += len;
497cee43b67Sjdolecek 
498cee43b67Sjdolecek 	return 0;
499cee43b67Sjdolecek }
500cee43b67Sjdolecek #endif /* !LINUX_MACHDEP_ELF_COPYARGS */
501