imgact_elf.c revision 24131
1194140Simp/*-
2194140Simp * Copyright (c) 1995-1996 S�ren Schmidt
3194140Simp * Copyright (c) 1996 Peter Wemm
4194140Simp * All rights reserved.
5194140Simp *
6194140Simp * Redistribution and use in source and binary forms, with or without
7194140Simp * modification, are permitted provided that the following conditions
8194140Simp * are met:
9194140Simp * 1. Redistributions of source code must retain the above copyright
10194140Simp *    notice, this list of conditions and the following disclaimer
11194140Simp *    in this position and unchanged.
12194140Simp * 2. Redistributions in binary form must reproduce the above copyright
13194140Simp *    notice, this list of conditions and the following disclaimer in the
14194140Simp *    documentation and/or other materials provided with the distribution.
15194140Simp * 3. The name of the author may not be used to endorse or promote products
16194140Simp *    derived from this software withough specific prior written permission
17194140Simp *
18194140Simp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19194140Simp * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20194140Simp * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21194140Simp * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22194140Simp * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23194140Simp * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24194140Simp * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25194140Simp * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26194140Simp * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27194140Simp * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28194140Simp *
29194140Simp *	$Id: imgact_elf.c,v 1.16 1997/02/22 09:38:56 peter Exp $
30194140Simp */
31194140Simp
32196262Simp#include "opt_rlimit.h"
33196262Simp
34194140Simp#include <sys/param.h>
35196262Simp#include <sys/systm.h>
36196262Simp#include <sys/resourcevar.h>
37196262Simp#include <sys/exec.h>
38196262Simp#include <sys/mman.h>
39196262Simp#include <sys/imgact.h>
40196262Simp#include <sys/imgact_elf.h>
41196262Simp#include <sys/kernel.h>
42196262Simp#include <sys/sysent.h>
43196262Simp#include <sys/fcntl.h>
44196262Simp#include <sys/malloc.h>
45196262Simp#include <sys/mount.h>
46196262Simp#include <sys/namei.h>
47196262Simp#include <sys/proc.h>
48242302Sjmallett#include <sys/sysproto.h>
49196262Simp#include <sys/syscall.h>
50196262Simp#include <sys/signalvar.h>
51210311Sjmallett#include <sys/sysctl.h>
52210311Sjmallett#include <sys/vnode.h>
53196262Simp
54196262Simp#include <vm/vm.h>
55196262Simp#include <vm/vm_kern.h>
56196262Simp#include <vm/vm_param.h>
57196262Simp#include <vm/pmap.h>
58196262Simp#include <sys/lock.h>
59196262Simp#include <vm/vm_map.h>
60196262Simp#include <vm/vm_prot.h>
61196262Simp#include <vm/vm_extern.h>
62196262Simp
63194140Simp#include <machine/md_var.h>
64194140Simp#include <i386/linux/linux_syscall.h>
65202063Simp#include <i386/linux/linux.h>
66196262Simp
67196262Simp#define MAX_PHDR	32	/* XXX enough ? */
68196262Simp
69196262Simpstatic int map_pages __P((struct vnode *vp, vm_offset_t offset, vm_offset_t *buf, vm_size_t size));
70194140Simpstatic void unmap_pages __P((vm_offset_t buf, vm_size_t size));
71196262Simpstatic int elf_check_permissions __P((struct proc *p, struct vnode *vp));
72196262Simpstatic int elf_check_header __P((const Elf32_Ehdr *hdr, int type));
73196262Simpstatic int elf_load_section __P((struct vmspace *vmspace, struct vnode *vp, vm_offset_t offset, caddr_t vmaddr, size_t memsz, size_t filsz, vm_prot_t prot));
74194140Simpstatic int elf_load_file __P((struct proc *p, char *file, u_long *addr, u_long *entry));
75210311Sjmallettstatic int elf_freebsd_fixup __P((int **stack_base, struct image_params *imgp));
76210311Sjmallettint exec_elf_imgact __P((struct image_params *imgp));
77242273Sjmallett
78242342Sjmallettint elf_trace = 0;
79210311SjmallettSYSCTL_INT(_debug, 1, elf_trace, CTLFLAG_RW, &elf_trace, 0, "");
80210311Sjmallett#define UPRINTF if (elf_trace) uprintf
81210311Sjmallett
82232812Sjmallettstatic struct sysentvec elf_freebsd_sysvec = {
83232812Sjmallett        SYS_MAXSYSCALL,
84194140Simp        sysent,
85196262Simp        0,
86194140Simp        0,
87196262Simp        0,
88194140Simp        0,
89194140Simp        0,
90210311Sjmallett        elf_freebsd_fixup,
91210311Sjmallett        sendsig,
92210311Sjmallett        sigcode,
93210311Sjmallett        &szsigcode,
94210311Sjmallett        0,
95196262Simp	"FreeBSD ELF"
96217518Simp};
97217518Simp
98194140Simpstatic Elf32_Brandinfo freebsd_brand_info = {
99210311Sjmallett						"FreeBSD",
100210311Sjmallett						"",
101210311Sjmallett						"/usr/libexec/ld-elf.so.1",
102210311Sjmallett						&elf_freebsd_sysvec
103216069Sjmallett					  };
104210311Sjmallettstatic Elf32_Brandinfo *elf_brand_list[MAX_BRANDS] = {
105216069Sjmallett							&freebsd_brand_info,
106210311Sjmallett							NULL, NULL, NULL,
107210311Sjmallett							NULL, NULL, NULL, NULL
108210311Sjmallett						    };
109210311Sjmallett
110210311Sjmallettint
111210311Sjmallettelf_insert_brand_entry(Elf32_Brandinfo *entry)
112210311Sjmallett{
113210311Sjmallett	int i;
114210311Sjmallett
115216069Sjmallett	for (i=1; i<MAX_BRANDS; i++) {
116232812Sjmallett		if (elf_brand_list[i] == NULL) {
117232812Sjmallett			elf_brand_list[i] = entry;
118232812Sjmallett			break;
119232812Sjmallett		}
120232812Sjmallett	}
121232812Sjmallett	if (i == MAX_BRANDS)
122232812Sjmallett		return -1;
123232812Sjmallett	return 0;
124232812Sjmallett}
125232812Sjmallett
126210311Sjmallettint
127210311Sjmallettelf_remove_brand_entry(Elf32_Brandinfo *entry)
128210311Sjmallett{
129210311Sjmallett	int i;
130210311Sjmallett
131210311Sjmallett	for (i=1; i<MAX_BRANDS; i++) {
132200344Simp		if (elf_brand_list[i] == entry) {
133200344Simp			elf_brand_list[i] = NULL;
134210311Sjmallett			break;
135210311Sjmallett		}
136210311Sjmallett	}
137210311Sjmallett	if (i == MAX_BRANDS)
138210311Sjmallett		return -1;
139210311Sjmallett	return 0;
140210311Sjmallett}
141210311Sjmallett
142210311Sjmallettstatic int
143198669Srrsmap_pages(struct vnode *vp, vm_offset_t offset,
144198669Srrs	     vm_offset_t *buf, vm_size_t size)
145198669Srrs{
146198669Srrs	int error;
147198669Srrs	vm_offset_t kern_buf;
148196262Simp	vm_size_t pageoff;
149194140Simp
150194140Simp	/*
151194140Simp	 * The request may not be aligned, and may even cross several
152196314Simp	 * page boundaries in the file...
153196314Simp	 */
154194140Simp	pageoff = (offset & PAGE_MASK);
155210311Sjmallett	offset -= pageoff;		/* start of first aligned page to map */
156194140Simp	size += pageoff;
157194140Simp	size = round_page(size);	/* size of aligned pages to map */
158194140Simp
159194140Simp	if (error = vm_mmap(kernel_map,
160194140Simp			    &kern_buf,
161194140Simp			    size,
162194140Simp			    VM_PROT_READ,
163194140Simp			    VM_PROT_READ,
164201530Simp			    0,
165201530Simp			    (caddr_t)vp,
166194140Simp			    offset))
167194140Simp		return error;
168194140Simp
169194140Simp	*buf = kern_buf + pageoff;
170194140Simp
171194140Simp	return 0;
172194140Simp}
173194140Simp
174201530Simpstatic void
175201530Simpunmap_pages(vm_offset_t buf, vm_size_t size)
176194140Simp{
177233417Sgonzo	vm_size_t pageoff;
178233417Sgonzo
179210311Sjmallett	pageoff = (buf & PAGE_MASK);
180210311Sjmallett	buf -= pageoff;		/* start of first aligned page to map */
181210311Sjmallett	size += pageoff;
182210311Sjmallett	size = round_page(size);/* size of aligned pages to map */
183210311Sjmallett
184194140Simp      	vm_map_remove(kernel_map, buf, buf + size);
185210311Sjmallett}
186210311Sjmallett
187210311Sjmallettstatic int
188232812Sjmallettelf_check_permissions(struct proc *p, struct vnode *vp)
189232812Sjmallett{
190210311Sjmallett	struct vattr attr;
191233417Sgonzo	int error;
192233417Sgonzo
193233417Sgonzo	/*
194233417Sgonzo	 * Check number of open-for-writes on the file and deny execution
195233417Sgonzo	 *	if there are any.
196233417Sgonzo	 */
197233417Sgonzo	if (vp->v_writecount) {
198233417Sgonzo		return (ETXTBSY);
199194140Simp	}
200194140Simp
201210311Sjmallett	/* Get file attributes */
202210311Sjmallett	error = VOP_GETATTR(vp, &attr, p->p_ucred, p);
203194140Simp	if (error)
204210311Sjmallett		return (error);
205210311Sjmallett
206216318Sgonzo	/*
207194140Simp	 * 1) Check if file execution is disabled for the filesystem that this
208210311Sjmallett	 *	file resides on.
209194140Simp	 * 2) Insure that at least one execute bit is on - otherwise root
210242346Sjmallett	 *	will always succeed, and we don't want to happen unless the
211210311Sjmallett	 *	file really is executable.
212210311Sjmallett	 * 3) Insure that the file is a regular file.
213210311Sjmallett	 */
214194140Simp	if ((vp->v_mount->mnt_flag & MNT_NOEXEC) ||
215216318Sgonzo	    ((attr.va_mode & 0111) == 0) ||
216216320Sgonzo	    (attr.va_type != VREG)) {
217216318Sgonzo		return (EACCES);
218210311Sjmallett	}
219210311Sjmallett
220201530Simp	/*
221194140Simp	 * Zero length files can't be exec'd
222210311Sjmallett	 */
223210311Sjmallett	if (attr.va_size == 0)
224210311Sjmallett		return (ENOEXEC);
225210311Sjmallett
226210311Sjmallett	/*
227210311Sjmallett	 *  Check for execute permission to file based on current credentials.
228216773Sjmallett	 *	Then call filesystem specific open routine (which does nothing
229216773Sjmallett	 *	in the general case).
230216773Sjmallett	 */
231216773Sjmallett	error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
232216773Sjmallett	if (error)
233216773Sjmallett		return (error);
234216773Sjmallett
235216773Sjmallett	error = VOP_OPEN(vp, FREAD, p->p_ucred, p);
236210311Sjmallett	if (error)
237210311Sjmallett		return (error);
238210311Sjmallett
239210311Sjmallett	return (0);
240194140Simp}
241212842Sjmallett
242212842Sjmallettstatic int
243212842Sjmallettelf_check_header(const Elf32_Ehdr *hdr, int type)
244212842Sjmallett{
245212842Sjmallett	if (!(hdr->e_ident[EI_MAG0] == ELFMAG0 &&
246212842Sjmallett	      hdr->e_ident[EI_MAG1] == ELFMAG1 &&
247212842Sjmallett	      hdr->e_ident[EI_MAG2] == ELFMAG2 &&
248212842Sjmallett	      hdr->e_ident[EI_MAG3] == ELFMAG3))
249212842Sjmallett		return ENOEXEC;
250212842Sjmallett
251212842Sjmallett	if (hdr->e_machine != EM_386 && hdr->e_machine != EM_486)
252212842Sjmallett		return ENOEXEC;
253210311Sjmallett
254194140Simp	if (hdr->e_type != type)
255210311Sjmallett		return ENOEXEC;
256210311Sjmallett
257210311Sjmallett	return 0;
258210311Sjmallett}
259194140Simp
260210311Sjmallettstatic int
261210311Sjmallettelf_load_section(struct vmspace *vmspace, struct vnode *vp, vm_offset_t offset, caddr_t vmaddr, size_t memsz, size_t filsz, vm_prot_t prot)
262194140Simp{
263210311Sjmallett	size_t map_len;
264201530Simp	vm_offset_t map_addr;
265194140Simp	int error;
266216320Sgonzo	unsigned char *data_buf = 0;
267216318Sgonzo	size_t copy_len;
268216318Sgonzo
269202831Simp	map_addr = trunc_page(vmaddr);
270202831Simp
271202831Simp	if (memsz > filsz)
272196262Simp		map_len = trunc_page(offset+filsz) - trunc_page(offset);
273201530Simp	else
274201530Simp		map_len = round_page(offset+filsz) - trunc_page(offset);
275196262Simp
276210311Sjmallett	if (error = vm_mmap (&vmspace->vm_map,
277196262Simp			     &map_addr,
278243469Sjmallett			     map_len,
279194140Simp			     prot,
280243253Sjmallett			     VM_PROT_ALL,
281243253Sjmallett			     MAP_PRIVATE | MAP_FIXED,
282210311Sjmallett			     (caddr_t)vp,
283243253Sjmallett			     trunc_page(offset)))
284243253Sjmallett		return error;
285210311Sjmallett
286243253Sjmallett	if (memsz == filsz)
287210311Sjmallett		return 0;
288201845Simp
289201881Simp	/*
290243253Sjmallett	 * We have to map the remaining bit of the file into the kernel's
291243253Sjmallett	 * memory map, allocate some anonymous memory, and copy that last
292243253Sjmallett	 * bit into it. The remaining space should be .bss...
293202831Simp	 */
294201845Simp	copy_len = (offset + filsz) - trunc_page(offset + filsz);
295243253Sjmallett	map_addr = trunc_page(vmaddr + filsz);
296243469Sjmallett	map_len = round_page(vmaddr + memsz) - map_addr;
297243253Sjmallett
298243469Sjmallett        if (map_len != 0) {
299243469Sjmallett		if (error = vm_map_find(&vmspace->vm_map, NULL, 0,
300243469Sjmallett					&map_addr, map_len, FALSE,
301243469Sjmallett					VM_PROT_ALL, VM_PROT_ALL,0))
302243469Sjmallett			return error;
303243469Sjmallett	}
304243469Sjmallett
305243253Sjmallett	if (error = vm_mmap(kernel_map,
306243253Sjmallett			    (vm_offset_t *)&data_buf,
307243253Sjmallett			    PAGE_SIZE,
308243469Sjmallett			    VM_PROT_READ,
309243469Sjmallett			    VM_PROT_READ,
310243469Sjmallett			    0,
311243253Sjmallett			    (caddr_t)vp,
312243469Sjmallett			    trunc_page(offset + filsz)))
313243469Sjmallett		return error;
314243469Sjmallett
315243253Sjmallett	error = copyout(data_buf, (caddr_t)map_addr, copy_len);
316243253Sjmallett
317243253Sjmallett        vm_map_remove(kernel_map, (vm_offset_t)data_buf,
318243253Sjmallett		      (vm_offset_t)data_buf + PAGE_SIZE);
319243253Sjmallett
320243253Sjmallett	/*
321243253Sjmallett	 * set it to the specified protection
322243253Sjmallett	 */
323243253Sjmallett	vm_map_protect(&vmspace->vm_map, map_addr, map_addr + map_len,  prot,
324243253Sjmallett		       FALSE);
325243253Sjmallett
326243469Sjmallett	UPRINTF("bss size %d (%x)\n", map_len-copy_len, map_len-copy_len);
327243469Sjmallett	return error;
328243469Sjmallett}
329243469Sjmallett
330243253Sjmallettstatic int
331243253Sjmallettelf_load_file(struct proc *p, char *file, u_long *addr, u_long *entry)
332243469Sjmallett{
333243469Sjmallett	Elf32_Ehdr *hdr = NULL;
334243469Sjmallett	Elf32_Phdr *phdr = NULL;
335243469Sjmallett	struct nameidata nd;
336243469Sjmallett	struct vmspace *vmspace = p->p_vmspace;
337243469Sjmallett	vm_prot_t prot = 0;
338243469Sjmallett	unsigned long text_size = 0, data_size = 0;
339243469Sjmallett	unsigned long text_addr = 0, data_addr = 0;
340243469Sjmallett	int header_size = 0;
341243469Sjmallett        int error, i;
342202831Simp
343210311Sjmallett        NDINIT(&nd, LOOKUP, LOCKLEAF|FOLLOW, UIO_SYSSPACE, file, p);
344210311Sjmallett
345210311Sjmallett	if (error = namei(&nd))
346210311Sjmallett                goto fail;
347210311Sjmallett
348210311Sjmallett	if (nd.ni_vp == NULL) {
349196262Simp		error = ENOEXEC;
350194140Simp		goto fail;
351202831Simp	}
352202831Simp
353202831Simp	/*
354202831Simp	 * Check permissions, modes, uid, etc on the file, and "open" it.
355202831Simp	 */
356202831Simp	error = elf_check_permissions(p, nd.ni_vp);
357202831Simp
358196262Simp	/*
359202831Simp	 * No longer need this, and it prevents demand paging.
360196262Simp	 */
361196262Simp	VOP_UNLOCK(nd.ni_vp, 0, p);
362196262Simp
363202831Simp	if (error)
364202831Simp                goto fail;
365196262Simp
366196262Simp	/*
367202850Simp	 * Map in the header
368202850Simp	 */
369202850Simp	if (error = map_pages(nd.ni_vp, 0, (vm_offset_t *)&hdr, sizeof(hdr)))
370196262Simp                goto fail;
371217518Simp
372217518Simp	/*
373217518Simp	 * Do we have a valid ELF header ?
374210311Sjmallett	 */
375206721Sjmallett	if (error = elf_check_header(hdr, ET_DYN))
376217518Simp		goto fail;
377206721Sjmallett
378206721Sjmallett	/*
379206721Sjmallett	 * ouch, need to bounds check in case user gives us a corrupted
380210311Sjmallett	 * file with an insane header size
381206721Sjmallett	 */
382210311Sjmallett	if (hdr->e_phnum > MAX_PHDR) {	/* XXX: ever more than this? */
383206721Sjmallett		error = ENOEXEC;
384210311Sjmallett		goto fail;
385210311Sjmallett	}
386210311Sjmallett
387210311Sjmallett	header_size = hdr->e_phentsize * hdr->e_phnum;
388210311Sjmallett
389210311Sjmallett	if (error = map_pages(nd.ni_vp, hdr->e_phoff, (vm_offset_t *)&phdr,
390210311Sjmallett			         header_size))
391196262Simp        	goto fail;
392196262Simp
393210311Sjmallett	for (i = 0; i < hdr->e_phnum; i++) {
394210311Sjmallett		switch(phdr[i].p_type) {
395210311Sjmallett
396210311Sjmallett	   	case PT_NULL:	/* NULL section */
397210311Sjmallett	    		UPRINTF ("ELF(file) PT_NULL section\n");
398210311Sjmallett			break;
399210311Sjmallett		case PT_LOAD:	/* Loadable segment */
400210311Sjmallett		{
401210311Sjmallett	    		UPRINTF ("ELF(file) PT_LOAD section ");
402210311Sjmallett			if (phdr[i].p_flags & PF_X)
403210311Sjmallett  				prot |= VM_PROT_EXECUTE;
404210311Sjmallett			if (phdr[i].p_flags & PF_W)
405210311Sjmallett  				prot |= VM_PROT_WRITE;
406210311Sjmallett			if (phdr[i].p_flags & PF_R)
407210311Sjmallett  				prot |= VM_PROT_READ;
408242302Sjmallett
409242302Sjmallett			if (error = elf_load_section(vmspace, nd.ni_vp,
410242302Sjmallett  						     phdr[i].p_offset,
411242302Sjmallett  						     (caddr_t)phdr[i].p_vaddr +
412242302Sjmallett							(*addr),
413242302Sjmallett  						     phdr[i].p_memsz,
414242302Sjmallett  						     phdr[i].p_filesz, prot))
415242302Sjmallett				goto fail;
416242302Sjmallett
417242302Sjmallett			/*
418242302Sjmallett			 * Is this .text or .data ??
419242302Sjmallett			 *
420242302Sjmallett			 * We only handle one each of those yet XXX
421242302Sjmallett			 */
422242302Sjmallett			if (hdr->e_entry >= phdr[i].p_vaddr &&
423242302Sjmallett			hdr->e_entry <(phdr[i].p_vaddr+phdr[i].p_memsz)) {
424242302Sjmallett  				text_addr = trunc_page(phdr[i].p_vaddr+(*addr));
425242302Sjmallett  				text_size = round_page(phdr[i].p_memsz +
426242302Sjmallett						       phdr[i].p_vaddr -
427242302Sjmallett						       trunc_page(phdr[i].p_vaddr));
428242302Sjmallett				*entry=(unsigned long)hdr->e_entry+(*addr);
429242302Sjmallett	    			UPRINTF(".text <%08x,%08x> entry=%08x\n",
430242302Sjmallett					text_addr, text_size, *entry);
431242302Sjmallett			} else {
432242302Sjmallett  				data_addr = trunc_page(phdr[i].p_vaddr+(*addr));
433242302Sjmallett  				data_size = round_page(phdr[i].p_memsz +
434242302Sjmallett						       phdr[i].p_vaddr -
435242302Sjmallett						       trunc_page(phdr[i].p_vaddr));
436242302Sjmallett	    			UPRINTF(".data <%08x,%08x>\n",
437242302Sjmallett					data_addr, data_size);
438242302Sjmallett			}
439242302Sjmallett		}
440242302Sjmallett		break;
441242302Sjmallett
442242302Sjmallett	   	case PT_DYNAMIC:/* Dynamic link information */
443242302Sjmallett	    		UPRINTF ("ELF(file) PT_DYNAMIC section\n");
444242302Sjmallett			break;
445242302Sjmallett	  	case PT_INTERP:	/* Path to interpreter */
446242302Sjmallett	    		UPRINTF ("ELF(file) PT_INTERP section\n");
447242302Sjmallett			break;
448243470Sjmallett	  	case PT_NOTE:	/* Note section */
449243470Sjmallett	    		UPRINTF ("ELF(file) PT_NOTE section\n");
450243470Sjmallett			break;
451243470Sjmallett	  	case PT_SHLIB:	/* Shared lib section  */
452243470Sjmallett	    		UPRINTF ("ELF(file) PT_SHLIB section\n");
453243470Sjmallett			break;
454243470Sjmallett		case PT_PHDR: 	/* Program header table info */
455243470Sjmallett	    		UPRINTF ("ELF(file) PT_PHDR section\n");
456243470Sjmallett			break;
457243470Sjmallett		default:
458243470Sjmallett	    		UPRINTF ("ELF(file) %d section ??\n", phdr[i].p_type );
459243470Sjmallett		}
460243470Sjmallett	}
461243470Sjmallett
462243470Sjmallettfail:
463243470Sjmallett	if (phdr)
464243470Sjmallett		unmap_pages((vm_offset_t)phdr, header_size);
465243470Sjmallett	if (hdr)
466215990Sjmallett		unmap_pages((vm_offset_t)hdr, sizeof(hdr));
467215990Sjmallett
468215990Sjmallett	return error;
469215990Sjmallett}
470215990Sjmallett
471215990Sjmallettint
472215990Sjmallettexec_elf_imgact(struct image_params *imgp)
473215990Sjmallett{
474215990Sjmallett	const Elf32_Ehdr *hdr = (const Elf32_Ehdr *) imgp->image_header;
475215990Sjmallett	const Elf32_Phdr *phdr, *mapped_phdr = NULL;
476215990Sjmallett	Elf32_Auxargs *elf_auxargs = NULL;
477215990Sjmallett	struct vmspace *vmspace = imgp->proc->p_vmspace;
478215990Sjmallett	vm_prot_t prot = 0;
479215990Sjmallett	u_long text_size = 0, data_size = 0;
480215990Sjmallett	u_long text_addr = 0, data_addr = 0;
481215990Sjmallett	u_long addr, entry = 0, proghdr = 0;
482215990Sjmallett	int error, i, header_size = 0, interp_len = 0;
483215990Sjmallett	char *interp = NULL;
484215990Sjmallett	char *brand = NULL;
485215990Sjmallett	char path[MAXPATHLEN];
486215990Sjmallett
487215990Sjmallett	/*
488215990Sjmallett	 * Do we have a valid ELF header ?
489215990Sjmallett	 */
490215990Sjmallett	if (elf_check_header(hdr, ET_EXEC))
491215990Sjmallett		return -1;
492215990Sjmallett
493215990Sjmallett	/*
494215990Sjmallett	 * From here on down, we return an errno, not -1, as we've
495215990Sjmallett	 * detected an ELF file.
496215990Sjmallett	 */
497215990Sjmallett
498215990Sjmallett	/*
499215990Sjmallett	 * ouch, need to bounds check in case user gives us a corrupted
500215990Sjmallett	 * file with an insane header size
501215990Sjmallett	 */
502215990Sjmallett	if (hdr->e_phnum > MAX_PHDR) {	/* XXX: ever more than this? */
503215990Sjmallett		return ENOEXEC;
504215990Sjmallett	}
505215990Sjmallett
506215990Sjmallett	header_size = hdr->e_phentsize * hdr->e_phnum;
507215990Sjmallett
508215990Sjmallett	if ((hdr->e_phoff > PAGE_SIZE) ||
509202831Simp	    (hdr->e_phoff + header_size) > PAGE_SIZE) {
510194140Simp	  	/*
511194140Simp		 * Ouch ! we only get one page full of header...
512194140Simp		 * Try to map it in ourselves, and see how we go.
513194140Simp	   	 */
514194140Simp		if (error = map_pages(imgp->vp, hdr->e_phoff,
515194140Simp				(vm_offset_t *)&mapped_phdr, header_size))
516194140Simp			return (error);
517194140Simp		/*
518194140Simp		 * Save manual mapping for cleanup
519194140Simp		 */
520194140Simp		phdr = mapped_phdr;
521194140Simp	} else {
522194140Simp		phdr = (const Elf32_Phdr*)
523194140Simp		       ((const char *)imgp->image_header + hdr->e_phoff);
524194140Simp	}
525194140Simp
526194140Simp	/*
527194140Simp	 * From this point on, we may have resources that need to be freed.
528194140Simp	 */
529194140Simp	if (error = exec_extract_strings(imgp))
530194140Simp		goto fail;
531194140Simp
532194140Simp	exec_new_vmspace(imgp);
533194140Simp
534194140Simp	for (i = 0; i < hdr->e_phnum; i++) {
535194140Simp		switch(phdr[i].p_type) {
536194140Simp
537194140Simp	   	case PT_NULL:	/* NULL section */
538194140Simp	    		UPRINTF ("ELF PT_NULL section\n");
539200344Simp			break;
540200344Simp		case PT_LOAD:	/* Loadable segment */
541200344Simp		{
542194140Simp	    		UPRINTF ("ELF PT_LOAD section ");
543200344Simp			if (phdr[i].p_flags & PF_X)
544200344Simp  				prot |= VM_PROT_EXECUTE;
545200344Simp			if (phdr[i].p_flags & PF_W)
546200344Simp  				prot |= VM_PROT_WRITE;
547200344Simp			if (phdr[i].p_flags & PF_R)
548200344Simp  				prot |= VM_PROT_READ;
549194140Simp
550200344Simp			if (error = elf_load_section(vmspace, imgp->vp,
551200344Simp  						     phdr[i].p_offset,
552200344Simp  						     (caddr_t)phdr[i].p_vaddr,
553200344Simp  						     phdr[i].p_memsz,
554200344Simp  						     phdr[i].p_filesz, prot))
555200344Simp  				goto fail;
556200344Simp
557200344Simp			/*
558200344Simp			 * Is this .text or .data ??
559200344Simp			 *
560200344Simp			 * We only handle one each of those yet XXX
561200344Simp			 */
562200344Simp			if (hdr->e_entry >= phdr[i].p_vaddr &&
563200344Simp			hdr->e_entry <(phdr[i].p_vaddr+phdr[i].p_memsz)) {
564200344Simp  				text_addr = trunc_page(phdr[i].p_vaddr);
565200344Simp  				text_size = round_page(phdr[i].p_memsz +
566200344Simp						       phdr[i].p_vaddr -
567200344Simp						       text_addr);
568200344Simp				entry = (u_long)hdr->e_entry;
569200344Simp	    			UPRINTF(".text <%08x,%08x> entry=%08x\n",
570200344Simp					text_addr, text_size, entry);
571200344Simp			} else {
572200344Simp  				data_addr = trunc_page(phdr[i].p_vaddr);
573194140Simp  				data_size = round_page(phdr[i].p_memsz +
574194140Simp						       phdr[i].p_vaddr -
575243253Sjmallett						       data_addr);
576243253Sjmallett	    			UPRINTF(".data <%08x,%08x>\n",
577243253Sjmallett					data_addr, data_size);
578243253Sjmallett			}
579194140Simp		}
580200344Simp		break;
581200344Simp
582243253Sjmallett	   	case PT_DYNAMIC:/* Dynamic link information */
583243253Sjmallett	    		UPRINTF ("ELF PT_DYNAMIC section ??\n");
584243253Sjmallett			break;
585243253Sjmallett	  	case PT_INTERP:	/* Path to interpreter */
586243253Sjmallett	    		UPRINTF ("ELF PT_INTERP section ");
587210311Sjmallett			if (phdr[i].p_filesz > MAXPATHLEN) {
588243253Sjmallett				error = ENOEXEC;
589243253Sjmallett				goto fail;
590243253Sjmallett			}
591243253Sjmallett			interp_len = MAXPATHLEN;
592243253Sjmallett			if (error = map_pages(imgp->vp, phdr[i].p_offset,
593243253Sjmallett					 (vm_offset_t *)&interp, interp_len))
594243253Sjmallett				goto fail;
595194140Simp			UPRINTF("<%s>\n", interp);
596215990Sjmallett			break;
597210311Sjmallett	  	case PT_NOTE:	/* Note section */
598210311Sjmallett	    		UPRINTF ("ELF PT_NOTE section\n");
599210311Sjmallett			break;
600210311Sjmallett	  	case PT_SHLIB:	/* Shared lib section  */
601242276Sjmallett	    		UPRINTF ("ELF PT_SHLIB section\n");
602242276Sjmallett			break;
603228088Sgonzo		case PT_PHDR: 	/* Program header table info */
604228853Sgonzo	    		UPRINTF ("ELF PT_PHDR section <%x>\n", phdr[i].p_vaddr);
605228853Sgonzo			proghdr = phdr[i].p_vaddr;
606228872Sgonzo			break;
607228872Sgonzo		default:
608232402Sjmallett	    		UPRINTF ("ELF %d section ??\n", phdr[i].p_type);
609242276Sjmallett		}
610242276Sjmallett	}
611242276Sjmallett
612242276Sjmallett	vmspace->vm_tsize = text_size >> PAGE_SHIFT;
613242276Sjmallett	vmspace->vm_taddr = (caddr_t)text_addr;
614243253Sjmallett	vmspace->vm_dsize = data_size >> PAGE_SHIFT;
615194140Simp	vmspace->vm_daddr = (caddr_t)data_addr;
616194140Simp
617200344Simp	addr = 2*MAXDSIZ; /* May depend on OS type XXX */
618200344Simp
619194140Simp	imgp->entry_addr = entry;
620243253Sjmallett
621243253Sjmallett	/*
622243253Sjmallett	 * So which kind (brand) of ELF binary do we have at hand
623243253Sjmallett	 * FreeBSD, Linux, SVR4 or something else ??
624243253Sjmallett	 * If its has a interpreter section try that first
625210311Sjmallett	 */
626243253Sjmallett        if (interp) {
627243253Sjmallett                for (i=0; i<MAX_BRANDS; i++) {
628194140Simp                        if (elf_brand_list[i] != NULL) {
629210311Sjmallett                                if (!strcmp(interp, elf_brand_list[i]->interp_path)) {
630243253Sjmallett                                        imgp->proc->p_sysent =
631243253Sjmallett                                                elf_brand_list[i]->sysvec;
632243253Sjmallett                                        strcpy(path, elf_brand_list[i]->emul_path);
633243253Sjmallett                                        strcat(path, elf_brand_list[i]->interp_path);
634243253Sjmallett                                        UPRINTF("interpreter=<%s> %s\n",
635243253Sjmallett                                                elf_brand_list[i]->interp_path,
636243253Sjmallett                                                elf_brand_list[i]->emul_path);
637243253Sjmallett                                        break;
638243253Sjmallett                                }
639210311Sjmallett                        }
640242273Sjmallett                }
641242273Sjmallett        }
642242273Sjmallett
643242273Sjmallett	/*
644242273Sjmallett	 * If there is no interpreter, or recognition of it
645242273Sjmallett	 * failed, se if the binary is branded.
646242273Sjmallett	 */
647242273Sjmallett	if (!interp || i == MAX_BRANDS) {
648242273Sjmallett		brand = (char *)&(hdr->e_ident[EI_BRAND]);
649242273Sjmallett		for (i=0; i<MAX_BRANDS; i++) {
650242273Sjmallett			if (elf_brand_list[i] != NULL) {
651242273Sjmallett				if (!strcmp(brand, elf_brand_list[i]->brand)) {
652243253Sjmallett					imgp->proc->p_sysent = elf_brand_list[i]->sysvec;
653243253Sjmallett					if (interp) {
654243253Sjmallett						strcpy(path, elf_brand_list[i]->emul_path);
655243253Sjmallett						strcat(path, elf_brand_list[i]->interp_path);
656215990Sjmallett						UPRINTF("interpreter=<%s> %s\n",
657210311Sjmallett						elf_brand_list[i]->interp_path,
658242342Sjmallett						elf_brand_list[i]->emul_path);
659242342Sjmallett					}
660242342Sjmallett					break;
661194140Simp				}
662202831Simp			}
663		}
664	}
665	if (i == MAX_BRANDS) {
666		uprintf("ELF binary type not known\n");
667		error = ENOEXEC;
668		goto fail;
669	}
670	if (interp) {
671                if (error = elf_load_file(imgp->proc,
672                                          path,
673                                          &addr,        /* XXX */
674                                          &imgp->entry_addr)) {
675                        uprintf("ELF interpreter %s not found\n", path);
676                        goto fail;
677                }
678	}
679
680	UPRINTF("Executing %s binary\n", elf_brand_list[i]->brand);
681
682	/*
683	 * Construct auxargs table (used by the fixup routine)
684	 */
685	elf_auxargs = malloc(sizeof(Elf32_Auxargs), M_TEMP, M_WAITOK);
686	elf_auxargs->execfd = -1;
687	elf_auxargs->phdr = proghdr;
688	elf_auxargs->phent = hdr->e_phentsize;
689	elf_auxargs->phnum = hdr->e_phnum;
690	elf_auxargs->pagesz = PAGE_SIZE;
691	elf_auxargs->base = addr;
692	elf_auxargs->flags = 0;
693	elf_auxargs->entry = entry;
694	elf_auxargs->trace = elf_trace;
695
696	imgp->auxargs = elf_auxargs;
697	imgp->interpreted = 0;
698
699	/* don't allow modifying the file while we run it */
700	imgp->vp->v_flag |= VTEXT;
701
702fail:
703	if (mapped_phdr)
704		unmap_pages((vm_offset_t)mapped_phdr, header_size);
705	if (interp)
706		unmap_pages((vm_offset_t)interp, interp_len);
707
708	return error;
709}
710
711static int
712elf_freebsd_fixup(int **stack_base, struct image_params *imgp)
713{
714	Elf32_Auxargs *args = (Elf32_Auxargs *)imgp->auxargs;
715	int *pos;
716
717	pos = *stack_base + (imgp->argc + imgp->envc + 2);
718
719	if (args->trace) {
720		AUXARGS_ENTRY(pos, AT_DEBUG, 1);
721	}
722	if (args->execfd != -1) {
723		AUXARGS_ENTRY(pos, AT_EXECFD, args->execfd);
724	}
725	AUXARGS_ENTRY(pos, AT_PHDR, args->phdr);
726	AUXARGS_ENTRY(pos, AT_PHENT, args->phent);
727	AUXARGS_ENTRY(pos, AT_PHNUM, args->phnum);
728	AUXARGS_ENTRY(pos, AT_PAGESZ, args->pagesz);
729	AUXARGS_ENTRY(pos, AT_FLAGS, args->flags);
730	AUXARGS_ENTRY(pos, AT_ENTRY, args->entry);
731	AUXARGS_ENTRY(pos, AT_BASE, args->base);
732	AUXARGS_ENTRY(pos, AT_NULL, 0);
733
734	free(imgp->auxargs, M_TEMP);
735	imgp->auxargs = NULL;
736
737	(*stack_base)--;
738	**stack_base = (int)imgp->argc;
739	return 0;
740}
741
742/*
743 * Tell kern_execve.c about it, with a little help from the linker.
744 * Since `const' objects end up in the text segment, TEXT_SET is the
745 * correct directive to use.
746 */
747const struct execsw elf_execsw = {exec_elf_imgact, "ELF"};
748TEXT_SET(execsw_set, elf_execsw);
749
750