xref: /netbsd-src/sys/compat/linux/common/linux_exec_elf32.c (revision 07bae7edddbb1ce4c926b2e8db425804589074c9)
1 /*	$NetBSD: linux_exec_elf32.c,v 1.4 1995/04/22 19:48:34 christos Exp $	*/
2 
3 /*
4  * Copyright (c) 1995 Frank van der Linden
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *      This product includes software developed for the NetBSD Project
18  *      by Frank van der Linden
19  * 4. The name of the author may not be used to endorse or promote products
20  *    derived from this software without specific prior written permission
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  *
33  * based on kern/exec_aout.c and compat/sunos/sunos_exec.c
34  */
35 
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/filedesc.h>
39 #include <sys/kernel.h>
40 #include <sys/proc.h>
41 #include <sys/mount.h>
42 #include <sys/malloc.h>
43 #include <sys/namei.h>
44 #include <sys/vnode.h>
45 #include <sys/file.h>
46 #include <sys/resourcevar.h>
47 #include <sys/wait.h>
48 
49 #include <sys/mman.h>
50 #include <vm/vm.h>
51 #include <vm/vm_param.h>
52 #include <vm/vm_map.h>
53 #include <vm/vm_kern.h>
54 #include <vm/vm_pager.h>
55 
56 #include <machine/cpu.h>
57 #include <machine/reg.h>
58 #include <machine/exec.h>
59 #include <machine/linux_machdep.h>
60 
61 #include <compat/linux/linux_types.h>
62 #include <compat/linux/linux_syscall.h>
63 #include <compat/linux/linux_syscallargs.h>
64 #include <compat/linux/linux_util.h>
65 #include <compat/linux/linux_exec.h>
66 
67 static void *linux_copyargs __P((struct exec_package *, struct ps_strings *,
68 				void *, void *));
69 
70 #define	LINUX_AUX_ARGSIZ	2
71 
72 extern int linux_error[];
73 extern struct sysent linux_sysent[];
74 extern char *linux_syscallnames[];
75 
76 struct emul emul_linux = {
77 	"linux",
78 	linux_error,
79 	linux_sendsig,
80 	LINUX_SYS_syscall,
81 	LINUX_SYS_MAXSYSCALL,
82 	linux_sysent,
83 	linux_syscallnames,
84 	LINUX_AUX_ARGSIZ,
85 	linux_copyargs,
86 	setregs,
87 	linux_sigcode,
88 	linux_esigcode,
89 };
90 
91 
92 static void *
93 linux_copyargs(pack, arginfo, stack, argp)
94 	struct exec_package *pack;
95 	struct ps_strings *arginfo;
96 	void *stack;
97 	void *argp;
98 {
99 	char **cpp = stack;
100 	char **stk = stack;
101 	char *dp, *sp;
102 	size_t len;
103 	void *nullp = NULL;
104 	int argc = arginfo->ps_nargvstr;
105 	int envc = arginfo->ps_nenvstr;
106 
107 	if (copyout(&argc, cpp++, sizeof(argc)))
108 		return NULL;
109 
110 	/* leave room for envp and argv */
111 	cpp += 2;
112 	if (copyout(&cpp, &stk[1], sizeof (cpp)))
113 		return NULL;
114 
115 	dp = (char *) (cpp + argc + envc + 2);
116 	sp = argp;
117 
118 	/* XXX don't copy them out, remap them! */
119 	arginfo->ps_argvstr = dp; /* remember location of argv for later */
120 
121 	for (; --argc >= 0; sp += len, dp += len)
122 		if (copyout(&dp, cpp++, sizeof(dp)) ||
123 		    copyoutstr(sp, dp, ARG_MAX, &len))
124 			return NULL;
125 
126 	if (copyout(&nullp, cpp++, sizeof(nullp)))
127 		return NULL;
128 
129 	if (copyout(&cpp, &stk[2], sizeof (cpp)))
130 		return NULL;
131 
132 	arginfo->ps_envstr = dp; /* remember location of envp for later */
133 
134 	for (; --envc >= 0; sp += len, dp += len)
135 		if (copyout(&dp, cpp++, sizeof(dp)) ||
136 		    copyoutstr(sp, dp, ARG_MAX, &len))
137 			return NULL;
138 
139 	if (copyout(&nullp, cpp++, sizeof(nullp)))
140 		return NULL;
141 
142 	return cpp;
143 }
144 
145 
146 int
147 exec_linux_aout_makecmds(p, epp)
148 	struct proc *p;
149 	struct exec_package *epp;
150 {
151 	struct exec *linux_ep = epp->ep_hdr;
152 	int machtype, magic;
153 	int error = ENOEXEC;
154 
155 	magic = LINUX_N_MAGIC(linux_ep);
156 	machtype = LINUX_N_MACHTYPE(linux_ep);
157 
158 
159 	if (machtype != LINUX_MID_MACHINE)
160 		return (ENOEXEC);
161 
162 	switch (magic) {
163 	case QMAGIC:
164 		error = exec_linux_aout_prep_qmagic(p, epp);
165 		break;
166 	case ZMAGIC:
167 		error = exec_linux_aout_prep_zmagic(p, epp);
168 		break;
169 	case NMAGIC:
170 		error = exec_linux_aout_prep_nmagic(p, epp);
171 		break;
172 	case OMAGIC:
173 		error = exec_linux_aout_prep_omagic(p, epp);
174 		break;
175 	}
176 	if (error == 0)
177 		epp->ep_emul = &emul_linux;
178 	return error;
179 }
180 
181 /*
182  * Since text starts at 0x400 in Linux ZMAGIC executables, and 0x400
183  * is very likely not page aligned on most architectures, it is treated
184  * as an NMAGIC here. XXX
185  */
186 
187 int
188 exec_linux_aout_prep_zmagic(p, epp)
189 	struct proc *p;
190 	struct exec_package *epp;
191 {
192 	struct exec *execp = epp->ep_hdr;
193 
194 	epp->ep_taddr = LINUX_N_TXTADDR(*execp, ZMAGIC);
195 	epp->ep_tsize = execp->a_text;
196 	epp->ep_daddr = LINUX_N_DATADDR(*execp, ZMAGIC);
197 	epp->ep_dsize = execp->a_data + execp->a_bss;
198 	epp->ep_entry = execp->a_entry;
199 
200 	/* set up command for text segment */
201 	NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_readvn, execp->a_text,
202 	    epp->ep_taddr, epp->ep_vp, LINUX_N_TXTOFF(*execp, ZMAGIC),
203 	    VM_PROT_READ|VM_PROT_EXECUTE);
204 
205 	/* set up command for data segment */
206 	NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_readvn, execp->a_data,
207 	    epp->ep_daddr, epp->ep_vp, LINUX_N_DATOFF(*execp, ZMAGIC),
208 	    VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE);
209 
210 	/* set up command for bss segment */
211 	NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, execp->a_bss,
212 	    epp->ep_daddr + execp->a_data, NULLVP, 0,
213 	    VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE);
214 
215 	return exec_aout_setup_stack(p, epp);
216 }
217 
218 /*
219  * exec_aout_prep_nmagic(): Prepare Linux NMAGIC package.
220  * Not different from the normal stuff.
221  */
222 
223 int
224 exec_linux_aout_prep_nmagic(p, epp)
225 	struct proc *p;
226 	struct exec_package *epp;
227 {
228 	struct exec *execp = epp->ep_hdr;
229 	long bsize, baddr;
230 
231 	epp->ep_taddr = LINUX_N_TXTADDR(*execp, NMAGIC);
232 	epp->ep_tsize = execp->a_text;
233 	epp->ep_daddr = LINUX_N_DATADDR(*execp, NMAGIC);
234 	epp->ep_dsize = execp->a_data + execp->a_bss;
235 	epp->ep_entry = execp->a_entry;
236 
237 	/* set up command for text segment */
238 	NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_readvn, execp->a_text,
239 	    epp->ep_taddr, epp->ep_vp, LINUX_N_TXTOFF(*execp, NMAGIC),
240 	    VM_PROT_READ|VM_PROT_EXECUTE);
241 
242 	/* set up command for data segment */
243 	NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_readvn, execp->a_data,
244 	    epp->ep_daddr, epp->ep_vp, LINUX_N_DATOFF(*execp, NMAGIC),
245 	    VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE);
246 
247 	/* set up command for bss segment */
248 	baddr = roundup(epp->ep_daddr + execp->a_data, NBPG);
249 	bsize = epp->ep_daddr + epp->ep_dsize - baddr;
250 	if (bsize > 0)
251 		NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, bsize, baddr,
252 		    NULLVP, 0, VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE);
253 
254 	return exec_aout_setup_stack(p, epp);
255 }
256 
257 /*
258  * exec_aout_prep_omagic(): Prepare Linux OMAGIC package.
259  * Business as usual.
260  */
261 
262 int
263 exec_linux_aout_prep_omagic(p, epp)
264 	struct proc *p;
265 	struct exec_package *epp;
266 {
267 	struct exec *execp = epp->ep_hdr;
268 	long dsize, bsize, baddr;
269 
270 	epp->ep_taddr = LINUX_N_TXTADDR(*execp, OMAGIC);
271 	epp->ep_tsize = execp->a_text;
272 	epp->ep_daddr = LINUX_N_DATADDR(*execp, OMAGIC);
273 	epp->ep_dsize = execp->a_data + execp->a_bss;
274 	epp->ep_entry = execp->a_entry;
275 
276 	/* set up command for text and data segments */
277 	NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_readvn,
278 	    execp->a_text + execp->a_data, epp->ep_taddr, epp->ep_vp,
279 	    LINUX_N_TXTOFF(*execp, OMAGIC), VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE);
280 
281 	/* set up command for bss segment */
282 	baddr = roundup(epp->ep_daddr + execp->a_data, NBPG);
283 	bsize = epp->ep_daddr + epp->ep_dsize - baddr;
284 	if (bsize > 0)
285 		NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, bsize, baddr,
286 		    NULLVP, 0, VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE);
287 
288 	/*
289 	 * Make sure (# of pages) mapped above equals (vm_tsize + vm_dsize);
290 	 * obreak(2) relies on this fact. Both `vm_tsize' and `vm_dsize' are
291 	 * computed (in execve(2)) by rounding *up* `ep_tsize' and `ep_dsize'
292 	 * respectively to page boundaries.
293 	 * Compensate `ep_dsize' for the amount of data covered by the last
294 	 * text page.
295 	 */
296 	dsize = epp->ep_dsize + execp->a_text - roundup(execp->a_text, NBPG);
297 	epp->ep_dsize = (dsize > 0) ? dsize : 0;
298 	return exec_aout_setup_stack(p, epp);
299 }
300 
301 int
302 exec_linux_aout_prep_qmagic(p, epp)
303 	struct proc *p;
304 	struct exec_package *epp;
305 {
306 	struct exec *execp = epp->ep_hdr;
307 
308 	epp->ep_taddr = LINUX_N_TXTADDR(*execp, QMAGIC);
309 	epp->ep_tsize = execp->a_text;
310 	epp->ep_daddr = LINUX_N_DATADDR(*execp, QMAGIC);
311 	epp->ep_dsize = execp->a_data + execp->a_bss;
312 	epp->ep_entry = execp->a_entry;
313 
314 	/*
315 	 * check if vnode is in open for writing, because we want to
316 	 * demand-page out of it.  if it is, don't do it, for various
317 	 * reasons
318 	 */
319 	if ((execp->a_text != 0 || execp->a_data != 0) &&
320 	    epp->ep_vp->v_writecount != 0) {
321 #ifdef DIAGNOSTIC
322 		if (epp->ep_vp->v_flag & VTEXT)
323 			panic("exec: a VTEXT vnode has writecount != 0\n");
324 #endif
325 		return ETXTBSY;
326 	}
327 	epp->ep_vp->v_flag |= VTEXT;
328 
329 	/* set up command for text segment */
330 	NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_pagedvn, execp->a_text,
331 	    epp->ep_taddr, epp->ep_vp, LINUX_N_TXTOFF(*execp, QMAGIC),
332 	    VM_PROT_READ|VM_PROT_EXECUTE);
333 
334 	/* set up command for data segment */
335 	NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_pagedvn, execp->a_data,
336 	    epp->ep_daddr, epp->ep_vp, LINUX_N_DATOFF(*execp, QMAGIC),
337 	    VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE);
338 
339 	/* set up command for bss segment */
340 	NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, execp->a_bss,
341 	    epp->ep_daddr + execp->a_data, NULLVP, 0,
342 	    VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE);
343 
344 	return exec_aout_setup_stack(p, epp);
345 }
346 
347 /*
348  * The Linux system call to load shared libraries. The current shared
349  * libraries are just (QMAGIC) a.out files that are mapped onto a fixed
350  * address * in the process' address space. The address is given in
351  * a_entry. Read in the header, set up some VM commands and run them.
352  *
353  * Yes, both text and data are mapped at once, so we're left with
354  * writeable text for the shared libs. The Linux crt0 seemed to break
355  * sometimes when data was mapped seperately. It munmapped a uselib()
356  * of ld.so by hand, which failed with shared text and data for ld.so
357  * Yuck.
358  *
359  * Because of the problem with ZMAGIC executables (text starts
360  * at 0x400 in the file, but needs t be mapped at 0), ZMAGIC
361  * shared libs are not handled very efficiently :-(
362  */
363 
364 int
365 linux_uselib(p, uap, retval)
366 	struct proc *p;
367 	struct linux_uselib_args /* {
368 		syscallarg(char *) path;
369 	} */ *uap;
370 	register_t *retval;
371 {
372 	caddr_t sg;
373 	long bsize, dsize, tsize, taddr, baddr, daddr;
374 	struct nameidata ni;
375 	struct vnode *vp;
376 	struct exec hdr;
377 	struct exec_vmcmd_set vcset;
378 	int rem, i, magic, error;
379 
380 	sg = stackgap_init();
381 	CHECK_ALT_EXIST(p, &sg, SCARG(uap, path));
382 
383 	NDINIT(&ni, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
384 
385 	if ((error = namei(&ni)))
386 		return error;
387 
388 	vp = ni.ni_vp;
389 
390 	if ((error = vn_rdwr(UIO_READ, vp, (caddr_t) &hdr, LINUX_AOUT_HDR_SIZE,
391 			     0, UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred,
392 			     &rem, p))) {
393 		vrele(vp);
394 		return error;
395 	}
396 
397 	if (rem != 0) {
398 		vrele(vp);
399 		return ENOEXEC;
400 	}
401 
402 	magic = LINUX_N_MAGIC(&hdr);
403 	taddr = hdr.a_entry & (~(NBPG - 1));
404 	tsize = hdr.a_text;
405 	daddr = taddr + tsize;
406 	dsize = hdr.a_data + hdr.a_bss;
407 
408 	if ((hdr.a_text != 0 || hdr.a_data != 0) && vp->v_writecount != 0) {
409 		vrele(vp);
410                 return ETXTBSY;
411         }
412 	vp->v_flag |= VTEXT;
413 
414 	vcset.evs_cnt = 0;
415 	vcset.evs_used = 0;
416 
417 	NEW_VMCMD(&vcset,
418 		  magic == ZMAGIC ? vmcmd_map_readvn : vmcmd_map_pagedvn,
419 		  hdr.a_text + hdr.a_data, taddr,
420 		  vp, LINUX_N_TXTOFF(hdr, magic),
421 		  VM_PROT_READ|VM_PROT_EXECUTE|VM_PROT_WRITE);
422 
423 	baddr = roundup(daddr + hdr.a_data, NBPG);
424 	bsize = daddr + dsize - baddr;
425         if (bsize > 0) {
426                 NEW_VMCMD(&vcset, vmcmd_map_zero, bsize, baddr,
427                     NULLVP, 0, VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE);
428 	}
429 
430 	for (i = 0; i < vcset.evs_used && !error; i++) {
431 		struct exec_vmcmd *vcp;
432 
433 		vcp = &vcset.evs_cmds[i];
434 		error = (*vcp->ev_proc)(p, vcp);
435 	}
436 
437 	kill_vmcmds(&vcset);
438 
439 	vrele(vp);
440 
441 	return error;
442 }
443 
444 /*
445  * Execve(2). Just check the alternate emulation path, and pass it on
446  * to the NetBSD execve().
447  */
448 int
449 linux_execve(p, uap, retval)
450 	struct proc *p;
451 	struct linux_execve_args /* {
452 		syscallarg(char *) path;
453 		syscallarg(char **) argv;
454 		syscallarg(char **) envp;
455 	} */ *uap;
456 	register_t *retval;
457 {
458 	caddr_t sg;
459 
460 	sg = stackgap_init();
461 	CHECK_ALT_EXIST(p, &sg, SCARG(uap, path));
462 
463 	return execve(p, uap, retval);
464 }
465