xref: /freebsd/sys/kern/imgact_elf.c (revision c8a7999933a3c8b9918feabe0c4798cc5fc862cb)
1e1743d02SSøren Schmidt /*-
2e1743d02SSøren Schmidt  * Copyright (c) 1995-1996 S�ren Schmidt
3e1743d02SSøren Schmidt  * Copyright (c) 1996 Peter Wemm
4e1743d02SSøren Schmidt  * All rights reserved.
5e1743d02SSøren Schmidt  *
6e1743d02SSøren Schmidt  * Redistribution and use in source and binary forms, with or without
7e1743d02SSøren Schmidt  * modification, are permitted provided that the following conditions
8e1743d02SSøren Schmidt  * are met:
9e1743d02SSøren Schmidt  * 1. Redistributions of source code must retain the above copyright
10e1743d02SSøren Schmidt  *    notice, this list of conditions and the following disclaimer
11e1743d02SSøren Schmidt  *    in this position and unchanged.
12e1743d02SSøren Schmidt  * 2. Redistributions in binary form must reproduce the above copyright
13e1743d02SSøren Schmidt  *    notice, this list of conditions and the following disclaimer in the
14e1743d02SSøren Schmidt  *    documentation and/or other materials provided with the distribution.
15e1743d02SSøren Schmidt  * 3. The name of the author may not be used to endorse or promote products
16e1743d02SSøren Schmidt  *    derived from this software withough specific prior written permission
17e1743d02SSøren Schmidt  *
18e1743d02SSøren Schmidt  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19e1743d02SSøren Schmidt  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20e1743d02SSøren Schmidt  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21e1743d02SSøren Schmidt  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22e1743d02SSøren Schmidt  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23e1743d02SSøren Schmidt  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24e1743d02SSøren Schmidt  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25e1743d02SSøren Schmidt  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26e1743d02SSøren Schmidt  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27e1743d02SSøren Schmidt  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28e1743d02SSøren Schmidt  *
29c8a79999SPeter Wemm  *	$Id: imgact_elf.c,v 1.21 1998/02/09 06:09:21 eivind Exp $
30e1743d02SSøren Schmidt  */
31e1743d02SSøren Schmidt 
32e9822d92SJoerg Wunsch #include "opt_rlimit.h"
33e9822d92SJoerg Wunsch 
34e1743d02SSøren Schmidt #include <sys/param.h>
35e1743d02SSøren Schmidt #include <sys/systm.h>
36e1743d02SSøren Schmidt #include <sys/exec.h>
37e1743d02SSøren Schmidt #include <sys/mman.h>
38e1743d02SSøren Schmidt #include <sys/imgact.h>
39e1743d02SSøren Schmidt #include <sys/imgact_elf.h>
40e1743d02SSøren Schmidt #include <sys/kernel.h>
41e1743d02SSøren Schmidt #include <sys/sysent.h>
423ac4d1efSBruce Evans #include <sys/fcntl.h>
43e1743d02SSøren Schmidt #include <sys/malloc.h>
44e1743d02SSøren Schmidt #include <sys/mount.h>
45a794e791SBruce Evans #include <sys/namei.h>
46a794e791SBruce Evans #include <sys/proc.h>
47e1743d02SSøren Schmidt #include <sys/syscall.h>
48e1743d02SSøren Schmidt #include <sys/signalvar.h>
49e1743d02SSøren Schmidt #include <sys/sysctl.h>
50a794e791SBruce Evans #include <sys/vnode.h>
51e1743d02SSøren Schmidt 
52e1743d02SSøren Schmidt #include <vm/vm.h>
53e1743d02SSøren Schmidt #include <vm/vm_kern.h>
54e1743d02SSøren Schmidt #include <vm/vm_param.h>
55e1743d02SSøren Schmidt #include <vm/pmap.h>
56996c772fSJohn Dyson #include <sys/lock.h>
57e1743d02SSøren Schmidt #include <vm/vm_map.h>
58e1743d02SSøren Schmidt #include <vm/vm_prot.h>
59e1743d02SSøren Schmidt #include <vm/vm_extern.h>
60e1743d02SSøren Schmidt 
61e1743d02SSøren Schmidt #include <machine/md_var.h>
62e1743d02SSøren Schmidt 
63e1743d02SSøren Schmidt #define MAX_PHDR	32	/* XXX enough ? */
64e1743d02SSøren Schmidt 
65e0c95ed9SBruce Evans static int elf_check_header __P((const Elf32_Ehdr *hdr, int type));
66e1743d02SSøren Schmidt static 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));
67e1743d02SSøren Schmidt static int elf_load_file __P((struct proc *p, char *file, u_long *addr, u_long *entry));
68e1743d02SSøren Schmidt static int elf_freebsd_fixup __P((int **stack_base, struct image_params *imgp));
69303b270bSEivind Eklund static int exec_elf_imgact __P((struct image_params *imgp));
70e1743d02SSøren Schmidt 
71d8a4f230SBruce Evans static int elf_trace = 0;
72d8a4f230SBruce Evans SYSCTL_INT(_debug, OID_AUTO, elf_trace, CTLFLAG_RW, &elf_trace, 0, "");
73e1743d02SSøren Schmidt #define UPRINTF if (elf_trace) uprintf
74e1743d02SSøren Schmidt 
75e1743d02SSøren Schmidt static struct sysentvec elf_freebsd_sysvec = {
76e1743d02SSøren Schmidt         SYS_MAXSYSCALL,
77e1743d02SSøren Schmidt         sysent,
78e1743d02SSøren Schmidt         0,
79e1743d02SSøren Schmidt         0,
80e1743d02SSøren Schmidt         0,
81e1743d02SSøren Schmidt         0,
82e1743d02SSøren Schmidt         0,
83e1743d02SSøren Schmidt         elf_freebsd_fixup,
84e1743d02SSøren Schmidt         sendsig,
85e1743d02SSøren Schmidt         sigcode,
86e1743d02SSøren Schmidt         &szsigcode,
87e1743d02SSøren Schmidt         0,
886ead3eddSJohn Dyson 	"FreeBSD ELF"
89e1743d02SSøren Schmidt };
90e1743d02SSøren Schmidt 
91ea5a2b2eSSøren Schmidt static Elf32_Brandinfo freebsd_brand_info = {
92ea5a2b2eSSøren Schmidt 						"FreeBSD",
93ea5a2b2eSSøren Schmidt 						"",
94e1743d02SSøren Schmidt 						"/usr/libexec/ld-elf.so.1",
95ea5a2b2eSSøren Schmidt 						&elf_freebsd_sysvec
96e1743d02SSøren Schmidt 					  };
97ea5a2b2eSSøren Schmidt static Elf32_Brandinfo *elf_brand_list[MAX_BRANDS] = {
98ea5a2b2eSSøren Schmidt 							&freebsd_brand_info,
99e1743d02SSøren Schmidt 							NULL, NULL, NULL,
100e1743d02SSøren Schmidt 							NULL, NULL, NULL, NULL
101e1743d02SSøren Schmidt 						    };
102e1743d02SSøren Schmidt 
103e1743d02SSøren Schmidt int
104ea5a2b2eSSøren Schmidt elf_insert_brand_entry(Elf32_Brandinfo *entry)
105e1743d02SSøren Schmidt {
106e1743d02SSøren Schmidt 	int i;
107e1743d02SSøren Schmidt 
108ea5a2b2eSSøren Schmidt 	for (i=1; i<MAX_BRANDS; i++) {
109ea5a2b2eSSøren Schmidt 		if (elf_brand_list[i] == NULL) {
110ea5a2b2eSSøren Schmidt 			elf_brand_list[i] = entry;
111e1743d02SSøren Schmidt 			break;
112e1743d02SSøren Schmidt 		}
113e1743d02SSøren Schmidt 	}
114ea5a2b2eSSøren Schmidt 	if (i == MAX_BRANDS)
115e1743d02SSøren Schmidt 		return -1;
116e1743d02SSøren Schmidt 	return 0;
117e1743d02SSøren Schmidt }
118e1743d02SSøren Schmidt 
119e1743d02SSøren Schmidt int
120ea5a2b2eSSøren Schmidt elf_remove_brand_entry(Elf32_Brandinfo *entry)
121e1743d02SSøren Schmidt {
122e1743d02SSøren Schmidt 	int i;
123e1743d02SSøren Schmidt 
124ea5a2b2eSSøren Schmidt 	for (i=1; i<MAX_BRANDS; i++) {
125ea5a2b2eSSøren Schmidt 		if (elf_brand_list[i] == entry) {
126ea5a2b2eSSøren Schmidt 			elf_brand_list[i] = NULL;
127e1743d02SSøren Schmidt 			break;
128e1743d02SSøren Schmidt 		}
129e1743d02SSøren Schmidt 	}
130ea5a2b2eSSøren Schmidt 	if (i == MAX_BRANDS)
131e1743d02SSøren Schmidt 		return -1;
132e1743d02SSøren Schmidt 	return 0;
133e1743d02SSøren Schmidt }
134e1743d02SSøren Schmidt 
135e1743d02SSøren Schmidt static int
136e0c95ed9SBruce Evans elf_check_header(const Elf32_Ehdr *hdr, int type)
137e1743d02SSøren Schmidt {
138e1743d02SSøren Schmidt 	if (!(hdr->e_ident[EI_MAG0] == ELFMAG0 &&
139e1743d02SSøren Schmidt 	      hdr->e_ident[EI_MAG1] == ELFMAG1 &&
140e1743d02SSøren Schmidt 	      hdr->e_ident[EI_MAG2] == ELFMAG2 &&
141e1743d02SSøren Schmidt 	      hdr->e_ident[EI_MAG3] == ELFMAG3))
142e1743d02SSøren Schmidt 		return ENOEXEC;
143e1743d02SSøren Schmidt 
144e1743d02SSøren Schmidt 	if (hdr->e_machine != EM_386 && hdr->e_machine != EM_486)
145e1743d02SSøren Schmidt 		return ENOEXEC;
146e1743d02SSøren Schmidt 
147e1743d02SSøren Schmidt 	if (hdr->e_type != type)
148e1743d02SSøren Schmidt 		return ENOEXEC;
149e1743d02SSøren Schmidt 
150e1743d02SSøren Schmidt 	return 0;
151e1743d02SSøren Schmidt }
152e1743d02SSøren Schmidt 
153e1743d02SSøren Schmidt static int
154e1743d02SSøren Schmidt elf_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)
155e1743d02SSøren Schmidt {
156e1743d02SSøren Schmidt 	size_t map_len;
157e1743d02SSøren Schmidt 	vm_offset_t map_addr;
158e1743d02SSøren Schmidt 	int error;
159e1743d02SSøren Schmidt 	unsigned char *data_buf = 0;
160e1743d02SSøren Schmidt 	size_t copy_len;
161e1743d02SSøren Schmidt 
162e1743d02SSøren Schmidt 	map_addr = trunc_page(vmaddr);
163e1743d02SSøren Schmidt 
164e1743d02SSøren Schmidt 	if (memsz > filsz)
165e1743d02SSøren Schmidt 		map_len = trunc_page(offset+filsz) - trunc_page(offset);
166e1743d02SSøren Schmidt 	else
167e1743d02SSøren Schmidt 		map_len = round_page(offset+filsz) - trunc_page(offset);
168e1743d02SSøren Schmidt 
169e1743d02SSøren Schmidt 	if (error = vm_mmap (&vmspace->vm_map,
170e1743d02SSøren Schmidt 			     &map_addr,
171e1743d02SSøren Schmidt 			     map_len,
172e1743d02SSøren Schmidt 			     prot,
173e1743d02SSøren Schmidt 			     VM_PROT_ALL,
17471d7d1b1SPeter Wemm 			     MAP_PRIVATE | MAP_FIXED,
175e1743d02SSøren Schmidt 			     (caddr_t)vp,
176e1743d02SSøren Schmidt 			     trunc_page(offset)))
177e1743d02SSøren Schmidt 		return error;
178e1743d02SSøren Schmidt 
179e1743d02SSøren Schmidt 	if (memsz == filsz)
180e1743d02SSøren Schmidt 		return 0;
181e1743d02SSøren Schmidt 
182e1743d02SSøren Schmidt 	/*
183e1743d02SSøren Schmidt 	 * We have to map the remaining bit of the file into the kernel's
184e1743d02SSøren Schmidt 	 * memory map, allocate some anonymous memory, and copy that last
185e1743d02SSøren Schmidt 	 * bit into it. The remaining space should be .bss...
186e1743d02SSøren Schmidt 	 */
187e1743d02SSøren Schmidt 	copy_len = (offset + filsz) - trunc_page(offset + filsz);
188e1743d02SSøren Schmidt 	map_addr = trunc_page(vmaddr + filsz);
189250c11f9SPeter Wemm 	map_len = round_page(vmaddr + memsz) - map_addr;
190e1743d02SSøren Schmidt 
1918191d577SPeter Wemm         if (map_len != 0) {
192e1743d02SSøren Schmidt 		if (error = vm_map_find(&vmspace->vm_map, NULL, 0,
193e1743d02SSøren Schmidt 					&map_addr, map_len, FALSE,
194e1743d02SSøren Schmidt 					VM_PROT_ALL, VM_PROT_ALL,0))
195e1743d02SSøren Schmidt 			return error;
1968191d577SPeter Wemm 	}
197e1743d02SSøren Schmidt 
198c8a79999SPeter Wemm 	if (error = vm_mmap(exec_map,
199e1743d02SSøren Schmidt 			    (vm_offset_t *)&data_buf,
200e1743d02SSøren Schmidt 			    PAGE_SIZE,
201e1743d02SSøren Schmidt 			    VM_PROT_READ,
202e1743d02SSøren Schmidt 			    VM_PROT_READ,
20371d7d1b1SPeter Wemm 			    0,
204e1743d02SSøren Schmidt 			    (caddr_t)vp,
205e1743d02SSøren Schmidt 			    trunc_page(offset + filsz)))
206e1743d02SSøren Schmidt 		return error;
207e1743d02SSøren Schmidt 
208e1743d02SSøren Schmidt 	error = copyout(data_buf, (caddr_t)map_addr, copy_len);
209e1743d02SSøren Schmidt 
210c8a79999SPeter Wemm         vm_map_remove(exec_map, (vm_offset_t)data_buf,
211e1743d02SSøren Schmidt 		      (vm_offset_t)data_buf + PAGE_SIZE);
212e1743d02SSøren Schmidt 
213e1743d02SSøren Schmidt 	/*
2148191d577SPeter Wemm 	 * set it to the specified protection
215e1743d02SSøren Schmidt 	 */
2168191d577SPeter Wemm 	vm_map_protect(&vmspace->vm_map, map_addr, map_addr + map_len,  prot,
2178191d577SPeter Wemm 		       FALSE);
2188191d577SPeter Wemm 
219e1743d02SSøren Schmidt 	UPRINTF("bss size %d (%x)\n", map_len-copy_len, map_len-copy_len);
220e1743d02SSøren Schmidt 	return error;
221e1743d02SSøren Schmidt }
222e1743d02SSøren Schmidt 
223e1743d02SSøren Schmidt static int
224e1743d02SSøren Schmidt elf_load_file(struct proc *p, char *file, u_long *addr, u_long *entry)
225e1743d02SSøren Schmidt {
226e1743d02SSøren Schmidt 	Elf32_Ehdr *hdr = NULL;
227e1743d02SSøren Schmidt 	Elf32_Phdr *phdr = NULL;
228e1743d02SSøren Schmidt 	struct nameidata nd;
229e1743d02SSøren Schmidt 	struct vmspace *vmspace = p->p_vmspace;
230c8a79999SPeter Wemm 	struct vattr attr;
231c8a79999SPeter Wemm 	struct image_params image_params, *imgp;
232e1743d02SSøren Schmidt 	vm_prot_t prot = 0;
233e1743d02SSøren Schmidt 	unsigned long text_size = 0, data_size = 0;
234e1743d02SSøren Schmidt 	unsigned long text_addr = 0, data_addr = 0;
235e1743d02SSøren Schmidt 	int header_size = 0;
236e1743d02SSøren Schmidt         int error, i;
237e1743d02SSøren Schmidt 
238c8a79999SPeter Wemm 	imgp = &image_params;
239c8a79999SPeter Wemm 	/*
240c8a79999SPeter Wemm 	 * Initialize part of the common data
241c8a79999SPeter Wemm 	 */
242c8a79999SPeter Wemm 	imgp->proc = p;
243c8a79999SPeter Wemm 	imgp->uap = NULL;
244c8a79999SPeter Wemm 	imgp->attr = &attr;
245c8a79999SPeter Wemm 	imgp->firstpage = NULL;
246c8a79999SPeter Wemm 	imgp->image_header = (char *)kmem_alloc_wait(exec_map, PAGE_SIZE);
247c8a79999SPeter Wemm 
248c8a79999SPeter Wemm 	if (imgp->image_header == NULL) {
249c8a79999SPeter Wemm 		nd.ni_vp = NULL;
250c8a79999SPeter Wemm 		error = ENOMEM;
251c8a79999SPeter Wemm 		goto fail;
252c8a79999SPeter Wemm 	}
253c8a79999SPeter Wemm 
254e1743d02SSøren Schmidt         NDINIT(&nd, LOOKUP, LOCKLEAF|FOLLOW, UIO_SYSSPACE, file, p);
255e1743d02SSøren Schmidt 
2561560a9d5SPeter Wemm 	if (error = namei(&nd)) {
2571560a9d5SPeter Wemm 		nd.ni_vp = NULL;
258e1743d02SSøren Schmidt 		goto fail;
259e1743d02SSøren Schmidt 	}
260e1743d02SSøren Schmidt 
261c8a79999SPeter Wemm 	imgp->vp = nd.ni_vp;
262c8a79999SPeter Wemm 
263e1743d02SSøren Schmidt 	/*
264e1743d02SSøren Schmidt 	 * Check permissions, modes, uid, etc on the file, and "open" it.
265e1743d02SSøren Schmidt 	 */
266c8a79999SPeter Wemm 	error = exec_check_permissions(imgp);
267c8a79999SPeter Wemm 	if (error) {
268996c772fSJohn Dyson 		VOP_UNLOCK(nd.ni_vp, 0, p);
269c8a79999SPeter Wemm 		goto fail;
270c8a79999SPeter Wemm 	}
271e1743d02SSøren Schmidt 
272c8a79999SPeter Wemm 	error = exec_map_first_page(imgp);
273c8a79999SPeter Wemm 	VOP_UNLOCK(nd.ni_vp, 0, p);
274e1743d02SSøren Schmidt 	if (error)
275e1743d02SSøren Schmidt                 goto fail;
276e1743d02SSøren Schmidt 
277c8a79999SPeter Wemm 	hdr = (Elf32_Ehdr *)imgp->image_header;
278e1743d02SSøren Schmidt 	if (error = elf_check_header(hdr, ET_DYN))
279e1743d02SSøren Schmidt 		goto fail;
280e1743d02SSøren Schmidt 
281e1743d02SSøren Schmidt 	/*
282e1743d02SSøren Schmidt 	 * ouch, need to bounds check in case user gives us a corrupted
283e1743d02SSøren Schmidt 	 * file with an insane header size
284e1743d02SSøren Schmidt 	 */
285e1743d02SSøren Schmidt 	if (hdr->e_phnum > MAX_PHDR) {	/* XXX: ever more than this? */
286e1743d02SSøren Schmidt 		error = ENOEXEC;
287e1743d02SSøren Schmidt 		goto fail;
288e1743d02SSøren Schmidt 	}
289e1743d02SSøren Schmidt 
290e1743d02SSøren Schmidt 	header_size = hdr->e_phentsize * hdr->e_phnum;
291e1743d02SSøren Schmidt 
292c8a79999SPeter Wemm 	/* Only support headers that fit within first page for now */
293c8a79999SPeter Wemm 	if (header_size + hdr->e_phoff > PAGE_SIZE) {
294c8a79999SPeter Wemm 		error = ENOEXEC;
295e1743d02SSøren Schmidt 		goto fail;
296c8a79999SPeter Wemm 	}
297c8a79999SPeter Wemm 
298c8a79999SPeter Wemm 	phdr = (Elf32_Phdr *)(imgp->image_header + hdr->e_phoff);
299e1743d02SSøren Schmidt 
300e1743d02SSøren Schmidt 	for (i = 0; i < hdr->e_phnum; i++) {
301e1743d02SSøren Schmidt 		switch(phdr[i].p_type) {
302e1743d02SSøren Schmidt 
303e1743d02SSøren Schmidt 	   	case PT_NULL:	/* NULL section */
304e1743d02SSøren Schmidt 	    		UPRINTF ("ELF(file) PT_NULL section\n");
305e1743d02SSøren Schmidt 			break;
306e1743d02SSøren Schmidt 		case PT_LOAD:	/* Loadable segment */
307e1743d02SSøren Schmidt 		{
308e1743d02SSøren Schmidt 	    		UPRINTF ("ELF(file) PT_LOAD section ");
309e1743d02SSøren Schmidt 			if (phdr[i].p_flags & PF_X)
310e1743d02SSøren Schmidt   				prot |= VM_PROT_EXECUTE;
311e1743d02SSøren Schmidt 			if (phdr[i].p_flags & PF_W)
312e1743d02SSøren Schmidt   				prot |= VM_PROT_WRITE;
313e1743d02SSøren Schmidt 			if (phdr[i].p_flags & PF_R)
314e1743d02SSøren Schmidt   				prot |= VM_PROT_READ;
315e1743d02SSøren Schmidt 
316e1743d02SSøren Schmidt 			if (error = elf_load_section(vmspace, nd.ni_vp,
317e1743d02SSøren Schmidt   						     phdr[i].p_offset,
318e1743d02SSøren Schmidt   						     (caddr_t)phdr[i].p_vaddr +
319e1743d02SSøren Schmidt 							(*addr),
320e1743d02SSøren Schmidt   						     phdr[i].p_memsz,
321e1743d02SSøren Schmidt   						     phdr[i].p_filesz, prot))
322e1743d02SSøren Schmidt 				goto fail;
323e1743d02SSøren Schmidt 
324e1743d02SSøren Schmidt 			/*
325e1743d02SSøren Schmidt 			 * Is this .text or .data ??
326e1743d02SSøren Schmidt 			 *
327e1743d02SSøren Schmidt 			 * We only handle one each of those yet XXX
328e1743d02SSøren Schmidt 			 */
329e1743d02SSøren Schmidt 			if (hdr->e_entry >= phdr[i].p_vaddr &&
330e1743d02SSøren Schmidt 			hdr->e_entry <(phdr[i].p_vaddr+phdr[i].p_memsz)) {
331e1743d02SSøren Schmidt   				text_addr = trunc_page(phdr[i].p_vaddr+(*addr));
3328191d577SPeter Wemm   				text_size = round_page(phdr[i].p_memsz +
3338191d577SPeter Wemm 						       phdr[i].p_vaddr -
3348191d577SPeter Wemm 						       trunc_page(phdr[i].p_vaddr));
335e1743d02SSøren Schmidt 				*entry=(unsigned long)hdr->e_entry+(*addr);
336e1743d02SSøren Schmidt 	    			UPRINTF(".text <%08x,%08x> entry=%08x\n",
337e1743d02SSøren Schmidt 					text_addr, text_size, *entry);
338e1743d02SSøren Schmidt 			} else {
339e1743d02SSøren Schmidt   				data_addr = trunc_page(phdr[i].p_vaddr+(*addr));
3408191d577SPeter Wemm   				data_size = round_page(phdr[i].p_memsz +
3418191d577SPeter Wemm 						       phdr[i].p_vaddr -
3428191d577SPeter Wemm 						       trunc_page(phdr[i].p_vaddr));
343e1743d02SSøren Schmidt 	    			UPRINTF(".data <%08x,%08x>\n",
344e1743d02SSøren Schmidt 					data_addr, data_size);
345e1743d02SSøren Schmidt 			}
346e1743d02SSøren Schmidt 		}
347e1743d02SSøren Schmidt 		break;
348e1743d02SSøren Schmidt 
349e1743d02SSøren Schmidt 	   	case PT_DYNAMIC:/* Dynamic link information */
350e1743d02SSøren Schmidt 	    		UPRINTF ("ELF(file) PT_DYNAMIC section\n");
351e1743d02SSøren Schmidt 			break;
352e1743d02SSøren Schmidt 	  	case PT_INTERP:	/* Path to interpreter */
353e1743d02SSøren Schmidt 	    		UPRINTF ("ELF(file) PT_INTERP section\n");
354e1743d02SSøren Schmidt 			break;
355e1743d02SSøren Schmidt 	  	case PT_NOTE:	/* Note section */
356e1743d02SSøren Schmidt 	    		UPRINTF ("ELF(file) PT_NOTE section\n");
357e1743d02SSøren Schmidt 			break;
358e1743d02SSøren Schmidt 	  	case PT_SHLIB:	/* Shared lib section  */
359e1743d02SSøren Schmidt 	    		UPRINTF ("ELF(file) PT_SHLIB section\n");
360e1743d02SSøren Schmidt 			break;
361e1743d02SSøren Schmidt 		case PT_PHDR: 	/* Program header table info */
362e1743d02SSøren Schmidt 	    		UPRINTF ("ELF(file) PT_PHDR section\n");
363e1743d02SSøren Schmidt 			break;
364e1743d02SSøren Schmidt 		default:
365e1743d02SSøren Schmidt 	    		UPRINTF ("ELF(file) %d section ??\n", phdr[i].p_type );
366e1743d02SSøren Schmidt 		}
367e1743d02SSøren Schmidt 	}
368e1743d02SSøren Schmidt 
369e1743d02SSøren Schmidt fail:
370c8a79999SPeter Wemm 	if (imgp->firstpage)
371c8a79999SPeter Wemm 		exec_unmap_first_page(imgp);
372c8a79999SPeter Wemm 	if (imgp->image_header)
373c8a79999SPeter Wemm 		kmem_free_wakeup(exec_map, (vm_offset_t)imgp->image_header,
374c8a79999SPeter Wemm 			PAGE_SIZE);
3751560a9d5SPeter Wemm 	if (nd.ni_vp)
3761560a9d5SPeter Wemm 		vrele(nd.ni_vp);
377e1743d02SSøren Schmidt 
378e1743d02SSøren Schmidt 	return error;
379e1743d02SSøren Schmidt }
380e1743d02SSøren Schmidt 
381303b270bSEivind Eklund static int
382e1743d02SSøren Schmidt exec_elf_imgact(struct image_params *imgp)
383e1743d02SSøren Schmidt {
384e0c95ed9SBruce Evans 	const Elf32_Ehdr *hdr = (const Elf32_Ehdr *) imgp->image_header;
385e0c95ed9SBruce Evans 	const Elf32_Phdr *phdr, *mapped_phdr = NULL;
386e1743d02SSøren Schmidt 	Elf32_Auxargs *elf_auxargs = NULL;
3875856e12eSJohn Dyson 	struct vmspace *vmspace;
388e1743d02SSøren Schmidt 	vm_prot_t prot = 0;
389e1743d02SSøren Schmidt 	u_long text_size = 0, data_size = 0;
390e1743d02SSøren Schmidt 	u_long text_addr = 0, data_addr = 0;
391e1743d02SSøren Schmidt 	u_long addr, entry = 0, proghdr = 0;
392c8a79999SPeter Wemm 	int error, i, header_size = 0;
393c8a79999SPeter Wemm 	const char *interp = NULL;
394ea5a2b2eSSøren Schmidt 	char *brand = NULL;
395ea5a2b2eSSøren Schmidt 	char path[MAXPATHLEN];
396e1743d02SSøren Schmidt 
397e1743d02SSøren Schmidt 	/*
398e1743d02SSøren Schmidt 	 * Do we have a valid ELF header ?
399e1743d02SSøren Schmidt 	 */
400e1743d02SSøren Schmidt 	if (elf_check_header(hdr, ET_EXEC))
401e1743d02SSøren Schmidt 		return -1;
402e1743d02SSøren Schmidt 
403e1743d02SSøren Schmidt 	/*
404e1743d02SSøren Schmidt 	 * From here on down, we return an errno, not -1, as we've
405e1743d02SSøren Schmidt 	 * detected an ELF file.
406e1743d02SSøren Schmidt 	 */
407e1743d02SSøren Schmidt 
408e1743d02SSøren Schmidt 	/*
409e1743d02SSøren Schmidt 	 * ouch, need to bounds check in case user gives us a corrupted
410e1743d02SSøren Schmidt 	 * file with an insane header size
411e1743d02SSøren Schmidt 	 */
412e1743d02SSøren Schmidt 	if (hdr->e_phnum > MAX_PHDR) {	/* XXX: ever more than this? */
413e1743d02SSøren Schmidt 		return ENOEXEC;
414e1743d02SSøren Schmidt 	}
415e1743d02SSøren Schmidt 
416e1743d02SSøren Schmidt 	header_size = hdr->e_phentsize * hdr->e_phnum;
417e1743d02SSøren Schmidt 
418e1743d02SSøren Schmidt 	if ((hdr->e_phoff > PAGE_SIZE) ||
419e1743d02SSøren Schmidt 	    (hdr->e_phoff + header_size) > PAGE_SIZE) {
420c8a79999SPeter Wemm 		/* Only support headers in first page for now */
421c8a79999SPeter Wemm 		return ENOEXEC;
422e1743d02SSøren Schmidt 	} else {
423e0c95ed9SBruce Evans 		phdr = (const Elf32_Phdr*)
424e0c95ed9SBruce Evans 		       ((const char *)imgp->image_header + hdr->e_phoff);
425e1743d02SSøren Schmidt 	}
426e1743d02SSøren Schmidt 
427e1743d02SSøren Schmidt 	/*
428e1743d02SSøren Schmidt 	 * From this point on, we may have resources that need to be freed.
429e1743d02SSøren Schmidt 	 */
430e1743d02SSøren Schmidt 	if (error = exec_extract_strings(imgp))
431e1743d02SSøren Schmidt 		goto fail;
432e1743d02SSøren Schmidt 
433e1743d02SSøren Schmidt 	exec_new_vmspace(imgp);
434e1743d02SSøren Schmidt 
4355856e12eSJohn Dyson 	vmspace = imgp->proc->p_vmspace;
4365856e12eSJohn Dyson 
437e1743d02SSøren Schmidt 	for (i = 0; i < hdr->e_phnum; i++) {
438e1743d02SSøren Schmidt 		switch(phdr[i].p_type) {
439e1743d02SSøren Schmidt 
440e1743d02SSøren Schmidt 	   	case PT_NULL:	/* NULL section */
441e1743d02SSøren Schmidt 	    		UPRINTF ("ELF PT_NULL section\n");
442e1743d02SSøren Schmidt 			break;
443e1743d02SSøren Schmidt 		case PT_LOAD:	/* Loadable segment */
444e1743d02SSøren Schmidt 		{
445e1743d02SSøren Schmidt 	    		UPRINTF ("ELF PT_LOAD section ");
446e1743d02SSøren Schmidt 			if (phdr[i].p_flags & PF_X)
447e1743d02SSøren Schmidt   				prot |= VM_PROT_EXECUTE;
448e1743d02SSøren Schmidt 			if (phdr[i].p_flags & PF_W)
449e1743d02SSøren Schmidt   				prot |= VM_PROT_WRITE;
450e1743d02SSøren Schmidt 			if (phdr[i].p_flags & PF_R)
451e1743d02SSøren Schmidt   				prot |= VM_PROT_READ;
452e1743d02SSøren Schmidt 
453e1743d02SSøren Schmidt 			if (error = elf_load_section(vmspace, imgp->vp,
454e1743d02SSøren Schmidt   						     phdr[i].p_offset,
455e1743d02SSøren Schmidt   						     (caddr_t)phdr[i].p_vaddr,
456e1743d02SSøren Schmidt   						     phdr[i].p_memsz,
457e1743d02SSøren Schmidt   						     phdr[i].p_filesz, prot))
458e1743d02SSøren Schmidt   				goto fail;
459e1743d02SSøren Schmidt 
460e1743d02SSøren Schmidt 			/*
461e1743d02SSøren Schmidt 			 * Is this .text or .data ??
462e1743d02SSøren Schmidt 			 *
463e1743d02SSøren Schmidt 			 * We only handle one each of those yet XXX
464e1743d02SSøren Schmidt 			 */
465e1743d02SSøren Schmidt 			if (hdr->e_entry >= phdr[i].p_vaddr &&
466e1743d02SSøren Schmidt 			hdr->e_entry <(phdr[i].p_vaddr+phdr[i].p_memsz)) {
467e1743d02SSøren Schmidt   				text_addr = trunc_page(phdr[i].p_vaddr);
4688191d577SPeter Wemm   				text_size = round_page(phdr[i].p_memsz +
4698191d577SPeter Wemm 						       phdr[i].p_vaddr -
4708191d577SPeter Wemm 						       text_addr);
471e1743d02SSøren Schmidt 				entry = (u_long)hdr->e_entry;
472e1743d02SSøren Schmidt 	    			UPRINTF(".text <%08x,%08x> entry=%08x\n",
473e1743d02SSøren Schmidt 					text_addr, text_size, entry);
474e1743d02SSøren Schmidt 			} else {
475e1743d02SSøren Schmidt   				data_addr = trunc_page(phdr[i].p_vaddr);
4768191d577SPeter Wemm   				data_size = round_page(phdr[i].p_memsz +
4778191d577SPeter Wemm 						       phdr[i].p_vaddr -
4788191d577SPeter Wemm 						       data_addr);
479e1743d02SSøren Schmidt 	    			UPRINTF(".data <%08x,%08x>\n",
480e1743d02SSøren Schmidt 					data_addr, data_size);
481e1743d02SSøren Schmidt 			}
482e1743d02SSøren Schmidt 		}
483e1743d02SSøren Schmidt 		break;
484e1743d02SSøren Schmidt 
485e1743d02SSøren Schmidt 	   	case PT_DYNAMIC:/* Dynamic link information */
486e1743d02SSøren Schmidt 	    		UPRINTF ("ELF PT_DYNAMIC section ??\n");
487e1743d02SSøren Schmidt 			break;
488e1743d02SSøren Schmidt 	  	case PT_INTERP:	/* Path to interpreter */
489e1743d02SSøren Schmidt 	    		UPRINTF ("ELF PT_INTERP section ");
490c8a79999SPeter Wemm 			if (phdr[i].p_filesz > MAXPATHLEN ||
491c8a79999SPeter Wemm 			    phdr[i].p_offset + phdr[i].p_filesz > PAGE_SIZE) {
492e1743d02SSøren Schmidt 				error = ENOEXEC;
493e1743d02SSøren Schmidt 				goto fail;
494e1743d02SSøren Schmidt 			}
495c8a79999SPeter Wemm 			interp = imgp->image_header + phdr[i].p_offset;
496e1743d02SSøren Schmidt 			UPRINTF("<%s>\n", interp);
497e1743d02SSøren Schmidt 			break;
498e1743d02SSøren Schmidt 	  	case PT_NOTE:	/* Note section */
499e1743d02SSøren Schmidt 	    		UPRINTF ("ELF PT_NOTE section\n");
500e1743d02SSøren Schmidt 			break;
501e1743d02SSøren Schmidt 	  	case PT_SHLIB:	/* Shared lib section  */
502e1743d02SSøren Schmidt 	    		UPRINTF ("ELF PT_SHLIB section\n");
503e1743d02SSøren Schmidt 			break;
504e1743d02SSøren Schmidt 		case PT_PHDR: 	/* Program header table info */
505e1743d02SSøren Schmidt 	    		UPRINTF ("ELF PT_PHDR section <%x>\n", phdr[i].p_vaddr);
506e1743d02SSøren Schmidt 			proghdr = phdr[i].p_vaddr;
507e1743d02SSøren Schmidt 			break;
508e1743d02SSøren Schmidt 		default:
509e1743d02SSøren Schmidt 	    		UPRINTF ("ELF %d section ??\n", phdr[i].p_type);
510e1743d02SSøren Schmidt 		}
511e1743d02SSøren Schmidt 	}
512e1743d02SSøren Schmidt 
513e1743d02SSøren Schmidt 	vmspace->vm_tsize = text_size >> PAGE_SHIFT;
514e1743d02SSøren Schmidt 	vmspace->vm_taddr = (caddr_t)text_addr;
515e1743d02SSøren Schmidt 	vmspace->vm_dsize = data_size >> PAGE_SHIFT;
516e1743d02SSøren Schmidt 	vmspace->vm_daddr = (caddr_t)data_addr;
517e1743d02SSøren Schmidt 
518e1743d02SSøren Schmidt 	addr = 2*MAXDSIZ; /* May depend on OS type XXX */
519e1743d02SSøren Schmidt 
520ea5a2b2eSSøren Schmidt 	imgp->entry_addr = entry;
521ea5a2b2eSSøren Schmidt 
522e1743d02SSøren Schmidt 	/*
523ea5a2b2eSSøren Schmidt 	 * So which kind (brand) of ELF binary do we have at hand
524ea5a2b2eSSøren Schmidt 	 * FreeBSD, Linux, SVR4 or something else ??
525ea5a2b2eSSøren Schmidt 	 * If its has a interpreter section try that first
526e1743d02SSøren Schmidt 	 */
527ea5a2b2eSSøren Schmidt         if (interp) {
528ea5a2b2eSSøren Schmidt                 for (i=0; i<MAX_BRANDS; i++) {
529ea5a2b2eSSøren Schmidt                         if (elf_brand_list[i] != NULL) {
530ea5a2b2eSSøren Schmidt                                 if (!strcmp(interp, elf_brand_list[i]->interp_path)) {
531e1743d02SSøren Schmidt                                         imgp->proc->p_sysent =
532ea5a2b2eSSøren Schmidt                                                 elf_brand_list[i]->sysvec;
533ea5a2b2eSSøren Schmidt                                         strcpy(path, elf_brand_list[i]->emul_path);
534ea5a2b2eSSøren Schmidt                                         strcat(path, elf_brand_list[i]->interp_path);
535e1743d02SSøren Schmidt                                         UPRINTF("interpreter=<%s> %s\n",
536ea5a2b2eSSøren Schmidt                                                 elf_brand_list[i]->interp_path,
537ea5a2b2eSSøren Schmidt                                                 elf_brand_list[i]->emul_path);
538e1743d02SSøren Schmidt                                         break;
539e1743d02SSøren Schmidt                                 }
540e1743d02SSøren Schmidt                         }
541e1743d02SSøren Schmidt                 }
542ea5a2b2eSSøren Schmidt         }
543ea5a2b2eSSøren Schmidt 
544ea5a2b2eSSøren Schmidt 	/*
545ea5a2b2eSSøren Schmidt 	 * If there is no interpreter, or recognition of it
546ea5a2b2eSSøren Schmidt 	 * failed, se if the binary is branded.
547ea5a2b2eSSøren Schmidt 	 */
548ea5a2b2eSSøren Schmidt 	if (!interp || i == MAX_BRANDS) {
549ea5a2b2eSSøren Schmidt 		brand = (char *)&(hdr->e_ident[EI_BRAND]);
550ea5a2b2eSSøren Schmidt 		for (i=0; i<MAX_BRANDS; i++) {
551ea5a2b2eSSøren Schmidt 			if (elf_brand_list[i] != NULL) {
552ea5a2b2eSSøren Schmidt 				if (!strcmp(brand, elf_brand_list[i]->brand)) {
553ea5a2b2eSSøren Schmidt 					imgp->proc->p_sysent = elf_brand_list[i]->sysvec;
554ea5a2b2eSSøren Schmidt 					if (interp) {
555ea5a2b2eSSøren Schmidt 						strcpy(path, elf_brand_list[i]->emul_path);
556ea5a2b2eSSøren Schmidt 						strcat(path, elf_brand_list[i]->interp_path);
557ea5a2b2eSSøren Schmidt 						UPRINTF("interpreter=<%s> %s\n",
558ea5a2b2eSSøren Schmidt 						elf_brand_list[i]->interp_path,
559ea5a2b2eSSøren Schmidt 						elf_brand_list[i]->emul_path);
560ea5a2b2eSSøren Schmidt 					}
561d672246bSSøren Schmidt 					break;
562ea5a2b2eSSøren Schmidt 				}
563ea5a2b2eSSøren Schmidt 			}
564ea5a2b2eSSøren Schmidt 		}
565ea5a2b2eSSøren Schmidt 	}
566ea5a2b2eSSøren Schmidt 	if (i == MAX_BRANDS) {
567ea5a2b2eSSøren Schmidt 		uprintf("ELF binary type not known\n");
568e1743d02SSøren Schmidt 		error = ENOEXEC;
569e1743d02SSøren Schmidt 		goto fail;
570e1743d02SSøren Schmidt 	}
571ea5a2b2eSSøren Schmidt 	if (interp) {
572e1743d02SSøren Schmidt                 if (error = elf_load_file(imgp->proc,
573e1743d02SSøren Schmidt                                           path,
574e1743d02SSøren Schmidt                                           &addr,        /* XXX */
575e1743d02SSøren Schmidt                                           &imgp->entry_addr)) {
576e1743d02SSøren Schmidt                         uprintf("ELF interpreter %s not found\n", path);
577e1743d02SSøren Schmidt                         goto fail;
578e1743d02SSøren Schmidt                 }
579e1743d02SSøren Schmidt 	}
580ea5a2b2eSSøren Schmidt 
581717fb679SSøren Schmidt 	UPRINTF("Executing %s binary\n", elf_brand_list[i]->brand);
582e1743d02SSøren Schmidt 
583e1743d02SSøren Schmidt 	/*
584e1743d02SSøren Schmidt 	 * Construct auxargs table (used by the fixup routine)
585e1743d02SSøren Schmidt 	 */
586e1743d02SSøren Schmidt 	elf_auxargs = malloc(sizeof(Elf32_Auxargs), M_TEMP, M_WAITOK);
587e1743d02SSøren Schmidt 	elf_auxargs->execfd = -1;
588e1743d02SSøren Schmidt 	elf_auxargs->phdr = proghdr;
589e1743d02SSøren Schmidt 	elf_auxargs->phent = hdr->e_phentsize;
590e1743d02SSøren Schmidt 	elf_auxargs->phnum = hdr->e_phnum;
591e1743d02SSøren Schmidt 	elf_auxargs->pagesz = PAGE_SIZE;
592e1743d02SSøren Schmidt 	elf_auxargs->base = addr;
593e1743d02SSøren Schmidt 	elf_auxargs->flags = 0;
594e1743d02SSøren Schmidt 	elf_auxargs->entry = entry;
595e1743d02SSøren Schmidt 	elf_auxargs->trace = elf_trace;
596e1743d02SSøren Schmidt 
597e1743d02SSøren Schmidt 	imgp->auxargs = elf_auxargs;
598e1743d02SSøren Schmidt 	imgp->interpreted = 0;
599e1743d02SSøren Schmidt 
600e1743d02SSøren Schmidt 	/* don't allow modifying the file while we run it */
601e1743d02SSøren Schmidt 	imgp->vp->v_flag |= VTEXT;
602e1743d02SSøren Schmidt 
603e1743d02SSøren Schmidt fail:
604e1743d02SSøren Schmidt 	return error;
605e1743d02SSøren Schmidt }
606e1743d02SSøren Schmidt 
607e1743d02SSøren Schmidt static int
608e1743d02SSøren Schmidt elf_freebsd_fixup(int **stack_base, struct image_params *imgp)
609e1743d02SSøren Schmidt {
610e1743d02SSøren Schmidt 	Elf32_Auxargs *args = (Elf32_Auxargs *)imgp->auxargs;
611e1743d02SSøren Schmidt 	int *pos;
612e1743d02SSøren Schmidt 
613e1743d02SSøren Schmidt 	pos = *stack_base + (imgp->argc + imgp->envc + 2);
614e1743d02SSøren Schmidt 
615e1743d02SSøren Schmidt 	if (args->trace) {
616e1743d02SSøren Schmidt 		AUXARGS_ENTRY(pos, AT_DEBUG, 1);
617e1743d02SSøren Schmidt 	}
618e1743d02SSøren Schmidt 	if (args->execfd != -1) {
619e1743d02SSøren Schmidt 		AUXARGS_ENTRY(pos, AT_EXECFD, args->execfd);
620e1743d02SSøren Schmidt 	}
621e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_PHDR, args->phdr);
622e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_PHENT, args->phent);
623e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_PHNUM, args->phnum);
624e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_PAGESZ, args->pagesz);
625e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_FLAGS, args->flags);
626e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_ENTRY, args->entry);
627e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_BASE, args->base);
628e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_NULL, 0);
629e1743d02SSøren Schmidt 
630e1743d02SSøren Schmidt 	free(imgp->auxargs, M_TEMP);
631e1743d02SSøren Schmidt 	imgp->auxargs = NULL;
632e1743d02SSøren Schmidt 
633e1743d02SSøren Schmidt 	(*stack_base)--;
634e1743d02SSøren Schmidt 	**stack_base = (int)imgp->argc;
635e1743d02SSøren Schmidt 	return 0;
636e1743d02SSøren Schmidt }
637e1743d02SSøren Schmidt 
638e1743d02SSøren Schmidt /*
639e1743d02SSøren Schmidt  * Tell kern_execve.c about it, with a little help from the linker.
640e1743d02SSøren Schmidt  * Since `const' objects end up in the text segment, TEXT_SET is the
641e1743d02SSøren Schmidt  * correct directive to use.
642e1743d02SSøren Schmidt  */
643d8a4f230SBruce Evans static const struct execsw elf_execsw = {exec_elf_imgact, "ELF"};
644e1743d02SSøren Schmidt TEXT_SET(execsw_set, elf_execsw);
645e1743d02SSøren Schmidt 
646