exec_elf32.c revision 1.1
1/*	$NetBSD: exec_elf32.c,v 1.1 1995/06/22 21:29:53 fvdl Exp $	*/
2
3/*
4 * Copyright (c) 1994 Christos Zoulas
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. The name of the author may not be used to endorse or promote products
16 *    derived from this software without specific prior written permission
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 *
29 */
30
31#include <sys/param.h>
32#include <sys/systm.h>
33#include <sys/kernel.h>
34#include <sys/proc.h>
35#include <sys/malloc.h>
36#include <sys/namei.h>
37#include <sys/vnode.h>
38#include <sys/exec.h>
39#include <sys/exec_elf.h>
40
41#include <sys/mman.h>
42#include <vm/vm.h>
43#include <vm/vm_param.h>
44#include <vm/vm_map.h>
45
46#include <machine/cpu.h>
47#include <machine/reg.h>
48#include <machine/exec.h>
49
50#ifdef COMPAT_LINUX
51#include <compat/linux/linux_exec.h>
52#endif
53
54#ifdef COMPAT_SVR4
55#include <compat/svr4/svr4_exec.h>
56#endif
57
58int (*elf_probe_funcs[])() = {
59#ifdef COMPAT_SVR4
60	svr4_elf_probe,
61#endif
62#ifdef COMPAT_LINUX
63	linux_elf_probe
64#endif
65};
66
67static int elf_set_segment __P((struct exec_package *, u_long, u_long,
68	int));
69static int elf_read_from __P((struct proc *, struct vnode *, u_long,
70	caddr_t, int));
71static void elf_load_psection __P((struct exec_vmcmd_set *,
72	struct vnode *, Elf32_Phdr *, u_long *, u_long *, int *));
73
74#define ELF_ALIGN(a, b) ((a) & ~((b) - 1))
75#define ELF_AUX_ARGSIZ (sizeof(AuxInfo) * 8 / sizeof(char *))
76
77/*
78 * Copy arguments onto the stack in the normal way, but add some
79 * extra information in case of dynamic binding.
80 */
81void *
82elf_copyargs(pack, arginfo, stack, argp)
83	struct exec_package *pack;
84	struct ps_strings *arginfo;
85	void *stack;
86	void *argp;
87{
88	char **cpp = stack;
89	char *dp, *sp;
90	size_t len;
91	void *nullp = NULL;
92	int argc = arginfo->ps_nargvstr;
93	int envc = arginfo->ps_nenvstr;
94	AuxInfo *a;
95	struct elf_args *ap;
96
97	if (copyout(&argc, cpp++, sizeof(argc)))
98		return NULL;
99
100	dp = (char *) (cpp + argc + envc + 2 + pack->ep_emul->e_arglen);
101	sp = argp;
102
103	/* XXX don't copy them out, remap them! */
104	arginfo->ps_argvstr = cpp; /* remember location of argv for later */
105
106	for (; --argc >= 0; sp += len, dp += len)
107		if (copyout(&dp, cpp++, sizeof(dp)) ||
108		    copyoutstr(sp, dp, ARG_MAX, &len))
109			return NULL;
110
111	if (copyout(&nullp, cpp++, sizeof(nullp)))
112		return NULL;
113
114	arginfo->ps_envstr = cpp; /* remember location of envp for later */
115
116	for (; --envc >= 0; sp += len, dp += len)
117		if (copyout(&dp, cpp++, sizeof(dp)) ||
118		    copyoutstr(sp, dp, ARG_MAX, &len))
119			return NULL;
120
121	if (copyout(&nullp, cpp++, sizeof(nullp)))
122		return NULL;
123
124	/*
125	 * Push extra arguments on the stack needed by dynamically
126	 * linked binaries
127	 */
128	a = (AuxInfo *) cpp;
129	if ((ap = (struct elf_args *) pack->ep_emul_arg)) {
130
131		a->au_id = AUX_phdr;
132		a->au_v = ap->arg_phaddr;
133		a++;
134
135		a->au_id = AUX_phent;
136		a->au_v = ap->arg_phentsize;
137		a++;
138
139		a->au_id = AUX_phnum;
140		a->au_v = ap->arg_phnum;
141		a++;
142
143		a->au_id = AUX_pagesz;
144		a->au_v = NBPG;
145		a++;
146
147		a->au_id = AUX_base;
148		a->au_v = ap->arg_interp;
149		a++;
150
151		a->au_id = AUX_flags;
152		a->au_v = 0;
153		a++;
154
155		a->au_id = AUX_entry;
156		a->au_v = ap->arg_entry;
157		a++;
158
159		a->au_id = AUX_null;
160		a->au_v = 0;
161		a++;
162
163		free((char *) ap, M_TEMP);
164	}
165	return a;
166}
167
168/*
169 * elf_check_header():
170 *
171 * Check header for validity; return 0 of ok ENOEXEC if error
172 *
173 * XXX machine type needs to be moved to <machine/param.h> so
174 * just one comparison can be done. Unfortunately, there is both
175 * em_486 and em_386, so this would not work on the i386.
176 */
177int
178elf_check_header(eh, type)
179	Elf32_Ehdr *eh;
180	int type;
181{
182#ifdef sparc
183  /* #$%@#$%@#$%! */
184# define memcmp bcmp
185#endif
186	if (memcmp(eh->e_ident, Elf32_e_ident, Elf32_e_siz) != 0)
187		return ENOEXEC;
188
189	switch (eh->e_machine) {
190	/* XXX */
191#ifdef i386
192	case Elf32_em_386:
193	case Elf32_em_486:
194#endif
195#ifdef sparc
196	case Elf32_em_sparc:
197#endif
198		break;
199
200	default:
201		return ENOEXEC;
202	}
203
204	if (eh->e_type != type)
205		return ENOEXEC;
206
207	return 0;
208}
209
210/*
211 * elf_load_psection():
212 *
213 * Load a psection at the appropriate address
214 */
215static void
216elf_load_psection(vcset, vp, ph, addr, size, prot)
217	struct exec_vmcmd_set *vcset;
218	struct vnode *vp;
219	Elf32_Phdr *ph;
220	u_long *addr;
221	u_long *size;
222	int *prot;
223{
224	u_long uaddr, msize, rm, rf;
225	long diff, offset;
226
227	/*
228         * If the user specified an address, then we load there.
229         */
230	if (*addr != ELF32_NO_ADDR) {
231		if (ph->p_align > 1) {
232			*addr = ELF_ALIGN(*addr + ph->p_align, ph->p_align);
233			uaddr = ELF_ALIGN(ph->p_vaddr, ph->p_align);
234		} else
235			uaddr = ph->p_vaddr;
236		diff = ph->p_vaddr - uaddr;
237	} else {
238		*addr = uaddr = ph->p_vaddr;
239		if (ph->p_align > 1)
240			*addr = ELF_ALIGN(uaddr, ph->p_align);
241		diff = uaddr - *addr;
242	}
243
244	*prot |= (ph->p_flags & Elf32_pf_r) ? VM_PROT_READ : 0;
245	*prot |= (ph->p_flags & Elf32_pf_w) ? VM_PROT_WRITE : 0;
246	*prot |= (ph->p_flags & Elf32_pf_x) ? VM_PROT_EXECUTE : 0;
247
248	offset = ph->p_offset - diff;
249	*size = ph->p_filesz + diff;
250	msize = ph->p_memsz + diff;
251
252	NEW_VMCMD(vcset, vmcmd_map_readvn, *size, *addr, vp, offset, *prot);
253
254	/*
255         * Check if we need to extend the size of the segment
256         */
257	rm = round_page(*addr + msize);
258	rf = round_page(*addr + *size);
259
260	if (rm != rf) {
261		NEW_VMCMD(vcset, vmcmd_map_zero, rm - rf, rf, NULLVP, 0, *prot);
262		*size = msize;
263	}
264}
265
266/*
267 * elf_set_segment():
268 *
269 * Decide if the segment is text or data, depending on the protection
270 * and set it appropriately
271 */
272static int
273elf_set_segment(epp, vaddr, size, prot)
274	struct exec_package *epp;
275	u_long vaddr;
276	u_long size;
277	int prot;
278{
279	/*
280         * Kludge: Unfortunately the current implementation of
281         * exec package assumes a single text and data segment.
282         * In Elf we can have more, but here we limit ourselves
283         * to two and hope :-(
284         * We also assume that the text is r-x, and data is rwx or rw-.
285         */
286	switch (prot) {
287	case (VM_PROT_READ | VM_PROT_EXECUTE):
288		if (epp->ep_tsize != ELF32_NO_ADDR)
289			return ENOEXEC;
290		epp->ep_taddr = vaddr;
291		epp->ep_tsize = size;
292		break;
293
294	case (VM_PROT_READ | VM_PROT_WRITE):
295	case (VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE):
296		if (epp->ep_dsize != ELF32_NO_ADDR)
297			return ENOEXEC;
298		epp->ep_daddr = vaddr;
299		epp->ep_dsize = size;
300		break;
301
302	default:
303		return ENOEXEC;
304	}
305	return 0;
306}
307
308/*
309 * elf_read_from():
310 *
311 *	Read from vnode into buffer at offset.
312 */
313static int
314elf_read_from(p, vp, off, buf, size)
315	struct vnode *vp;
316	u_long off;
317	struct proc *p;
318	caddr_t buf;
319	int size;
320{
321	int error;
322	int resid;
323
324	if ((error = vn_rdwr(UIO_READ, vp, buf, size,
325			     off, UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred,
326			     &resid, p)) != 0)
327		return error;
328	/*
329         * See if we got all of it
330         */
331	if (resid != 0)
332		return error;
333	return 0;
334}
335
336/*
337 * elf_load_file():
338 *
339 * Load a file (interpreter/library) pointed to by path
340 * [stolen from coff_load_shlib()]. Made slightly generic
341 * so it might be used externally.
342 */
343int
344elf_load_file(p, path, vcset, entry, ap, last)
345	struct proc *p;
346	char *path;
347	struct exec_vmcmd_set *vcset;
348	u_long *entry;
349	struct elf_args	*ap;
350	u_long *last;
351{
352	int error, i;
353	struct nameidata nd;
354	Elf32_Ehdr eh;
355	Elf32_Phdr *ph = NULL;
356	u_long phsize;
357	char *bp = NULL;
358	u_long addr = *last;
359
360	bp = path;
361	/*
362         * 1. open file
363         * 2. read filehdr
364         * 3. map text, data, and bss out of it using VM_*
365         */
366	NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, path, p);
367	if ((error = namei(&nd)) != 0) {
368		return error;
369	}
370	if ((error = elf_read_from(p, nd.ni_vp, 0, (caddr_t) &eh,
371				    sizeof(eh))) != 0)
372		goto bad;
373
374	if ((error = elf_check_header(&eh, Elf32_et_dyn)) != 0)
375		goto bad;
376
377	phsize = eh.e_phnum * sizeof(Elf32_Phdr);
378	ph = (Elf32_Phdr *) malloc(phsize, M_TEMP, M_WAITOK);
379
380	if ((error = elf_read_from(p, nd.ni_vp, eh.e_phoff,
381				    (caddr_t) ph, phsize)) != 0)
382		goto bad;
383
384	/*
385         * Load all the necessary sections
386         */
387	for (i = 0; i < eh.e_phnum; i++) {
388		u_long size = 0;
389		int prot = 0;
390
391		switch (ph[i].p_type) {
392		case Elf32_pt_load:
393			elf_load_psection(vcset, nd.ni_vp, &ph[i], &addr,
394						&size, &prot);
395			/* Assume that the text segment is r-x only */
396			if ((prot & PROT_WRITE) == 0) {
397				*entry = addr + eh.e_entry;
398				ap->arg_interp = addr;
399			}
400			addr += size;
401			break;
402
403		case Elf32_pt_dynamic:
404		case Elf32_pt_phdr:
405		case Elf32_pt_note:
406			break;
407
408		default:
409			break;
410		}
411	}
412
413bad:
414	if (ph != NULL)
415		free((char *) ph, M_TEMP);
416
417	*last = addr;
418	vrele(nd.ni_vp);
419	return error;
420}
421
422/*
423 * exec_elf_makecmds(): Prepare an Elf binary's exec package
424 *
425 * First, set of the various offsets/lengths in the exec package.
426 *
427 * Then, mark the text image busy (so it can be demand paged) or error
428 * out if this is not possible.  Finally, set up vmcmds for the
429 * text, data, bss, and stack segments.
430 *
431 * XXX no demand paging (yet?)
432 */
433int
434exec_elf_makecmds(p, epp)
435	struct proc *p;
436	struct exec_package *epp;
437{
438	Elf32_Ehdr *eh = epp->ep_hdr;
439	Elf32_Phdr *ph, *pp;
440	int error, i, n;
441	char interp[MAXPATHLEN];
442	u_long pos = 0, phsize;
443
444	if (epp->ep_hdrvalid < sizeof(Elf32_Ehdr))
445		return ENOEXEC;
446
447	if (elf_check_header(eh, Elf32_et_exec))
448		return ENOEXEC;
449
450	/*
451         * check if vnode is in open for writing, because we want to
452         * demand-page out of it.  if it is, don't do it, for various
453         * reasons
454         */
455	if (epp->ep_vp->v_writecount != 0) {
456#ifdef DIAGNOSTIC
457		if (epp->ep_vp->v_flag & VTEXT)
458			panic("exec: a VTEXT vnode has writecount != 0\n");
459#endif
460		return ETXTBSY;
461	}
462	/*
463         * Allocate space to hold all the program headers, and read them
464         * from the file
465         */
466	phsize = eh->e_phnum * sizeof(Elf32_Phdr);
467	ph = (Elf32_Phdr *) malloc(phsize, M_TEMP, M_WAITOK);
468
469	if ((error = elf_read_from(p, epp->ep_vp, eh->e_phoff,
470				    (caddr_t) ph, phsize)) != 0)
471		goto bad;
472
473	epp->ep_tsize = ELF32_NO_ADDR;
474	epp->ep_dsize = ELF32_NO_ADDR;
475
476	interp[0] = '\0';
477
478	for (i = 0; i < eh->e_phnum; i++) {
479		pp = &ph[i];
480		if (pp->p_type == Elf32_pt_interp) {
481			if (pp->p_filesz >= sizeof(interp))
482				goto bad;
483			if ((error = elf_read_from(p, epp->ep_vp, pp->p_offset,
484				      (caddr_t) interp, pp->p_filesz)) != 0)
485				goto bad;
486			break;
487		}
488	}
489
490	/*
491	 * On the same architecture, we may be emulating different systems.
492	 * See which one will accept this executable. This currently only
493	 * applies to Linux and SVR4 on the i386.
494	 *
495	 * Probe functions would normally see if the interpreter (if any)
496	 * exists. Emulation packages may possibly replace the interpreter in
497	 * interp[] with a changed path (/emul/xxx/<path>), and also
498	 * set the ep_emul field in the exec package structure.
499	 */
500	if ((n = sizeof elf_probe_funcs / sizeof elf_probe_funcs[0])) {
501		error = ENOEXEC;
502		for (i = 0; i < n && error; i++)
503			error = elf_probe_funcs[i](p, epp, interp, &pos);
504
505		if (error)
506			goto bad;
507	}
508
509	/*
510         * Load all the necessary sections
511         */
512	for (i = 0; i < eh->e_phnum; i++) {
513		u_long  addr = ELF32_NO_ADDR, size = 0;
514		int prot = 0;
515
516		pp = &ph[i];
517
518		switch (ph[i].p_type) {
519		case Elf32_pt_load:
520			elf_load_psection(&epp->ep_vmcmds, epp->ep_vp,
521				&ph[i], &addr, &size, &prot);
522			if ((error = elf_set_segment(epp, addr, size,
523						      prot)) != 0)
524				goto bad;
525			break;
526
527		case Elf32_pt_shlib:
528			error = ENOEXEC;
529			goto bad;
530
531		case Elf32_pt_interp:
532			/* Already did this one */
533		case Elf32_pt_dynamic:
534		case Elf32_pt_phdr:
535		case Elf32_pt_note:
536			break;
537
538		default:
539			/*
540			 * Not fatal, we don't need to understand everything
541			 * :-)
542			 */
543			break;
544		}
545	}
546
547	/*
548         * Check if we found a dynamically linked binary and arrange to load
549         * it's interpreter
550         */
551	if (interp[0]) {
552		struct elf_args *ap;
553
554		ap = (struct elf_args *) malloc(sizeof(struct elf_args),
555						 M_TEMP, M_WAITOK);
556		if ((error = elf_load_file(p, interp, &epp->ep_vmcmds,
557				&epp->ep_entry, ap, &pos)) != 0) {
558			free((char *) ap, M_TEMP);
559			goto bad;
560		}
561		/* Arrange to load the program headers. */
562		pos = ELF_ALIGN(pos + NBPG, NBPG);
563		ap->arg_phaddr = pos;
564		NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_readvn, phsize,
565			  pos, epp->ep_vp, eh->e_phoff,
566			  VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE);
567		pos += phsize;
568
569		ap->arg_phentsize = eh->e_phentsize;
570		ap->arg_phnum = eh->e_phnum;
571		ap->arg_entry = eh->e_entry;
572
573		epp->ep_emul_arg = ap;
574	} else
575		epp->ep_entry = eh->e_entry;
576
577	free((char *) ph, M_TEMP);
578	epp->ep_vp->v_flag |= VTEXT;
579	return exec_aout_setup_stack(p, epp);
580
581bad:
582	free((char *) ph, M_TEMP);
583	kill_vmcmds(&epp->ep_vmcmds);
584	return ENOEXEC;
585}
586