xref: /netbsd-src/sys/compat/linux/common/linux_exec_aout.c (revision 6ad8aacf8efaf30139609016bdfb7cc13f00ea77)
1*6ad8aacfSmaxv /*	$NetBSD: linux_exec_aout.c,v 1.68 2015/10/18 16:59:19 maxv Exp $	*/
28fb507a3Schristos 
38fb507a3Schristos /*-
48096c25aSfvdl  * Copyright (c) 1995, 1998 The NetBSD Foundation, Inc.
58fb507a3Schristos  * All rights reserved.
68fb507a3Schristos  *
78fb507a3Schristos  * This code is derived from software contributed to The NetBSD Foundation
88096c25aSfvdl  * by Christos Zoulas, Frank van der Linden and Eric Haszlakiewicz.
98fb507a3Schristos  *
108fb507a3Schristos  * Redistribution and use in source and binary forms, with or without
118fb507a3Schristos  * modification, are permitted provided that the following conditions
128fb507a3Schristos  * are met:
138fb507a3Schristos  * 1. Redistributions of source code must retain the above copyright
148fb507a3Schristos  *    notice, this list of conditions and the following disclaimer.
158fb507a3Schristos  * 2. Redistributions in binary form must reproduce the above copyright
168fb507a3Schristos  *    notice, this list of conditions and the following disclaimer in the
178fb507a3Schristos  *    documentation and/or other materials provided with the distribution.
188fb507a3Schristos  *
198fb507a3Schristos  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
208fb507a3Schristos  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
218fb507a3Schristos  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
228fb507a3Schristos  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
238fb507a3Schristos  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
248fb507a3Schristos  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
258fb507a3Schristos  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
268fb507a3Schristos  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
278fb507a3Schristos  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
288fb507a3Schristos  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
298fb507a3Schristos  * POSSIBILITY OF SUCH DAMAGE.
308fb507a3Schristos  */
313bf459f3Sfvdl 
323bf459f3Sfvdl /*
33fb777788Sfvdl  * based on exec_aout.c, sunos_exec.c and svr4_exec.c
343bf459f3Sfvdl  */
353bf459f3Sfvdl 
36dab6ef8bSlukem #include <sys/cdefs.h>
37*6ad8aacfSmaxv __KERNEL_RCSID(0, "$NetBSD: linux_exec_aout.c,v 1.68 2015/10/18 16:59:19 maxv Exp $");
387bb407d6Smatt 
397bb407d6Smatt #ifdef _KERNEL_OPT
407bb407d6Smatt #include "opt_execfmt.h"
417bb407d6Smatt #endif
42dab6ef8bSlukem 
433bf459f3Sfvdl #include <sys/param.h>
443bf459f3Sfvdl #include <sys/systm.h>
453bf459f3Sfvdl #include <sys/kernel.h>
463bf459f3Sfvdl #include <sys/proc.h>
473bf459f3Sfvdl #include <sys/namei.h>
483bf459f3Sfvdl #include <sys/vnode.h>
49151fa70fSchristos #include <sys/mount.h>
50d551a4edSchristos #include <sys/exec.h>
513bf459f3Sfvdl 
523bf459f3Sfvdl #include <sys/mman.h>
53151fa70fSchristos #include <sys/syscallargs.h>
54151fa70fSchristos 
55a2a38285Sad #include <sys/cpu.h>
56f7ac1bd3Serh #include <machine/reg.h>
57908291d2Schristos 
58908291d2Schristos #include <compat/linux/common/linux_types.h>
59908291d2Schristos #include <compat/linux/common/linux_signal.h>
60908291d2Schristos #include <compat/linux/common/linux_util.h>
61908291d2Schristos #include <compat/linux/common/linux_exec.h>
62908291d2Schristos #include <compat/linux/common/linux_machdep.h>
63908291d2Schristos 
64908291d2Schristos #include <compat/linux/linux_syscallargs.h>
65908291d2Schristos #include <compat/linux/linux_syscall.h>
66908291d2Schristos 
67f2af9174Sdsl int linux_aout_copyargs(struct lwp *, struct exec_package *,
68f2af9174Sdsl     struct ps_strings *, char **, void *);
69fc7cfb5fSfvdl 
70f2af9174Sdsl static int exec_linux_aout_prep_zmagic(struct lwp *,
71f2af9174Sdsl     struct exec_package *);
72f2af9174Sdsl static int exec_linux_aout_prep_nmagic(struct lwp *,
73f2af9174Sdsl     struct exec_package *);
74f2af9174Sdsl static int exec_linux_aout_prep_omagic(struct lwp *,
75f2af9174Sdsl     struct exec_package *);
76f2af9174Sdsl static int exec_linux_aout_prep_qmagic(struct lwp *,
77f2af9174Sdsl     struct exec_package *);
78c4aaa600Sfvdl 
79934898bcSchristos int
linux_aout_copyargs(struct lwp * l,struct exec_package * pack,struct ps_strings * arginfo,char ** stackp,void * argp)80168cd830Schristos linux_aout_copyargs(struct lwp *l, struct exec_package *pack,
814d595fd7Schristos     struct ps_strings *arginfo, char **stackp, void *argp)
8244eef7c2Schristos {
83934898bcSchristos 	char **cpp = (char **)*stackp;
84934898bcSchristos 	char **stk = (char **)*stackp;
8544eef7c2Schristos 	char *dp, *sp;
8644eef7c2Schristos 	size_t len;
8744eef7c2Schristos 	void *nullp = NULL;
8844eef7c2Schristos 	int argc = arginfo->ps_nargvstr;
8944eef7c2Schristos 	int envc = arginfo->ps_nenvstr;
90934898bcSchristos 	int error;
9144eef7c2Schristos 
92934898bcSchristos 	if ((error = copyout(&argc, cpp++, sizeof(argc))) != 0)
93934898bcSchristos 		return error;
9444eef7c2Schristos 
9544eef7c2Schristos 	/* leave room for envp and argv */
9644eef7c2Schristos 	cpp += 2;
97934898bcSchristos 	if ((error = copyout(&cpp, &stk[1], sizeof (cpp))) != 0)
98934898bcSchristos 		return error;
9944eef7c2Schristos 
10044eef7c2Schristos 	dp = (char *) (cpp + argc + envc + 2);
10144eef7c2Schristos 	sp = argp;
10244eef7c2Schristos 
10344eef7c2Schristos 	/* XXX don't copy them out, remap them! */
104bfd22ffdSmycroft 	arginfo->ps_argvstr = cpp; /* remember location of argv for later */
10544eef7c2Schristos 
10644eef7c2Schristos 	for (; --argc >= 0; sp += len, dp += len)
107934898bcSchristos 		if ((error = copyout(&dp, cpp++, sizeof(dp))) != 0 ||
108934898bcSchristos 		    (error = copyoutstr(sp, dp, ARG_MAX, &len)) != 0)
109934898bcSchristos 			return error;
11044eef7c2Schristos 
111934898bcSchristos 	if ((error = copyout(&nullp, cpp++, sizeof(nullp))) != 0)
112934898bcSchristos 		return error;
11344eef7c2Schristos 
114934898bcSchristos 	if ((error = copyout(&cpp, &stk[2], sizeof (cpp))) != 0)
115934898bcSchristos 		return error;
11644eef7c2Schristos 
117bfd22ffdSmycroft 	arginfo->ps_envstr = cpp; /* remember location of envp for later */
11844eef7c2Schristos 
11944eef7c2Schristos 	for (; --envc >= 0; sp += len, dp += len)
120934898bcSchristos 		if ((error = copyout(&dp, cpp++, sizeof(dp))) != 0 ||
121934898bcSchristos 		    (error = copyoutstr(sp, dp, ARG_MAX, &len)) != 0)
122934898bcSchristos 			return error;
12344eef7c2Schristos 
124934898bcSchristos 	if ((error = copyout(&nullp, cpp++, sizeof(nullp))) != 0)
125934898bcSchristos 		return error;
12644eef7c2Schristos 
127934898bcSchristos 	*stackp = (char *)cpp;
128934898bcSchristos 	return 0;
12944eef7c2Schristos }
13044eef7c2Schristos 
1313bf459f3Sfvdl int
exec_linux_aout_makecmds(struct lwp * l,struct exec_package * epp)13228bae79bSdsl exec_linux_aout_makecmds(struct lwp *l, struct exec_package *epp)
1333bf459f3Sfvdl {
1343bf459f3Sfvdl 	struct exec *linux_ep = epp->ep_hdr;
1353bf459f3Sfvdl 	int machtype, magic;
1363bf459f3Sfvdl 	int error = ENOEXEC;
1373bf459f3Sfvdl 
138*6ad8aacfSmaxv 	if (epp->ep_hdrvalid < sizeof(struct exec))
139*6ad8aacfSmaxv 		return ENOEXEC;
140*6ad8aacfSmaxv 
1413bf459f3Sfvdl 	magic = LINUX_N_MAGIC(linux_ep);
1423bf459f3Sfvdl 	machtype = LINUX_N_MACHTYPE(linux_ep);
1433bf459f3Sfvdl 
1443bf459f3Sfvdl 	if (machtype != LINUX_MID_MACHINE)
1453bf459f3Sfvdl 		return (ENOEXEC);
1463bf459f3Sfvdl 
1473bf459f3Sfvdl 	switch (magic) {
1483bf459f3Sfvdl 	case QMAGIC:
14995e1ffb1Schristos 		error = exec_linux_aout_prep_qmagic(l, epp);
1503bf459f3Sfvdl 		break;
1513bf459f3Sfvdl 	case ZMAGIC:
15295e1ffb1Schristos 		error = exec_linux_aout_prep_zmagic(l, epp);
1533bf459f3Sfvdl 		break;
1543bf459f3Sfvdl 	case NMAGIC:
15595e1ffb1Schristos 		error = exec_linux_aout_prep_nmagic(l, epp);
1563bf459f3Sfvdl 		break;
1573bf459f3Sfvdl 	case OMAGIC:
15895e1ffb1Schristos 		error = exec_linux_aout_prep_omagic(l, epp);
1593bf459f3Sfvdl 		break;
1603bf459f3Sfvdl 	}
1613bf459f3Sfvdl 	return error;
1623bf459f3Sfvdl }
1633bf459f3Sfvdl 
1643bf459f3Sfvdl /*
1653bf459f3Sfvdl  * Since text starts at 0x400 in Linux ZMAGIC executables, and 0x400
1663bf459f3Sfvdl  * is very likely not page aligned on most architectures, it is treated
1673bf459f3Sfvdl  * as an NMAGIC here. XXX
1683bf459f3Sfvdl  */
1693bf459f3Sfvdl 
170baae0324Sjdolecek static int
exec_linux_aout_prep_zmagic(struct lwp * l,struct exec_package * epp)17128bae79bSdsl exec_linux_aout_prep_zmagic(struct lwp *l, struct exec_package *epp)
1723bf459f3Sfvdl {
1733bf459f3Sfvdl 	struct exec *execp = epp->ep_hdr;
1743bf459f3Sfvdl 
1753bf459f3Sfvdl 	epp->ep_taddr = LINUX_N_TXTADDR(*execp, ZMAGIC);
1763bf459f3Sfvdl 	epp->ep_tsize = execp->a_text;
1773bf459f3Sfvdl 	epp->ep_daddr = LINUX_N_DATADDR(*execp, ZMAGIC);
1783bf459f3Sfvdl 	epp->ep_dsize = execp->a_data + execp->a_bss;
1793bf459f3Sfvdl 	epp->ep_entry = execp->a_entry;
1803bf459f3Sfvdl 
1813bf459f3Sfvdl 	/* set up command for text segment */
1823bf459f3Sfvdl 	NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_readvn, execp->a_text,
1833bf459f3Sfvdl 	    epp->ep_taddr, epp->ep_vp, LINUX_N_TXTOFF(*execp, ZMAGIC),
1843bf459f3Sfvdl 	    VM_PROT_READ|VM_PROT_EXECUTE);
1853bf459f3Sfvdl 
1863bf459f3Sfvdl 	/* set up command for data segment */
1873bf459f3Sfvdl 	NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_readvn, execp->a_data,
1883bf459f3Sfvdl 	    epp->ep_daddr, epp->ep_vp, LINUX_N_DATOFF(*execp, ZMAGIC),
1893bf459f3Sfvdl 	    VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE);
1903bf459f3Sfvdl 
1913bf459f3Sfvdl 	/* set up command for bss segment */
1920b71a2d5Schristos 	if (execp->a_bss)
1933bf459f3Sfvdl 		NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, execp->a_bss,
1943bf459f3Sfvdl 		    epp->ep_daddr + execp->a_data, NULLVP, 0,
1953bf459f3Sfvdl 		    VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE);
1963bf459f3Sfvdl 
19795e1ffb1Schristos 	return (*epp->ep_esch->es_setup_stack)(l, epp);
1983bf459f3Sfvdl }
1993bf459f3Sfvdl 
2003bf459f3Sfvdl /*
2013bf459f3Sfvdl  * exec_aout_prep_nmagic(): Prepare Linux NMAGIC package.
2023bf459f3Sfvdl  * Not different from the normal stuff.
2033bf459f3Sfvdl  */
2043bf459f3Sfvdl 
205baae0324Sjdolecek static int
exec_linux_aout_prep_nmagic(struct lwp * l,struct exec_package * epp)20628bae79bSdsl exec_linux_aout_prep_nmagic(struct lwp *l, struct exec_package *epp)
2073bf459f3Sfvdl {
2083bf459f3Sfvdl 	struct exec *execp = epp->ep_hdr;
2093bf459f3Sfvdl 	long bsize, baddr;
2103bf459f3Sfvdl 
2113bf459f3Sfvdl 	epp->ep_taddr = LINUX_N_TXTADDR(*execp, NMAGIC);
2123bf459f3Sfvdl 	epp->ep_tsize = execp->a_text;
2133bf459f3Sfvdl 	epp->ep_daddr = LINUX_N_DATADDR(*execp, NMAGIC);
2143bf459f3Sfvdl 	epp->ep_dsize = execp->a_data + execp->a_bss;
2153bf459f3Sfvdl 	epp->ep_entry = execp->a_entry;
2163bf459f3Sfvdl 
2173bf459f3Sfvdl 	/* set up command for text segment */
2183bf459f3Sfvdl 	NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_readvn, execp->a_text,
2193bf459f3Sfvdl 	    epp->ep_taddr, epp->ep_vp, LINUX_N_TXTOFF(*execp, NMAGIC),
2203bf459f3Sfvdl 	    VM_PROT_READ|VM_PROT_EXECUTE);
2213bf459f3Sfvdl 
2223bf459f3Sfvdl 	/* set up command for data segment */
2233bf459f3Sfvdl 	NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_readvn, execp->a_data,
2243bf459f3Sfvdl 	    epp->ep_daddr, epp->ep_vp, LINUX_N_DATOFF(*execp, NMAGIC),
2253bf459f3Sfvdl 	    VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE);
2263bf459f3Sfvdl 
2273bf459f3Sfvdl 	/* set up command for bss segment */
228d071d9a8Sthorpej 	baddr = roundup(epp->ep_daddr + execp->a_data, PAGE_SIZE);
2293bf459f3Sfvdl 	bsize = epp->ep_daddr + epp->ep_dsize - baddr;
2303bf459f3Sfvdl 	if (bsize > 0)
2313bf459f3Sfvdl 		NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, bsize, baddr,
2323bf459f3Sfvdl 		    NULLVP, 0, VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE);
2333bf459f3Sfvdl 
23495e1ffb1Schristos 	return (*epp->ep_esch->es_setup_stack)(l, epp);
2353bf459f3Sfvdl }
2363bf459f3Sfvdl 
2373bf459f3Sfvdl /*
2383bf459f3Sfvdl  * exec_aout_prep_omagic(): Prepare Linux OMAGIC package.
2393bf459f3Sfvdl  * Business as usual.
2403bf459f3Sfvdl  */
2413bf459f3Sfvdl 
242baae0324Sjdolecek static int
exec_linux_aout_prep_omagic(struct lwp * l,struct exec_package * epp)24328bae79bSdsl exec_linux_aout_prep_omagic(struct lwp *l, struct exec_package *epp)
2443bf459f3Sfvdl {
2453bf459f3Sfvdl 	struct exec *execp = epp->ep_hdr;
2463bf459f3Sfvdl 	long dsize, bsize, baddr;
2473bf459f3Sfvdl 
2483bf459f3Sfvdl 	epp->ep_taddr = LINUX_N_TXTADDR(*execp, OMAGIC);
2493bf459f3Sfvdl 	epp->ep_tsize = execp->a_text;
2503bf459f3Sfvdl 	epp->ep_daddr = LINUX_N_DATADDR(*execp, OMAGIC);
2513bf459f3Sfvdl 	epp->ep_dsize = execp->a_data + execp->a_bss;
2523bf459f3Sfvdl 	epp->ep_entry = execp->a_entry;
2533bf459f3Sfvdl 
2543bf459f3Sfvdl 	/* set up command for text and data segments */
2553bf459f3Sfvdl 	NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_readvn,
2563bf459f3Sfvdl 	    execp->a_text + execp->a_data, epp->ep_taddr, epp->ep_vp,
2573bf459f3Sfvdl 	    LINUX_N_TXTOFF(*execp, OMAGIC), VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE);
2583bf459f3Sfvdl 
2593bf459f3Sfvdl 	/* set up command for bss segment */
260d071d9a8Sthorpej 	baddr = roundup(epp->ep_daddr + execp->a_data, PAGE_SIZE);
2613bf459f3Sfvdl 	bsize = epp->ep_daddr + epp->ep_dsize - baddr;
2623bf459f3Sfvdl 	if (bsize > 0)
2633bf459f3Sfvdl 		NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, bsize, baddr,
2643bf459f3Sfvdl 		    NULLVP, 0, VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE);
2653bf459f3Sfvdl 
2663bf459f3Sfvdl 	/*
2673bf459f3Sfvdl 	 * Make sure (# of pages) mapped above equals (vm_tsize + vm_dsize);
2683bf459f3Sfvdl 	 * obreak(2) relies on this fact. Both `vm_tsize' and `vm_dsize' are
2693bf459f3Sfvdl 	 * computed (in execve(2)) by rounding *up* `ep_tsize' and `ep_dsize'
2703bf459f3Sfvdl 	 * respectively to page boundaries.
2713bf459f3Sfvdl 	 * Compensate `ep_dsize' for the amount of data covered by the last
2723bf459f3Sfvdl 	 * text page.
2733bf459f3Sfvdl 	 */
274d071d9a8Sthorpej 	dsize = epp->ep_dsize + execp->a_text - roundup(execp->a_text,
275d071d9a8Sthorpej 							PAGE_SIZE);
2763bf459f3Sfvdl 	epp->ep_dsize = (dsize > 0) ? dsize : 0;
27795e1ffb1Schristos 	return (*epp->ep_esch->es_setup_stack)(l, epp);
2783bf459f3Sfvdl }
2793bf459f3Sfvdl 
280baae0324Sjdolecek static int
exec_linux_aout_prep_qmagic(struct lwp * l,struct exec_package * epp)28128bae79bSdsl exec_linux_aout_prep_qmagic(struct lwp *l, struct exec_package *epp)
2823bf459f3Sfvdl {
2833bf459f3Sfvdl 	struct exec *execp = epp->ep_hdr;
284993948e9Schs 	int error;
2853bf459f3Sfvdl 
2863bf459f3Sfvdl 	epp->ep_taddr = LINUX_N_TXTADDR(*execp, QMAGIC);
2873bf459f3Sfvdl 	epp->ep_tsize = execp->a_text;
2883bf459f3Sfvdl 	epp->ep_daddr = LINUX_N_DATADDR(*execp, QMAGIC);
2893bf459f3Sfvdl 	epp->ep_dsize = execp->a_data + execp->a_bss;
2903bf459f3Sfvdl 	epp->ep_entry = execp->a_entry;
2913bf459f3Sfvdl 
292993948e9Schs 	error = vn_marktext(epp->ep_vp);
293993948e9Schs 	if (error)
294993948e9Schs 		return (error);
2953bf459f3Sfvdl 
2963bf459f3Sfvdl 	/* set up command for text segment */
2973bf459f3Sfvdl 	NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_pagedvn, execp->a_text,
2983bf459f3Sfvdl 	    epp->ep_taddr, epp->ep_vp, LINUX_N_TXTOFF(*execp, QMAGIC),
2993bf459f3Sfvdl 	    VM_PROT_READ|VM_PROT_EXECUTE);
3003bf459f3Sfvdl 
3013bf459f3Sfvdl 	/* set up command for data segment */
3023bf459f3Sfvdl 	NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_pagedvn, execp->a_data,
3033bf459f3Sfvdl 	    epp->ep_daddr, epp->ep_vp, LINUX_N_DATOFF(*execp, QMAGIC),
3043bf459f3Sfvdl 	    VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE);
3053bf459f3Sfvdl 
3063bf459f3Sfvdl 	/* set up command for bss segment */
3070b71a2d5Schristos 	if (execp->a_bss)
3083bf459f3Sfvdl 		NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, execp->a_bss,
3093bf459f3Sfvdl 		    epp->ep_daddr + execp->a_data, NULLVP, 0,
3103bf459f3Sfvdl 		    VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE);
3113bf459f3Sfvdl 
31295e1ffb1Schristos 	return (*epp->ep_esch->es_setup_stack)(l, epp);
3133bf459f3Sfvdl }
314