xref: /netbsd-src/sys/compat/linux/common/linux_exec_elf32.c (revision fb4b40b7e88f729bb1ceefb180c21d3ac2be1daf)
1*fb4b40b7Schristos /*	$NetBSD: linux_exec_elf32.c,v 1.69 2005/05/29 22:08:16 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*fb4b40b7Schristos __KERNEL_RCSID(0, "$NetBSD: linux_exec_elf32.c,v 1.69 2005/05/29 22:08:16 christos 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>
633bf459f3Sfvdl 
643bf459f3Sfvdl #include <sys/mman.h>
6546141a31Sthorpej #include <sys/sa.h>
66151fa70fSchristos #include <sys/syscallargs.h>
67151fa70fSchristos 
683bf459f3Sfvdl #include <machine/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 
80d5aece61Sfvdl static int ELFNAME2(linux,signature) __P((struct proc *, struct exec_package *,
81b29180b2Smycroft 	Elf_Ehdr *, char *));
82f7ac1bd3Serh #ifdef LINUX_GCC_SIGNATURE
83d5aece61Sfvdl static int ELFNAME2(linux,gcc_signature) __P((struct proc *p,
84f7ac1bd3Serh 	struct exec_package *, Elf_Ehdr *));
85f7ac1bd3Serh #endif
86ac10cf69Smanu #ifdef LINUX_ATEXIT_SIGNATURE
87d5aece61Sfvdl static int ELFNAME2(linux,atexit_signature) __P((struct proc *p,
88ac10cf69Smanu 	struct exec_package *, Elf_Ehdr *));
89ac10cf69Smanu #endif
90ac10cf69Smanu 
9165fc8539Schristos #ifdef DEBUG_LINUX
9265fc8539Schristos #define DPRINTF(a)	uprintf a
9365fc8539Schristos #else
9465fc8539Schristos #define DPRINTF(a)
9565fc8539Schristos #endif
9665fc8539Schristos 
97ac10cf69Smanu #ifdef LINUX_ATEXIT_SIGNATURE
98ac10cf69Smanu /*
99ac10cf69Smanu  * On the PowerPC, statically linked Linux binaries are not recognized
100ac10cf69Smanu  * by linux_signature nor by linux_gcc_signature. Fortunately, thoses
101ac10cf69Smanu  * binaries features a __libc_atexit ELF section. We therefore assume we
102ac10cf69Smanu  * have a Linux binary if we find this section.
103ac10cf69Smanu  */
104ac10cf69Smanu static int
105d5aece61Sfvdl ELFNAME2(linux,atexit_signature)(p, epp, eh)
106d5aece61Sfvdl 	struct proc *p;
107ac10cf69Smanu 	struct exec_package *epp;
108ac10cf69Smanu 	Elf_Ehdr *eh;
109ac10cf69Smanu {
110ac10cf69Smanu 	size_t shsize;
111ac10cf69Smanu 	int strndx;
112ac10cf69Smanu 	size_t i;
113ac10cf69Smanu 	static const char signature[] = "__libc_atexit";
1143b6d3c71Schs 	char *strtable = NULL;
115ac10cf69Smanu 	Elf_Shdr *sh;
116ac10cf69Smanu 
117ac10cf69Smanu 	int error;
118ac10cf69Smanu 
119ac10cf69Smanu 	/*
120ac10cf69Smanu 	 * load the section header table
121ac10cf69Smanu 	 */
122ac10cf69Smanu 	shsize = eh->e_shnum * sizeof(Elf_Shdr);
123ac10cf69Smanu 	sh = (Elf_Shdr *) malloc(shsize, M_TEMP, M_WAITOK);
124d5aece61Sfvdl 	error = exec_read_from(p, epp->ep_vp, eh->e_shoff, sh, shsize);
125ac10cf69Smanu 	if (error)
126ac10cf69Smanu 		goto out;
127ac10cf69Smanu 
128ac10cf69Smanu 	/*
129ac10cf69Smanu 	 * Now let's find the string table. If it does not exists, give up.
130ac10cf69Smanu 	 */
131ac10cf69Smanu 	strndx = (int)(eh->e_shstrndx);
132ac10cf69Smanu 	if (strndx == SHN_UNDEF) {
133ac10cf69Smanu 		error = ENOEXEC;
134ac10cf69Smanu 		goto out;
135ac10cf69Smanu 	}
136ac10cf69Smanu 
137ac10cf69Smanu 	/*
13897c9d7a9Schristos 	 * strndx is the index in section header table of the string table
13997c9d7a9Schristos 	 * section get the whole string table in strtable, and then we get access to the names
140ac10cf69Smanu 	 * s->sh_name is the offset of the section name in strtable.
141ac10cf69Smanu 	 */
142ac10cf69Smanu 	strtable = malloc(sh[strndx].sh_size, M_TEMP, M_WAITOK);
143d5aece61Sfvdl 	error = exec_read_from(p, epp->ep_vp, sh[strndx].sh_offset, strtable,
14497c9d7a9Schristos 	    sh[strndx].sh_size);
145ac10cf69Smanu 	if (error)
146ac10cf69Smanu 		goto out;
147ac10cf69Smanu 
148ac10cf69Smanu 	for (i = 0; i < eh->e_shnum; i++) {
149ac10cf69Smanu 		Elf_Shdr *s = &sh[i];
150ac10cf69Smanu 		if (!memcmp((void*)(&(strtable[s->sh_name])), signature,
151ac10cf69Smanu 				sizeof(signature))) {
15265fc8539Schristos 			DPRINTF(("linux_atexit_sig=%s\n",
15365fc8539Schristos 			    &(strtable[s->sh_name])));
154ac10cf69Smanu 			error = 0;
155ac10cf69Smanu 			goto out;
156ac10cf69Smanu 		}
157ac10cf69Smanu 	}
158ac10cf69Smanu 	error = ENOEXEC;
159ac10cf69Smanu 
160ac10cf69Smanu out:
161ac10cf69Smanu 	free(sh, M_TEMP);
1623b6d3c71Schs 	if (strtable)
163ac10cf69Smanu 		free(strtable, M_TEMP);
164ac10cf69Smanu 	return (error);
165ac10cf69Smanu }
166ac10cf69Smanu #endif
167f7ac1bd3Serh 
168f7ac1bd3Serh #ifdef LINUX_GCC_SIGNATURE
1694d9a6e09Schristos /*
1704d9a6e09Schristos  * Take advantage of the fact that all the linux binaries are compiled
1714d9a6e09Schristos  * with gcc, and gcc sticks in the comment field a signature. Note that
1724d9a6e09Schristos  * on SVR4 binaries, the gcc signature will follow the OS name signature,
1734d9a6e09Schristos  * that will not be a problem. We don't bother to read in the string table,
1744d9a6e09Schristos  * but we check all the progbits headers.
175f7ac1bd3Serh  *
176f7ac1bd3Serh  * XXX This only works in the i386.  On the alpha (at least)
177f7ac1bd3Serh  * XXX we have the same gcc signature which incorrectly identifies
178f7ac1bd3Serh  * XXX NetBSD binaries as Linux.
1794d9a6e09Schristos  */
1804d9a6e09Schristos static int
181d5aece61Sfvdl ELFNAME2(linux,gcc_signature)(p, epp, eh)
182d5aece61Sfvdl 	struct proc *p;
183fc7cfb5fSfvdl 	struct exec_package *epp;
184f7ac1bd3Serh 	Elf_Ehdr *eh;
1854d9a6e09Schristos {
186b29180b2Smycroft 	size_t shsize;
1874d9a6e09Schristos 	size_t i;
1884d9a6e09Schristos 	static const char signature[] = "\0GCC: (GNU) ";
189*fb4b40b7Schristos 	char tbuf[sizeof(signature) - 1];
190f7ac1bd3Serh 	Elf_Shdr *sh;
1914d9a6e09Schristos 	int error;
1924d9a6e09Schristos 
193b29180b2Smycroft 	shsize = eh->e_shnum * sizeof(Elf_Shdr);
194f7ac1bd3Serh 	sh = (Elf_Shdr *) malloc(shsize, M_TEMP, M_WAITOK);
195d5aece61Sfvdl 	error = exec_read_from(p, epp->ep_vp, eh->e_shoff, sh, shsize);
196b29180b2Smycroft 	if (error)
1974d9a6e09Schristos 		goto out;
1984d9a6e09Schristos 
1994d9a6e09Schristos 	for (i = 0; i < eh->e_shnum; i++) {
200f7ac1bd3Serh 		Elf_Shdr *s = &sh[i];
2014d9a6e09Schristos 
2024d9a6e09Schristos 		/*
2034d9a6e09Schristos 		 * Identify candidates for the comment header;
204d83602c1Schristos 		 * Header cannot have a load address, or flags and
2054d9a6e09Schristos 		 * it must be large enough.
2064d9a6e09Schristos 		 */
207522cbf02Skleink 		if (s->sh_type != SHT_PROGBITS ||
2084d9a6e09Schristos 		    s->sh_addr != 0 ||
2094d9a6e09Schristos 		    s->sh_flags != 0 ||
2104d9a6e09Schristos 		    s->sh_size < sizeof(signature) - 1)
2114d9a6e09Schristos 			continue;
2124d9a6e09Schristos 
213*fb4b40b7Schristos 		error = exec_read_from(p, epp->ep_vp, s->sh_offset, tbuf,
21497c9d7a9Schristos 		    sizeof(signature) - 1);
215b29180b2Smycroft 		if (error)
216b29180b2Smycroft 			continue;
2174d9a6e09Schristos 
218d83602c1Schristos 		/*
219d83602c1Schristos 		 * error is 0, if the signatures match we are done.
220d83602c1Schristos 		 */
221*fb4b40b7Schristos 		DPRINTF(("linux_gcc_sig: sig=%s\n", tbuf));
222*fb4b40b7Schristos 		if (!memcmp(tbuf, signature, sizeof(signature) - 1)) {
223b29180b2Smycroft 			error = 0;
2244d9a6e09Schristos 			goto out;
2254d9a6e09Schristos 		}
226b29180b2Smycroft 	}
227b29180b2Smycroft 	error = ENOEXEC;
2284d9a6e09Schristos 
2294d9a6e09Schristos out:
2304d9a6e09Schristos 	free(sh, M_TEMP);
231b29180b2Smycroft 	return (error);
2324d9a6e09Schristos }
233f7ac1bd3Serh #endif
2344d9a6e09Schristos 
235f7ac1bd3Serh static int
236d5aece61Sfvdl ELFNAME2(linux,signature)(p, epp, eh, itp)
237d5aece61Sfvdl 	struct proc *p;
2384d9a6e09Schristos 	struct exec_package *epp;
239f7ac1bd3Serh 	Elf_Ehdr *eh;
240b29180b2Smycroft 	char *itp;
241f7ac1bd3Serh {
242f7ac1bd3Serh 	size_t i;
243f7ac1bd3Serh 	Elf_Phdr *ph;
244f7ac1bd3Serh 	size_t phsize;
245b29180b2Smycroft 	int error;
2466cc14962Schristos 	static const char linux[] = "Linux";
2476cc14962Schristos 
2486cc14962Schristos 	if (eh->e_ident[EI_OSABI] == 3 ||
2496cc14962Schristos 	    memcmp(&eh->e_ident[EI_ABIVERSION], linux, sizeof(linux)) == 0)
2506cc14962Schristos 		return 0;
251f7ac1bd3Serh 
252f7ac1bd3Serh 	phsize = eh->e_phnum * sizeof(Elf_Phdr);
253f7ac1bd3Serh 	ph = (Elf_Phdr *)malloc(phsize, M_TEMP, M_WAITOK);
254d5aece61Sfvdl 	error = exec_read_from(p, epp->ep_vp, eh->e_phoff, ph, phsize);
255b29180b2Smycroft 	if (error)
256b29180b2Smycroft 		goto out;
257f7ac1bd3Serh 
258f7ac1bd3Serh 	for (i = 0; i < eh->e_phnum; i++) {
259f7ac1bd3Serh 		Elf_Phdr *ephp = &ph[i];
260b29180b2Smycroft 		Elf_Nhdr *np;
261b29180b2Smycroft 		u_int32_t *abi;
262f7ac1bd3Serh 
263b29180b2Smycroft 		if (ephp->p_type != PT_NOTE ||
264b29180b2Smycroft 		    ephp->p_filesz > 1024 ||
265b29180b2Smycroft 		    ephp->p_filesz < sizeof(Elf_Nhdr) + 20)
266f7ac1bd3Serh 			continue;
267f7ac1bd3Serh 
268b29180b2Smycroft 		np = (Elf_Nhdr *)malloc(ephp->p_filesz, M_TEMP, M_WAITOK);
269d5aece61Sfvdl 		error = exec_read_from(p, epp->ep_vp, ephp->p_offset, np,
27097c9d7a9Schristos 		    ephp->p_filesz);
271b29180b2Smycroft 		if (error)
272b29180b2Smycroft 			goto next;
273f7ac1bd3Serh 
274b29180b2Smycroft 		if (np->n_type != ELF_NOTE_TYPE_ABI_TAG ||
275b29180b2Smycroft 		    np->n_namesz != ELF_NOTE_ABI_NAMESZ ||
276b29180b2Smycroft 		    np->n_descsz != ELF_NOTE_ABI_DESCSZ ||
277b29180b2Smycroft 		    memcmp((caddr_t)(np + 1), ELF_NOTE_ABI_NAME,
278b29180b2Smycroft 		    ELF_NOTE_ABI_NAMESZ))
279b29180b2Smycroft 			goto next;
280b29180b2Smycroft 
281b29180b2Smycroft 		/* Make sure the OS is Linux. */
282b29180b2Smycroft 		abi = (u_int32_t *)((caddr_t)np + sizeof(Elf_Nhdr) +
283b29180b2Smycroft 		    np->n_namesz);
284b29180b2Smycroft 		if (abi[0] == ELF_NOTE_ABI_OS_LINUX)
285f7ac1bd3Serh 			error = 0;
286b29180b2Smycroft 		else
287b29180b2Smycroft 			error = ENOEXEC;
288b29180b2Smycroft 		free(np, M_TEMP);
289b29180b2Smycroft 		goto out;
290f7ac1bd3Serh 
291b29180b2Smycroft 	next:
292b29180b2Smycroft 		free(np, M_TEMP);
293f7ac1bd3Serh 		continue;
294f7ac1bd3Serh 	}
295f7ac1bd3Serh 
296b29180b2Smycroft 	/* Check for certain intepreter names. */
297714de045Sdrochner 	if (itp) {
298b29180b2Smycroft 		if (!strncmp(itp, "/lib/ld-linux", 13) ||
29989647c7cSmanu #if (ELFSIZE == 64)
30089647c7cSmanu 		    !strncmp(itp, "/lib64/ld-linux", 15) ||
30189647c7cSmanu #endif
302b29180b2Smycroft 		    !strncmp(itp, "/lib/ld.so.", 11))
303f7ac1bd3Serh 			error = 0;
304b29180b2Smycroft 		else
305b29180b2Smycroft 			error = ENOEXEC;
306b29180b2Smycroft 		goto out;
307f7ac1bd3Serh 	}
308f7ac1bd3Serh 
309f7ac1bd3Serh 	error = ENOEXEC;
310b29180b2Smycroft out:
311f7ac1bd3Serh 	free(ph, M_TEMP);
312b29180b2Smycroft 	return (error);
313f7ac1bd3Serh }
314f7ac1bd3Serh 
315f7ac1bd3Serh int
316d5aece61Sfvdl ELFNAME2(linux,probe)(p, epp, eh, itp, pos)
317d5aece61Sfvdl 	struct proc *p;
318f7ac1bd3Serh 	struct exec_package *epp;
319baae0324Sjdolecek 	void *eh;
320c4aaa600Sfvdl 	char *itp;
321baae0324Sjdolecek 	vaddr_t *pos;
322fc7cfb5fSfvdl {
323fc7cfb5fSfvdl 	int error;
324fc7cfb5fSfvdl 
325d5aece61Sfvdl 	if (((error = ELFNAME2(linux,signature)(p, epp, eh, itp)) != 0) &&
326f7ac1bd3Serh #ifdef LINUX_GCC_SIGNATURE
327d5aece61Sfvdl 	    ((error = ELFNAME2(linux,gcc_signature)(p, epp, eh)) != 0) &&
3288537f76cSmanu #endif
329ac10cf69Smanu #ifdef LINUX_ATEXIT_SIGNATURE
330d5aece61Sfvdl 	    ((error = ELFNAME2(linux,atexit_signature)(p, epp, eh)) != 0) &&
331ac10cf69Smanu #endif
3328537f76cSmanu 	    1)
3338537f76cSmanu 			return error;
3344d9a6e09Schristos 
335714de045Sdrochner 	if (itp) {
336d5aece61Sfvdl 		if ((error = emul_find_interp(p, epp->ep_esch->es_emul->e_path,
33747cd9b85Sjdolecek 		    itp)))
33847cd9b85Sjdolecek 			return (error);
339fc7cfb5fSfvdl 	}
34065fc8539Schristos 	DPRINTF(("linux_probe: returning 0\n"));
341c4aaa600Sfvdl 	return 0;
342fc7cfb5fSfvdl }
343c4aaa600Sfvdl 
344cee43b67Sjdolecek #ifndef LINUX_MACHDEP_ELF_COPYARGS
345cee43b67Sjdolecek /*
346cee43b67Sjdolecek  * Copy arguments onto the stack in the normal way, but add some
347cee43b67Sjdolecek  * extra information in case of dynamic binding.
348cee43b67Sjdolecek  */
349cee43b67Sjdolecek int
350d5aece61Sfvdl ELFNAME2(linux,copyargs)(struct proc *p, struct exec_package *pack,
351cee43b67Sjdolecek     struct ps_strings *arginfo, char **stackp, void *argp)
352cee43b67Sjdolecek {
353cee43b67Sjdolecek 	size_t len;
354cee43b67Sjdolecek 	AuxInfo ai[LINUX_ELF_AUX_ENTRIES], *a;
355cee43b67Sjdolecek 	struct elf_args *ap;
356cee43b67Sjdolecek 	int error;
357cee43b67Sjdolecek 	struct vattr *vap;
358cee43b67Sjdolecek 
359d5aece61Sfvdl 	if ((error = copyargs(p, pack, arginfo, stackp, argp)) != 0)
360cee43b67Sjdolecek 		return error;
361cee43b67Sjdolecek 
362cee43b67Sjdolecek 	a = ai;
363cee43b67Sjdolecek 
364cee43b67Sjdolecek 	/*
365cee43b67Sjdolecek 	 * Push extra arguments used by glibc on the stack.
366cee43b67Sjdolecek 	 */
367cee43b67Sjdolecek 
368cee43b67Sjdolecek 	a->a_type = AT_PAGESZ;
369cee43b67Sjdolecek 	a->a_v = PAGE_SIZE;
370cee43b67Sjdolecek 	a++;
371cee43b67Sjdolecek 
372cee43b67Sjdolecek 	if ((ap = (struct elf_args *)pack->ep_emul_arg)) {
373cee43b67Sjdolecek 
374cee43b67Sjdolecek 		a->a_type = AT_PHDR;
375cee43b67Sjdolecek 		a->a_v = ap->arg_phaddr;
376cee43b67Sjdolecek 		a++;
377cee43b67Sjdolecek 
378cee43b67Sjdolecek 		a->a_type = AT_PHENT;
379cee43b67Sjdolecek 		a->a_v = ap->arg_phentsize;
380cee43b67Sjdolecek 		a++;
381cee43b67Sjdolecek 
382cee43b67Sjdolecek 		a->a_type = AT_PHNUM;
383cee43b67Sjdolecek 		a->a_v = ap->arg_phnum;
384cee43b67Sjdolecek 		a++;
385cee43b67Sjdolecek 
386cee43b67Sjdolecek 		a->a_type = AT_BASE;
387cee43b67Sjdolecek 		a->a_v = ap->arg_interp;
388cee43b67Sjdolecek 		a++;
389cee43b67Sjdolecek 
390cee43b67Sjdolecek 		a->a_type = AT_FLAGS;
391cee43b67Sjdolecek 		a->a_v = 0;
392cee43b67Sjdolecek 		a++;
393cee43b67Sjdolecek 
394cee43b67Sjdolecek 		a->a_type = AT_ENTRY;
395cee43b67Sjdolecek 		a->a_v = ap->arg_entry;
396cee43b67Sjdolecek 		a++;
397cee43b67Sjdolecek 
398cee43b67Sjdolecek 		free(pack->ep_emul_arg, M_TEMP);
399cee43b67Sjdolecek 		pack->ep_emul_arg = NULL;
400cee43b67Sjdolecek 	}
401cee43b67Sjdolecek 
402cee43b67Sjdolecek 	/* Linux-specific items */
403cee43b67Sjdolecek 	a->a_type = LINUX_AT_CLKTCK;
404cee43b67Sjdolecek 	a->a_v = hz;
405cee43b67Sjdolecek 	a++;
406cee43b67Sjdolecek 
407cee43b67Sjdolecek 	vap = pack->ep_vap;
408cee43b67Sjdolecek 
409cee43b67Sjdolecek 	a->a_type = LINUX_AT_UID;
410cee43b67Sjdolecek 	a->a_v = p->p_cred->p_ruid;
411cee43b67Sjdolecek 	a++;
412cee43b67Sjdolecek 
413cee43b67Sjdolecek 	a->a_type = LINUX_AT_EUID;
414cee43b67Sjdolecek 	if (vap->va_mode & S_ISUID)
415cee43b67Sjdolecek 		a->a_v = vap->va_uid;
416cee43b67Sjdolecek 	else
417cee43b67Sjdolecek 		a->a_v = p->p_ucred->cr_uid;
418cee43b67Sjdolecek 	a++;
419cee43b67Sjdolecek 
420cee43b67Sjdolecek 	a->a_type = LINUX_AT_GID;
421cee43b67Sjdolecek 	a->a_v = p->p_cred->p_rgid;
422cee43b67Sjdolecek 	a++;
423cee43b67Sjdolecek 
424cee43b67Sjdolecek 	a->a_type = LINUX_AT_EGID;
425cee43b67Sjdolecek 	if (vap->va_mode & S_ISGID)
426cee43b67Sjdolecek 		a->a_v = vap->va_gid;
427cee43b67Sjdolecek 	else
428cee43b67Sjdolecek 		a->a_v = p->p_ucred->cr_gid;
429cee43b67Sjdolecek 	a++;
430cee43b67Sjdolecek 
431cee43b67Sjdolecek 	a->a_type = AT_NULL;
432cee43b67Sjdolecek 	a->a_v = 0;
433cee43b67Sjdolecek 	a++;
434cee43b67Sjdolecek 
435cee43b67Sjdolecek 	len = (a - ai) * sizeof(AuxInfo);
436cee43b67Sjdolecek 	if ((error = copyout(ai, *stackp, len)) != 0)
437cee43b67Sjdolecek 		return error;
438cee43b67Sjdolecek 	*stackp += len;
439cee43b67Sjdolecek 
440cee43b67Sjdolecek 	return 0;
441cee43b67Sjdolecek }
442cee43b67Sjdolecek #endif /* !LINUX_MACHDEP_ELF_COPYARGS */
443