1 /*	$NetBSD: linux_exec_aout.c,v 1.59 2006/10/12 01:30:48 christos Exp $	*/
2 
3 /*-
4  * Copyright (c) 1995, 1998 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Christos Zoulas, Frank van der Linden and Eric Haszlakiewicz.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *	This product includes software developed by the NetBSD
21  *	Foundation, Inc. and its contributors.
22  * 4. Neither the name of The NetBSD Foundation nor the names of its
23  *    contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  */
38 
39 /*
40  * based on exec_aout.c, sunos_exec.c and svr4_exec.c
41  */
42 
43 #include <sys/cdefs.h>
44 __KERNEL_RCSID(0, "$NetBSD: linux_exec_aout.c,v 1.59 2006/10/12 01:30:48 christos Exp $");
45 
46 #include <sys/param.h>
47 #include <sys/systm.h>
48 #include <sys/kernel.h>
49 #include <sys/proc.h>
50 #include <sys/malloc.h>
51 #include <sys/namei.h>
52 #include <sys/vnode.h>
53 #include <sys/mount.h>
54 #include <sys/exec.h>
55 #include <sys/exec_elf.h>
56 
57 #include <sys/mman.h>
58 #include <sys/sa.h>
59 #include <sys/syscallargs.h>
60 
61 #include <machine/cpu.h>
62 #include <machine/reg.h>
63 
64 #include <compat/linux/common/linux_types.h>
65 #include <compat/linux/common/linux_signal.h>
66 #include <compat/linux/common/linux_util.h>
67 #include <compat/linux/common/linux_exec.h>
68 #include <compat/linux/common/linux_machdep.h>
69 
70 #include <compat/linux/linux_syscallargs.h>
71 #include <compat/linux/linux_syscall.h>
72 
73 int linux_aout_copyargs __P((struct lwp *, struct exec_package *,
74     struct ps_strings *, char **, void *));
75 
76 static int exec_linux_aout_prep_zmagic __P((struct lwp *,
77     struct exec_package *));
78 static int exec_linux_aout_prep_nmagic __P((struct lwp *,
79     struct exec_package *));
80 static int exec_linux_aout_prep_omagic __P((struct lwp *,
81     struct exec_package *));
82 static int exec_linux_aout_prep_qmagic __P((struct lwp *,
83     struct exec_package *));
84 
85 int
86 linux_aout_copyargs(struct lwp *l __unused, struct exec_package *pack __unused,
87     struct ps_strings *arginfo, char **stackp, void *argp)
88 {
89 	char **cpp = (char **)*stackp;
90 	char **stk = (char **)*stackp;
91 	char *dp, *sp;
92 	size_t len;
93 	void *nullp = NULL;
94 	int argc = arginfo->ps_nargvstr;
95 	int envc = arginfo->ps_nenvstr;
96 	int error;
97 
98 	if ((error = copyout(&argc, cpp++, sizeof(argc))) != 0)
99 		return error;
100 
101 	/* leave room for envp and argv */
102 	cpp += 2;
103 	if ((error = copyout(&cpp, &stk[1], sizeof (cpp))) != 0)
104 		return error;
105 
106 	dp = (char *) (cpp + argc + envc + 2);
107 	sp = argp;
108 
109 	/* XXX don't copy them out, remap them! */
110 	arginfo->ps_argvstr = cpp; /* remember location of argv for later */
111 
112 	for (; --argc >= 0; sp += len, dp += len)
113 		if ((error = copyout(&dp, cpp++, sizeof(dp))) != 0 ||
114 		    (error = copyoutstr(sp, dp, ARG_MAX, &len)) != 0)
115 			return error;
116 
117 	if ((error = copyout(&nullp, cpp++, sizeof(nullp))) != 0)
118 		return error;
119 
120 	if ((error = copyout(&cpp, &stk[2], sizeof (cpp))) != 0)
121 		return error;
122 
123 	arginfo->ps_envstr = cpp; /* remember location of envp for later */
124 
125 	for (; --envc >= 0; sp += len, dp += len)
126 		if ((error = copyout(&dp, cpp++, sizeof(dp))) != 0 ||
127 		    (error = copyoutstr(sp, dp, ARG_MAX, &len)) != 0)
128 			return error;
129 
130 	if ((error = copyout(&nullp, cpp++, sizeof(nullp))) != 0)
131 		return error;
132 
133 	*stackp = (char *)cpp;
134 	return 0;
135 }
136 
137 int
138 exec_linux_aout_makecmds(l, epp)
139 	struct lwp *l;
140 	struct exec_package *epp;
141 {
142 	struct exec *linux_ep = epp->ep_hdr;
143 	int machtype, magic;
144 	int error = ENOEXEC;
145 
146 	magic = LINUX_N_MAGIC(linux_ep);
147 	machtype = LINUX_N_MACHTYPE(linux_ep);
148 
149 
150 	if (machtype != LINUX_MID_MACHINE)
151 		return (ENOEXEC);
152 
153 	switch (magic) {
154 	case QMAGIC:
155 		error = exec_linux_aout_prep_qmagic(l, epp);
156 		break;
157 	case ZMAGIC:
158 		error = exec_linux_aout_prep_zmagic(l, epp);
159 		break;
160 	case NMAGIC:
161 		error = exec_linux_aout_prep_nmagic(l, epp);
162 		break;
163 	case OMAGIC:
164 		error = exec_linux_aout_prep_omagic(l, epp);
165 		break;
166 	}
167 	return error;
168 }
169 
170 /*
171  * Since text starts at 0x400 in Linux ZMAGIC executables, and 0x400
172  * is very likely not page aligned on most architectures, it is treated
173  * as an NMAGIC here. XXX
174  */
175 
176 static int
177 exec_linux_aout_prep_zmagic(l, epp)
178 	struct lwp *l;
179 	struct exec_package *epp;
180 {
181 	struct exec *execp = epp->ep_hdr;
182 
183 	epp->ep_taddr = LINUX_N_TXTADDR(*execp, ZMAGIC);
184 	epp->ep_tsize = execp->a_text;
185 	epp->ep_daddr = LINUX_N_DATADDR(*execp, ZMAGIC);
186 	epp->ep_dsize = execp->a_data + execp->a_bss;
187 	epp->ep_entry = execp->a_entry;
188 
189 	/* set up command for text segment */
190 	NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_readvn, execp->a_text,
191 	    epp->ep_taddr, epp->ep_vp, LINUX_N_TXTOFF(*execp, ZMAGIC),
192 	    VM_PROT_READ|VM_PROT_EXECUTE);
193 
194 	/* set up command for data segment */
195 	NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_readvn, execp->a_data,
196 	    epp->ep_daddr, epp->ep_vp, LINUX_N_DATOFF(*execp, ZMAGIC),
197 	    VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE);
198 
199 	/* set up command for bss segment */
200 	if (execp->a_bss)
201 		NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, execp->a_bss,
202 		    epp->ep_daddr + execp->a_data, NULLVP, 0,
203 		    VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE);
204 
205 	return (*epp->ep_esch->es_setup_stack)(l, epp);
206 }
207 
208 /*
209  * exec_aout_prep_nmagic(): Prepare Linux NMAGIC package.
210  * Not different from the normal stuff.
211  */
212 
213 static int
214 exec_linux_aout_prep_nmagic(l, epp)
215 	struct lwp *l;
216 	struct exec_package *epp;
217 {
218 	struct exec *execp = epp->ep_hdr;
219 	long bsize, baddr;
220 
221 	epp->ep_taddr = LINUX_N_TXTADDR(*execp, NMAGIC);
222 	epp->ep_tsize = execp->a_text;
223 	epp->ep_daddr = LINUX_N_DATADDR(*execp, NMAGIC);
224 	epp->ep_dsize = execp->a_data + execp->a_bss;
225 	epp->ep_entry = execp->a_entry;
226 
227 	/* set up command for text segment */
228 	NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_readvn, execp->a_text,
229 	    epp->ep_taddr, epp->ep_vp, LINUX_N_TXTOFF(*execp, NMAGIC),
230 	    VM_PROT_READ|VM_PROT_EXECUTE);
231 
232 	/* set up command for data segment */
233 	NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_readvn, execp->a_data,
234 	    epp->ep_daddr, epp->ep_vp, LINUX_N_DATOFF(*execp, NMAGIC),
235 	    VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE);
236 
237 	/* set up command for bss segment */
238 	baddr = roundup(epp->ep_daddr + execp->a_data, PAGE_SIZE);
239 	bsize = epp->ep_daddr + epp->ep_dsize - baddr;
240 	if (bsize > 0)
241 		NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, bsize, baddr,
242 		    NULLVP, 0, VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE);
243 
244 	return (*epp->ep_esch->es_setup_stack)(l, epp);
245 }
246 
247 /*
248  * exec_aout_prep_omagic(): Prepare Linux OMAGIC package.
249  * Business as usual.
250  */
251 
252 static int
253 exec_linux_aout_prep_omagic(l, epp)
254 	struct lwp *l;
255 	struct exec_package *epp;
256 {
257 	struct exec *execp = epp->ep_hdr;
258 	long dsize, bsize, baddr;
259 
260 	epp->ep_taddr = LINUX_N_TXTADDR(*execp, OMAGIC);
261 	epp->ep_tsize = execp->a_text;
262 	epp->ep_daddr = LINUX_N_DATADDR(*execp, OMAGIC);
263 	epp->ep_dsize = execp->a_data + execp->a_bss;
264 	epp->ep_entry = execp->a_entry;
265 
266 	/* set up command for text and data segments */
267 	NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_readvn,
268 	    execp->a_text + execp->a_data, epp->ep_taddr, epp->ep_vp,
269 	    LINUX_N_TXTOFF(*execp, OMAGIC), VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE);
270 
271 	/* set up command for bss segment */
272 	baddr = roundup(epp->ep_daddr + execp->a_data, PAGE_SIZE);
273 	bsize = epp->ep_daddr + epp->ep_dsize - baddr;
274 	if (bsize > 0)
275 		NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, bsize, baddr,
276 		    NULLVP, 0, VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE);
277 
278 	/*
279 	 * Make sure (# of pages) mapped above equals (vm_tsize + vm_dsize);
280 	 * obreak(2) relies on this fact. Both `vm_tsize' and `vm_dsize' are
281 	 * computed (in execve(2)) by rounding *up* `ep_tsize' and `ep_dsize'
282 	 * respectively to page boundaries.
283 	 * Compensate `ep_dsize' for the amount of data covered by the last
284 	 * text page.
285 	 */
286 	dsize = epp->ep_dsize + execp->a_text - roundup(execp->a_text,
287 							PAGE_SIZE);
288 	epp->ep_dsize = (dsize > 0) ? dsize : 0;
289 	return (*epp->ep_esch->es_setup_stack)(l, epp);
290 }
291 
292 static int
293 exec_linux_aout_prep_qmagic(l, epp)
294 	struct lwp *l;
295 	struct exec_package *epp;
296 {
297 	struct exec *execp = epp->ep_hdr;
298 	int error;
299 
300 	epp->ep_taddr = LINUX_N_TXTADDR(*execp, QMAGIC);
301 	epp->ep_tsize = execp->a_text;
302 	epp->ep_daddr = LINUX_N_DATADDR(*execp, QMAGIC);
303 	epp->ep_dsize = execp->a_data + execp->a_bss;
304 	epp->ep_entry = execp->a_entry;
305 
306 	error = vn_marktext(epp->ep_vp);
307 	if (error)
308 		return (error);
309 
310 	/* set up command for text segment */
311 	NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_pagedvn, execp->a_text,
312 	    epp->ep_taddr, epp->ep_vp, LINUX_N_TXTOFF(*execp, QMAGIC),
313 	    VM_PROT_READ|VM_PROT_EXECUTE);
314 
315 	/* set up command for data segment */
316 	NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_pagedvn, execp->a_data,
317 	    epp->ep_daddr, epp->ep_vp, LINUX_N_DATOFF(*execp, QMAGIC),
318 	    VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE);
319 
320 	/* set up command for bss segment */
321 	if (execp->a_bss)
322 		NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, execp->a_bss,
323 		    epp->ep_daddr + execp->a_data, NULLVP, 0,
324 		    VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE);
325 
326 	return (*epp->ep_esch->es_setup_stack)(l, epp);
327 }
328