xref: /freebsd/sys/kern/imgact_elf.c (revision ecbb00a2629050fd720dc376a33c45f4ad767cea)
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  *
29ecbb00a2SDoug Rabson  *	$Id: imgact_elf.c,v 1.24 1998/04/28 18:15:07 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>
42e1743d02SSøren Schmidt #include <sys/malloc.h>
43a794e791SBruce Evans #include <sys/namei.h>
44a794e791SBruce Evans #include <sys/proc.h>
45e1743d02SSøren Schmidt #include <sys/syscall.h>
46e1743d02SSøren Schmidt #include <sys/signalvar.h>
47e1743d02SSøren Schmidt #include <sys/sysctl.h>
48a794e791SBruce Evans #include <sys/vnode.h>
49e1743d02SSøren Schmidt 
50e1743d02SSøren Schmidt #include <vm/vm.h>
51e1743d02SSøren Schmidt #include <vm/vm_kern.h>
52e1743d02SSøren Schmidt #include <vm/vm_param.h>
53e1743d02SSøren Schmidt #include <vm/pmap.h>
54996c772fSJohn Dyson #include <sys/lock.h>
55e1743d02SSøren Schmidt #include <vm/vm_map.h>
56e1743d02SSøren Schmidt #include <vm/vm_prot.h>
57e1743d02SSøren Schmidt #include <vm/vm_extern.h>
58e1743d02SSøren Schmidt 
59e1743d02SSøren Schmidt #include <machine/md_var.h>
60e1743d02SSøren Schmidt 
61e1743d02SSøren Schmidt #define MAX_PHDR	32	/* XXX enough ? */
62e1743d02SSøren Schmidt 
63ecbb00a2SDoug Rabson #if ELF_TARG_CLASS == ELFCLASS32
64ecbb00a2SDoug Rabson 
65ecbb00a2SDoug Rabson #define Elf_Ehdr	Elf32_Ehdr
66ecbb00a2SDoug Rabson #define Elf_Phdr	Elf32_Phdr
67ecbb00a2SDoug Rabson #define Elf_Auxargs	Elf32_Auxargs
68ecbb00a2SDoug Rabson #define Elf_Brandinfo	Elf32_Brandinfo
69ecbb00a2SDoug Rabson 
70ecbb00a2SDoug Rabson #else
71ecbb00a2SDoug Rabson 
72ecbb00a2SDoug Rabson #define Elf_Ehdr	Elf64_Ehdr
73ecbb00a2SDoug Rabson #define Elf_Phdr	Elf64_Phdr
74ecbb00a2SDoug Rabson #define Elf_Auxargs	Elf64_Auxargs
75ecbb00a2SDoug Rabson #define Elf_Brandinfo	Elf64_Brandinfo
76ecbb00a2SDoug Rabson 
77ecbb00a2SDoug Rabson #endif
78ecbb00a2SDoug Rabson 
79ecbb00a2SDoug Rabson 
80ecbb00a2SDoug Rabson static int elf_check_header __P((const Elf_Ehdr *hdr, int type));
81e1743d02SSø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));
82e1743d02SSøren Schmidt static int elf_load_file __P((struct proc *p, char *file, u_long *addr, u_long *entry));
83ecbb00a2SDoug Rabson static int elf_freebsd_fixup __P((long **stack_base, struct image_params *imgp));
84303b270bSEivind Eklund static int exec_elf_imgact __P((struct image_params *imgp));
85e1743d02SSøren Schmidt 
86d8a4f230SBruce Evans static int elf_trace = 0;
87d8a4f230SBruce Evans SYSCTL_INT(_debug, OID_AUTO, elf_trace, CTLFLAG_RW, &elf_trace, 0, "");
88e1743d02SSøren Schmidt #define UPRINTF if (elf_trace) uprintf
89e1743d02SSøren Schmidt 
90e1743d02SSøren Schmidt static struct sysentvec elf_freebsd_sysvec = {
91e1743d02SSøren Schmidt         SYS_MAXSYSCALL,
92e1743d02SSøren Schmidt         sysent,
93e1743d02SSøren Schmidt         0,
94e1743d02SSøren Schmidt         0,
95e1743d02SSøren Schmidt         0,
96e1743d02SSøren Schmidt         0,
97e1743d02SSøren Schmidt         0,
98288078beSEivind Eklund         0,
99e1743d02SSøren Schmidt         elf_freebsd_fixup,
100e1743d02SSøren Schmidt         sendsig,
101e1743d02SSøren Schmidt         sigcode,
102e1743d02SSøren Schmidt         &szsigcode,
103e1743d02SSøren Schmidt         0,
1046ead3eddSJohn Dyson 	"FreeBSD ELF"
105e1743d02SSøren Schmidt };
106e1743d02SSøren Schmidt 
107ecbb00a2SDoug Rabson static Elf_Brandinfo freebsd_brand_info = {
108ea5a2b2eSSøren Schmidt 						"FreeBSD",
109ea5a2b2eSSøren Schmidt 						"",
110e1743d02SSøren Schmidt 						"/usr/libexec/ld-elf.so.1",
111ea5a2b2eSSøren Schmidt 						&elf_freebsd_sysvec
112e1743d02SSøren Schmidt 					  };
113ecbb00a2SDoug Rabson static Elf_Brandinfo *elf_brand_list[MAX_BRANDS] = {
114ea5a2b2eSSøren Schmidt 							&freebsd_brand_info,
115e1743d02SSøren Schmidt 							NULL, NULL, NULL,
116e1743d02SSøren Schmidt 							NULL, NULL, NULL, NULL
117e1743d02SSøren Schmidt 						    };
118e1743d02SSøren Schmidt 
119e1743d02SSøren Schmidt int
120ecbb00a2SDoug Rabson elf_insert_brand_entry(Elf_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] == NULL) {
126ea5a2b2eSSøren Schmidt 			elf_brand_list[i] = entry;
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 int
136ecbb00a2SDoug Rabson elf_remove_brand_entry(Elf_Brandinfo *entry)
137e1743d02SSøren Schmidt {
138e1743d02SSøren Schmidt 	int i;
139e1743d02SSøren Schmidt 
140ea5a2b2eSSøren Schmidt 	for (i=1; i<MAX_BRANDS; i++) {
141ea5a2b2eSSøren Schmidt 		if (elf_brand_list[i] == entry) {
142ea5a2b2eSSøren Schmidt 			elf_brand_list[i] = NULL;
143e1743d02SSøren Schmidt 			break;
144e1743d02SSøren Schmidt 		}
145e1743d02SSøren Schmidt 	}
146ea5a2b2eSSøren Schmidt 	if (i == MAX_BRANDS)
147e1743d02SSøren Schmidt 		return -1;
148e1743d02SSøren Schmidt 	return 0;
149e1743d02SSøren Schmidt }
150e1743d02SSøren Schmidt 
151e1743d02SSøren Schmidt static int
152ecbb00a2SDoug Rabson elf_check_header(const Elf_Ehdr *hdr, int type)
153e1743d02SSøren Schmidt {
154e1743d02SSøren Schmidt 	if (!(hdr->e_ident[EI_MAG0] == ELFMAG0 &&
155e1743d02SSøren Schmidt 	      hdr->e_ident[EI_MAG1] == ELFMAG1 &&
156e1743d02SSøren Schmidt 	      hdr->e_ident[EI_MAG2] == ELFMAG2 &&
157e1743d02SSøren Schmidt 	      hdr->e_ident[EI_MAG3] == ELFMAG3))
158e1743d02SSøren Schmidt 		return ENOEXEC;
159e1743d02SSøren Schmidt 
160ecbb00a2SDoug Rabson #ifdef __i396__
161e1743d02SSøren Schmidt 	if (hdr->e_machine != EM_386 && hdr->e_machine != EM_486)
162ecbb00a2SDoug Rabson #endif
163ecbb00a2SDoug Rabson #ifdef __alpha__
164ecbb00a2SDoug Rabson 	if (hdr->e_machine != EM_ALPHA)
165ecbb00a2SDoug Rabson #endif
166e1743d02SSøren Schmidt 		return ENOEXEC;
167e1743d02SSøren Schmidt 
168ecbb00a2SDoug Rabson 
169e1743d02SSøren Schmidt 	if (hdr->e_type != type)
170e1743d02SSøren Schmidt 		return ENOEXEC;
171e1743d02SSøren Schmidt 
172e1743d02SSøren Schmidt 	return 0;
173e1743d02SSøren Schmidt }
174e1743d02SSøren Schmidt 
175e1743d02SSøren Schmidt static int
176e1743d02SSø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)
177e1743d02SSøren Schmidt {
178e1743d02SSøren Schmidt 	size_t map_len;
179e1743d02SSøren Schmidt 	vm_offset_t map_addr;
180e1743d02SSøren Schmidt 	int error;
181e1743d02SSøren Schmidt 	unsigned char *data_buf = 0;
182e1743d02SSøren Schmidt 	size_t copy_len;
183e1743d02SSøren Schmidt 
184e1743d02SSøren Schmidt 	map_addr = trunc_page(vmaddr);
185e1743d02SSøren Schmidt 
186e1743d02SSøren Schmidt 	if (memsz > filsz)
187e1743d02SSøren Schmidt 		map_len = trunc_page(offset+filsz) - trunc_page(offset);
188e1743d02SSøren Schmidt 	else
189e1743d02SSøren Schmidt 		map_len = round_page(offset+filsz) - trunc_page(offset);
190e1743d02SSøren Schmidt 
191e1743d02SSøren Schmidt 	if (error = vm_mmap (&vmspace->vm_map,
192e1743d02SSøren Schmidt 			     &map_addr,
193e1743d02SSøren Schmidt 			     map_len,
194e1743d02SSøren Schmidt 			     prot,
195e1743d02SSøren Schmidt 			     VM_PROT_ALL,
19671d7d1b1SPeter Wemm 			     MAP_PRIVATE | MAP_FIXED,
197e1743d02SSøren Schmidt 			     (caddr_t)vp,
198e1743d02SSøren Schmidt 			     trunc_page(offset)))
199e1743d02SSøren Schmidt 		return error;
200e1743d02SSøren Schmidt 
201e1743d02SSøren Schmidt 	if (memsz == filsz)
202e1743d02SSøren Schmidt 		return 0;
203e1743d02SSøren Schmidt 
204e1743d02SSøren Schmidt 	/*
205e1743d02SSøren Schmidt 	 * We have to map the remaining bit of the file into the kernel's
206e1743d02SSøren Schmidt 	 * memory map, allocate some anonymous memory, and copy that last
207e1743d02SSøren Schmidt 	 * bit into it. The remaining space should be .bss...
208e1743d02SSøren Schmidt 	 */
209e1743d02SSøren Schmidt 	copy_len = (offset + filsz) - trunc_page(offset + filsz);
210e1743d02SSøren Schmidt 	map_addr = trunc_page(vmaddr + filsz);
211250c11f9SPeter Wemm 	map_len = round_page(vmaddr + memsz) - map_addr;
212e1743d02SSøren Schmidt 
2138191d577SPeter Wemm         if (map_len != 0) {
214e1743d02SSøren Schmidt 		if (error = vm_map_find(&vmspace->vm_map, NULL, 0,
215e1743d02SSøren Schmidt 					&map_addr, map_len, FALSE,
216e1743d02SSøren Schmidt 					VM_PROT_ALL, VM_PROT_ALL,0))
217e1743d02SSøren Schmidt 			return error;
2188191d577SPeter Wemm 	}
219e1743d02SSøren Schmidt 
220c8a79999SPeter Wemm 	if (error = vm_mmap(exec_map,
221e1743d02SSøren Schmidt 			    (vm_offset_t *)&data_buf,
222e1743d02SSøren Schmidt 			    PAGE_SIZE,
223e1743d02SSøren Schmidt 			    VM_PROT_READ,
224e1743d02SSøren Schmidt 			    VM_PROT_READ,
22571d7d1b1SPeter Wemm 			    0,
226e1743d02SSøren Schmidt 			    (caddr_t)vp,
227e1743d02SSøren Schmidt 			    trunc_page(offset + filsz)))
228e1743d02SSøren Schmidt 		return error;
229e1743d02SSøren Schmidt 
230e1743d02SSøren Schmidt 	error = copyout(data_buf, (caddr_t)map_addr, copy_len);
231e1743d02SSøren Schmidt 
232c8a79999SPeter Wemm         vm_map_remove(exec_map, (vm_offset_t)data_buf,
233e1743d02SSøren Schmidt 		      (vm_offset_t)data_buf + PAGE_SIZE);
234e1743d02SSøren Schmidt 
235e1743d02SSøren Schmidt 	/*
2368191d577SPeter Wemm 	 * set it to the specified protection
237e1743d02SSøren Schmidt 	 */
2388191d577SPeter Wemm 	vm_map_protect(&vmspace->vm_map, map_addr, map_addr + map_len,  prot,
2398191d577SPeter Wemm 		       FALSE);
2408191d577SPeter Wemm 
241e1743d02SSøren Schmidt 	UPRINTF("bss size %d (%x)\n", map_len-copy_len, map_len-copy_len);
242e1743d02SSøren Schmidt 	return error;
243e1743d02SSøren Schmidt }
244e1743d02SSøren Schmidt 
245e1743d02SSøren Schmidt static int
246e1743d02SSøren Schmidt elf_load_file(struct proc *p, char *file, u_long *addr, u_long *entry)
247e1743d02SSøren Schmidt {
248ecbb00a2SDoug Rabson 	Elf_Ehdr *hdr = NULL;
249ecbb00a2SDoug Rabson 	Elf_Phdr *phdr = NULL;
250e1743d02SSøren Schmidt 	struct nameidata nd;
251e1743d02SSøren Schmidt 	struct vmspace *vmspace = p->p_vmspace;
252c8a79999SPeter Wemm 	struct vattr attr;
253c8a79999SPeter Wemm 	struct image_params image_params, *imgp;
254e1743d02SSøren Schmidt 	vm_prot_t prot = 0;
255e1743d02SSøren Schmidt 	unsigned long text_size = 0, data_size = 0;
256e1743d02SSøren Schmidt 	unsigned long text_addr = 0, data_addr = 0;
257e1743d02SSøren Schmidt 	int header_size = 0;
258e1743d02SSøren Schmidt         int error, i;
259e1743d02SSøren Schmidt 
260c8a79999SPeter Wemm 	imgp = &image_params;
261c8a79999SPeter Wemm 	/*
262c8a79999SPeter Wemm 	 * Initialize part of the common data
263c8a79999SPeter Wemm 	 */
264c8a79999SPeter Wemm 	imgp->proc = p;
265c8a79999SPeter Wemm 	imgp->uap = NULL;
266c8a79999SPeter Wemm 	imgp->attr = &attr;
267c8a79999SPeter Wemm 	imgp->firstpage = NULL;
268c8a79999SPeter Wemm 	imgp->image_header = (char *)kmem_alloc_wait(exec_map, PAGE_SIZE);
269c8a79999SPeter Wemm 
270c8a79999SPeter Wemm 	if (imgp->image_header == NULL) {
271c8a79999SPeter Wemm 		nd.ni_vp = NULL;
272c8a79999SPeter Wemm 		error = ENOMEM;
273c8a79999SPeter Wemm 		goto fail;
274c8a79999SPeter Wemm 	}
275c8a79999SPeter Wemm 
276e1743d02SSøren Schmidt         NDINIT(&nd, LOOKUP, LOCKLEAF|FOLLOW, UIO_SYSSPACE, file, p);
277e1743d02SSøren Schmidt 
2781560a9d5SPeter Wemm 	if (error = namei(&nd)) {
2791560a9d5SPeter Wemm 		nd.ni_vp = NULL;
280e1743d02SSøren Schmidt 		goto fail;
281e1743d02SSøren Schmidt 	}
282e1743d02SSøren Schmidt 
283c8a79999SPeter Wemm 	imgp->vp = nd.ni_vp;
284c8a79999SPeter Wemm 
285e1743d02SSøren Schmidt 	/*
286e1743d02SSøren Schmidt 	 * Check permissions, modes, uid, etc on the file, and "open" it.
287e1743d02SSøren Schmidt 	 */
288c8a79999SPeter Wemm 	error = exec_check_permissions(imgp);
289c8a79999SPeter Wemm 	if (error) {
290996c772fSJohn Dyson 		VOP_UNLOCK(nd.ni_vp, 0, p);
291c8a79999SPeter Wemm 		goto fail;
292c8a79999SPeter Wemm 	}
293e1743d02SSøren Schmidt 
294c8a79999SPeter Wemm 	error = exec_map_first_page(imgp);
295c8a79999SPeter Wemm 	VOP_UNLOCK(nd.ni_vp, 0, p);
296e1743d02SSøren Schmidt 	if (error)
297e1743d02SSøren Schmidt                 goto fail;
298e1743d02SSøren Schmidt 
299ecbb00a2SDoug Rabson 	hdr = (Elf_Ehdr *)imgp->image_header;
300e1743d02SSøren Schmidt 	if (error = elf_check_header(hdr, ET_DYN))
301e1743d02SSøren Schmidt 		goto fail;
302e1743d02SSøren Schmidt 
303e1743d02SSøren Schmidt 	/*
304e1743d02SSøren Schmidt 	 * ouch, need to bounds check in case user gives us a corrupted
305e1743d02SSøren Schmidt 	 * file with an insane header size
306e1743d02SSøren Schmidt 	 */
307e1743d02SSøren Schmidt 	if (hdr->e_phnum > MAX_PHDR) {	/* XXX: ever more than this? */
308e1743d02SSøren Schmidt 		error = ENOEXEC;
309e1743d02SSøren Schmidt 		goto fail;
310e1743d02SSøren Schmidt 	}
311e1743d02SSøren Schmidt 
312e1743d02SSøren Schmidt 	header_size = hdr->e_phentsize * hdr->e_phnum;
313e1743d02SSøren Schmidt 
314c8a79999SPeter Wemm 	/* Only support headers that fit within first page for now */
315c8a79999SPeter Wemm 	if (header_size + hdr->e_phoff > PAGE_SIZE) {
316c8a79999SPeter Wemm 		error = ENOEXEC;
317e1743d02SSøren Schmidt 		goto fail;
318c8a79999SPeter Wemm 	}
319c8a79999SPeter Wemm 
320ecbb00a2SDoug Rabson 	phdr = (Elf_Phdr *)(imgp->image_header + hdr->e_phoff);
321e1743d02SSøren Schmidt 
322e1743d02SSøren Schmidt 	for (i = 0; i < hdr->e_phnum; i++) {
323e1743d02SSøren Schmidt 		switch(phdr[i].p_type) {
324e1743d02SSøren Schmidt 
325e1743d02SSøren Schmidt 	   	case PT_NULL:	/* NULL section */
326e1743d02SSøren Schmidt 	    		UPRINTF ("ELF(file) PT_NULL section\n");
327e1743d02SSøren Schmidt 			break;
328e1743d02SSøren Schmidt 		case PT_LOAD:	/* Loadable segment */
329e1743d02SSøren Schmidt 		{
330e1743d02SSøren Schmidt 	    		UPRINTF ("ELF(file) PT_LOAD section ");
331e1743d02SSøren Schmidt 			if (phdr[i].p_flags & PF_X)
332e1743d02SSøren Schmidt   				prot |= VM_PROT_EXECUTE;
333e1743d02SSøren Schmidt 			if (phdr[i].p_flags & PF_W)
334e1743d02SSøren Schmidt   				prot |= VM_PROT_WRITE;
335e1743d02SSøren Schmidt 			if (phdr[i].p_flags & PF_R)
336e1743d02SSøren Schmidt   				prot |= VM_PROT_READ;
337e1743d02SSøren Schmidt 
338e1743d02SSøren Schmidt 			if (error = elf_load_section(vmspace, nd.ni_vp,
339e1743d02SSøren Schmidt   						     phdr[i].p_offset,
340e1743d02SSøren Schmidt   						     (caddr_t)phdr[i].p_vaddr +
341e1743d02SSøren Schmidt 							(*addr),
342e1743d02SSøren Schmidt   						     phdr[i].p_memsz,
343e1743d02SSøren Schmidt   						     phdr[i].p_filesz, prot))
344e1743d02SSøren Schmidt 				goto fail;
345e1743d02SSøren Schmidt 
346e1743d02SSøren Schmidt 			/*
347e1743d02SSøren Schmidt 			 * Is this .text or .data ??
348e1743d02SSøren Schmidt 			 *
349e1743d02SSøren Schmidt 			 * We only handle one each of those yet XXX
350e1743d02SSøren Schmidt 			 */
351e1743d02SSøren Schmidt 			if (hdr->e_entry >= phdr[i].p_vaddr &&
352e1743d02SSøren Schmidt 			hdr->e_entry <(phdr[i].p_vaddr+phdr[i].p_memsz)) {
353e1743d02SSøren Schmidt   				text_addr = trunc_page(phdr[i].p_vaddr+(*addr));
3548191d577SPeter Wemm   				text_size = round_page(phdr[i].p_memsz +
3558191d577SPeter Wemm 						       phdr[i].p_vaddr -
3568191d577SPeter Wemm 						       trunc_page(phdr[i].p_vaddr));
357e1743d02SSøren Schmidt 				*entry=(unsigned long)hdr->e_entry+(*addr);
358e1743d02SSøren Schmidt 	    			UPRINTF(".text <%08x,%08x> entry=%08x\n",
359e1743d02SSøren Schmidt 					text_addr, text_size, *entry);
360e1743d02SSøren Schmidt 			} else {
361e1743d02SSøren Schmidt   				data_addr = trunc_page(phdr[i].p_vaddr+(*addr));
3628191d577SPeter Wemm   				data_size = round_page(phdr[i].p_memsz +
3638191d577SPeter Wemm 						       phdr[i].p_vaddr -
3648191d577SPeter Wemm 						       trunc_page(phdr[i].p_vaddr));
365e1743d02SSøren Schmidt 	    			UPRINTF(".data <%08x,%08x>\n",
366e1743d02SSøren Schmidt 					data_addr, data_size);
367e1743d02SSøren Schmidt 			}
368e1743d02SSøren Schmidt 		}
369e1743d02SSøren Schmidt 		break;
370e1743d02SSøren Schmidt 
371e1743d02SSøren Schmidt 	   	case PT_DYNAMIC:/* Dynamic link information */
372e1743d02SSøren Schmidt 	    		UPRINTF ("ELF(file) PT_DYNAMIC section\n");
373e1743d02SSøren Schmidt 			break;
374e1743d02SSøren Schmidt 	  	case PT_INTERP:	/* Path to interpreter */
375e1743d02SSøren Schmidt 	    		UPRINTF ("ELF(file) PT_INTERP section\n");
376e1743d02SSøren Schmidt 			break;
377e1743d02SSøren Schmidt 	  	case PT_NOTE:	/* Note section */
378e1743d02SSøren Schmidt 	    		UPRINTF ("ELF(file) PT_NOTE section\n");
379e1743d02SSøren Schmidt 			break;
380e1743d02SSøren Schmidt 	  	case PT_SHLIB:	/* Shared lib section  */
381e1743d02SSøren Schmidt 	    		UPRINTF ("ELF(file) PT_SHLIB section\n");
382e1743d02SSøren Schmidt 			break;
383e1743d02SSøren Schmidt 		case PT_PHDR: 	/* Program header table info */
384e1743d02SSøren Schmidt 	    		UPRINTF ("ELF(file) PT_PHDR section\n");
385e1743d02SSøren Schmidt 			break;
386e1743d02SSøren Schmidt 		default:
387e1743d02SSøren Schmidt 	    		UPRINTF ("ELF(file) %d section ??\n", phdr[i].p_type );
388e1743d02SSøren Schmidt 		}
389e1743d02SSøren Schmidt 	}
390e1743d02SSøren Schmidt 
391e1743d02SSøren Schmidt fail:
392c8a79999SPeter Wemm 	if (imgp->firstpage)
393c8a79999SPeter Wemm 		exec_unmap_first_page(imgp);
394c8a79999SPeter Wemm 	if (imgp->image_header)
395c8a79999SPeter Wemm 		kmem_free_wakeup(exec_map, (vm_offset_t)imgp->image_header,
396c8a79999SPeter Wemm 			PAGE_SIZE);
3971560a9d5SPeter Wemm 	if (nd.ni_vp)
3981560a9d5SPeter Wemm 		vrele(nd.ni_vp);
399e1743d02SSøren Schmidt 
400e1743d02SSøren Schmidt 	return error;
401e1743d02SSøren Schmidt }
402e1743d02SSøren Schmidt 
403303b270bSEivind Eklund static int
404e1743d02SSøren Schmidt exec_elf_imgact(struct image_params *imgp)
405e1743d02SSøren Schmidt {
406ecbb00a2SDoug Rabson 	const Elf_Ehdr *hdr = (const Elf_Ehdr *) imgp->image_header;
407ecbb00a2SDoug Rabson 	const Elf_Phdr *phdr, *mapped_phdr = NULL;
408ecbb00a2SDoug Rabson 	Elf_Auxargs *elf_auxargs = NULL;
4095856e12eSJohn Dyson 	struct vmspace *vmspace;
410e1743d02SSøren Schmidt 	vm_prot_t prot = 0;
411e1743d02SSøren Schmidt 	u_long text_size = 0, data_size = 0;
412e1743d02SSøren Schmidt 	u_long text_addr = 0, data_addr = 0;
413e1743d02SSøren Schmidt 	u_long addr, entry = 0, proghdr = 0;
414c8a79999SPeter Wemm 	int error, i, header_size = 0;
415c8a79999SPeter Wemm 	const char *interp = NULL;
416ea5a2b2eSSøren Schmidt 	char *brand = NULL;
417ea5a2b2eSSøren Schmidt 	char path[MAXPATHLEN];
418e1743d02SSøren Schmidt 
419e1743d02SSøren Schmidt 	/*
420e1743d02SSøren Schmidt 	 * Do we have a valid ELF header ?
421e1743d02SSøren Schmidt 	 */
422e1743d02SSøren Schmidt 	if (elf_check_header(hdr, ET_EXEC))
423e1743d02SSøren Schmidt 		return -1;
424e1743d02SSøren Schmidt 
425e1743d02SSøren Schmidt 	/*
426e1743d02SSøren Schmidt 	 * From here on down, we return an errno, not -1, as we've
427e1743d02SSøren Schmidt 	 * detected an ELF file.
428e1743d02SSøren Schmidt 	 */
429e1743d02SSøren Schmidt 
430e1743d02SSøren Schmidt 	/*
431e1743d02SSøren Schmidt 	 * ouch, need to bounds check in case user gives us a corrupted
432e1743d02SSøren Schmidt 	 * file with an insane header size
433e1743d02SSøren Schmidt 	 */
434e1743d02SSøren Schmidt 	if (hdr->e_phnum > MAX_PHDR) {	/* XXX: ever more than this? */
435e1743d02SSøren Schmidt 		return ENOEXEC;
436e1743d02SSøren Schmidt 	}
437e1743d02SSøren Schmidt 
438e1743d02SSøren Schmidt 	header_size = hdr->e_phentsize * hdr->e_phnum;
439e1743d02SSøren Schmidt 
440e1743d02SSøren Schmidt 	if ((hdr->e_phoff > PAGE_SIZE) ||
441e1743d02SSøren Schmidt 	    (hdr->e_phoff + header_size) > PAGE_SIZE) {
442c8a79999SPeter Wemm 		/* Only support headers in first page for now */
443c8a79999SPeter Wemm 		return ENOEXEC;
444e1743d02SSøren Schmidt 	} else {
445ecbb00a2SDoug Rabson 		phdr = (const Elf_Phdr*)
446e0c95ed9SBruce Evans 		       ((const char *)imgp->image_header + hdr->e_phoff);
447e1743d02SSøren Schmidt 	}
448e1743d02SSøren Schmidt 
449e1743d02SSøren Schmidt 	/*
450e1743d02SSøren Schmidt 	 * From this point on, we may have resources that need to be freed.
451e1743d02SSøren Schmidt 	 */
452e1743d02SSøren Schmidt 	if (error = exec_extract_strings(imgp))
453e1743d02SSøren Schmidt 		goto fail;
454e1743d02SSøren Schmidt 
455e1743d02SSøren Schmidt 	exec_new_vmspace(imgp);
456e1743d02SSøren Schmidt 
4575856e12eSJohn Dyson 	vmspace = imgp->proc->p_vmspace;
4585856e12eSJohn Dyson 
459e1743d02SSøren Schmidt 	for (i = 0; i < hdr->e_phnum; i++) {
460e1743d02SSøren Schmidt 		switch(phdr[i].p_type) {
461e1743d02SSøren Schmidt 
462e1743d02SSøren Schmidt 	   	case PT_NULL:	/* NULL section */
463e1743d02SSøren Schmidt 	    		UPRINTF ("ELF PT_NULL section\n");
464e1743d02SSøren Schmidt 			break;
465e1743d02SSøren Schmidt 		case PT_LOAD:	/* Loadable segment */
466e1743d02SSøren Schmidt 		{
467e1743d02SSøren Schmidt 	    		UPRINTF ("ELF PT_LOAD section ");
468e1743d02SSøren Schmidt 			if (phdr[i].p_flags & PF_X)
469e1743d02SSøren Schmidt   				prot |= VM_PROT_EXECUTE;
470e1743d02SSøren Schmidt 			if (phdr[i].p_flags & PF_W)
471e1743d02SSøren Schmidt   				prot |= VM_PROT_WRITE;
472e1743d02SSøren Schmidt 			if (phdr[i].p_flags & PF_R)
473e1743d02SSøren Schmidt   				prot |= VM_PROT_READ;
474e1743d02SSøren Schmidt 
475e1743d02SSøren Schmidt 			if (error = elf_load_section(vmspace, imgp->vp,
476e1743d02SSøren Schmidt   						     phdr[i].p_offset,
477e1743d02SSøren Schmidt   						     (caddr_t)phdr[i].p_vaddr,
478e1743d02SSøren Schmidt   						     phdr[i].p_memsz,
479e1743d02SSøren Schmidt   						     phdr[i].p_filesz, prot))
480e1743d02SSøren Schmidt   				goto fail;
481e1743d02SSøren Schmidt 
482e1743d02SSøren Schmidt 			/*
483e1743d02SSøren Schmidt 			 * Is this .text or .data ??
484e1743d02SSøren Schmidt 			 *
485e1743d02SSøren Schmidt 			 * We only handle one each of those yet XXX
486e1743d02SSøren Schmidt 			 */
487e1743d02SSøren Schmidt 			if (hdr->e_entry >= phdr[i].p_vaddr &&
488e1743d02SSøren Schmidt 			hdr->e_entry <(phdr[i].p_vaddr+phdr[i].p_memsz)) {
489e1743d02SSøren Schmidt   				text_addr = trunc_page(phdr[i].p_vaddr);
4908191d577SPeter Wemm   				text_size = round_page(phdr[i].p_memsz +
4918191d577SPeter Wemm 						       phdr[i].p_vaddr -
4928191d577SPeter Wemm 						       text_addr);
493e1743d02SSøren Schmidt 				entry = (u_long)hdr->e_entry;
494e1743d02SSøren Schmidt 	    			UPRINTF(".text <%08x,%08x> entry=%08x\n",
495e1743d02SSøren Schmidt 					text_addr, text_size, entry);
496e1743d02SSøren Schmidt 			} else {
497e1743d02SSøren Schmidt   				data_addr = trunc_page(phdr[i].p_vaddr);
4988191d577SPeter Wemm   				data_size = round_page(phdr[i].p_memsz +
4998191d577SPeter Wemm 						       phdr[i].p_vaddr -
5008191d577SPeter Wemm 						       data_addr);
501e1743d02SSøren Schmidt 	    			UPRINTF(".data <%08x,%08x>\n",
502e1743d02SSøren Schmidt 					data_addr, data_size);
503e1743d02SSøren Schmidt 			}
504e1743d02SSøren Schmidt 		}
505e1743d02SSøren Schmidt 		break;
506e1743d02SSøren Schmidt 
507e1743d02SSøren Schmidt 	   	case PT_DYNAMIC:/* Dynamic link information */
508e1743d02SSøren Schmidt 	    		UPRINTF ("ELF PT_DYNAMIC section ??\n");
509e1743d02SSøren Schmidt 			break;
510e1743d02SSøren Schmidt 	  	case PT_INTERP:	/* Path to interpreter */
511e1743d02SSøren Schmidt 	    		UPRINTF ("ELF PT_INTERP section ");
512c8a79999SPeter Wemm 			if (phdr[i].p_filesz > MAXPATHLEN ||
513c8a79999SPeter Wemm 			    phdr[i].p_offset + phdr[i].p_filesz > PAGE_SIZE) {
514e1743d02SSøren Schmidt 				error = ENOEXEC;
515e1743d02SSøren Schmidt 				goto fail;
516e1743d02SSøren Schmidt 			}
517c8a79999SPeter Wemm 			interp = imgp->image_header + phdr[i].p_offset;
518e1743d02SSøren Schmidt 			UPRINTF("<%s>\n", interp);
519e1743d02SSøren Schmidt 			break;
520e1743d02SSøren Schmidt 	  	case PT_NOTE:	/* Note section */
521e1743d02SSøren Schmidt 	    		UPRINTF ("ELF PT_NOTE section\n");
522e1743d02SSøren Schmidt 			break;
523e1743d02SSøren Schmidt 	  	case PT_SHLIB:	/* Shared lib section  */
524e1743d02SSøren Schmidt 	    		UPRINTF ("ELF PT_SHLIB section\n");
525e1743d02SSøren Schmidt 			break;
526e1743d02SSøren Schmidt 		case PT_PHDR: 	/* Program header table info */
527e1743d02SSøren Schmidt 	    		UPRINTF ("ELF PT_PHDR section <%x>\n", phdr[i].p_vaddr);
528e1743d02SSøren Schmidt 			proghdr = phdr[i].p_vaddr;
529e1743d02SSøren Schmidt 			break;
530e1743d02SSøren Schmidt 		default:
531e1743d02SSøren Schmidt 	    		UPRINTF ("ELF %d section ??\n", phdr[i].p_type);
532e1743d02SSøren Schmidt 		}
533e1743d02SSøren Schmidt 	}
534e1743d02SSøren Schmidt 
535e1743d02SSøren Schmidt 	vmspace->vm_tsize = text_size >> PAGE_SHIFT;
536e1743d02SSøren Schmidt 	vmspace->vm_taddr = (caddr_t)text_addr;
537e1743d02SSøren Schmidt 	vmspace->vm_dsize = data_size >> PAGE_SHIFT;
538e1743d02SSøren Schmidt 	vmspace->vm_daddr = (caddr_t)data_addr;
539e1743d02SSøren Schmidt 
540ecbb00a2SDoug Rabson 	addr = 2L*MAXDSIZ; /* May depend on OS type XXX */
541e1743d02SSøren Schmidt 
542ea5a2b2eSSøren Schmidt 	imgp->entry_addr = entry;
543ea5a2b2eSSøren Schmidt 
544e1743d02SSøren Schmidt 	/*
545ea5a2b2eSSøren Schmidt 	 * So which kind (brand) of ELF binary do we have at hand
546ea5a2b2eSSøren Schmidt 	 * FreeBSD, Linux, SVR4 or something else ??
547ea5a2b2eSSøren Schmidt 	 * If its has a interpreter section try that first
548e1743d02SSøren Schmidt 	 */
549ea5a2b2eSSøren Schmidt         if (interp) {
550ea5a2b2eSSøren Schmidt                 for (i=0; i<MAX_BRANDS; i++) {
551ea5a2b2eSSøren Schmidt                         if (elf_brand_list[i] != NULL) {
552ea5a2b2eSSøren Schmidt                                 if (!strcmp(interp, elf_brand_list[i]->interp_path)) {
553e1743d02SSøren Schmidt                                         imgp->proc->p_sysent =
554ea5a2b2eSSøren Schmidt                                                 elf_brand_list[i]->sysvec;
555ea5a2b2eSSøren Schmidt                                         strcpy(path, elf_brand_list[i]->emul_path);
556ea5a2b2eSSøren Schmidt                                         strcat(path, elf_brand_list[i]->interp_path);
557e1743d02SSø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);
560e1743d02SSøren Schmidt                                         break;
561e1743d02SSøren Schmidt                                 }
562e1743d02SSøren Schmidt                         }
563e1743d02SSøren Schmidt                 }
564ea5a2b2eSSøren Schmidt         }
565ea5a2b2eSSøren Schmidt 
566ea5a2b2eSSøren Schmidt 	/*
567ea5a2b2eSSøren Schmidt 	 * If there is no interpreter, or recognition of it
568ea5a2b2eSSøren Schmidt 	 * failed, se if the binary is branded.
569ea5a2b2eSSøren Schmidt 	 */
570ea5a2b2eSSøren Schmidt 	if (!interp || i == MAX_BRANDS) {
571ea5a2b2eSSøren Schmidt 		brand = (char *)&(hdr->e_ident[EI_BRAND]);
572ea5a2b2eSSøren Schmidt 		for (i=0; i<MAX_BRANDS; i++) {
573ea5a2b2eSSøren Schmidt 			if (elf_brand_list[i] != NULL) {
574ea5a2b2eSSøren Schmidt 				if (!strcmp(brand, elf_brand_list[i]->brand)) {
575ea5a2b2eSSøren Schmidt 					imgp->proc->p_sysent = elf_brand_list[i]->sysvec;
576ea5a2b2eSSøren Schmidt 					if (interp) {
577ea5a2b2eSSøren Schmidt 						strcpy(path, elf_brand_list[i]->emul_path);
578ea5a2b2eSSøren Schmidt 						strcat(path, elf_brand_list[i]->interp_path);
579ea5a2b2eSSøren Schmidt 						UPRINTF("interpreter=<%s> %s\n",
580ea5a2b2eSSøren Schmidt 						elf_brand_list[i]->interp_path,
581ea5a2b2eSSøren Schmidt 						elf_brand_list[i]->emul_path);
582ea5a2b2eSSøren Schmidt 					}
583d672246bSSøren Schmidt 					break;
584ea5a2b2eSSøren Schmidt 				}
585ea5a2b2eSSøren Schmidt 			}
586ea5a2b2eSSøren Schmidt 		}
587ea5a2b2eSSøren Schmidt 	}
588ea5a2b2eSSøren Schmidt 	if (i == MAX_BRANDS) {
589ea5a2b2eSSøren Schmidt 		uprintf("ELF binary type not known\n");
590ecbb00a2SDoug Rabson #ifdef __alpha__
591ecbb00a2SDoug Rabson 		uprintf("assuming FreeBSD\n");
592ecbb00a2SDoug Rabson 		i = 0;
593ecbb00a2SDoug Rabson #else
594e1743d02SSøren Schmidt 		error = ENOEXEC;
595e1743d02SSøren Schmidt 		goto fail;
596ecbb00a2SDoug Rabson #endif
597e1743d02SSøren Schmidt 	}
598ea5a2b2eSSøren Schmidt 	if (interp) {
599e1743d02SSøren Schmidt                 if (error = elf_load_file(imgp->proc,
600e1743d02SSøren Schmidt                                           path,
601e1743d02SSøren Schmidt                                           &addr,        /* XXX */
602e1743d02SSøren Schmidt                                           &imgp->entry_addr)) {
603e1743d02SSøren Schmidt                         uprintf("ELF interpreter %s not found\n", path);
604e1743d02SSøren Schmidt                         goto fail;
605e1743d02SSøren Schmidt                 }
606e1743d02SSøren Schmidt 	}
607ea5a2b2eSSøren Schmidt 
608717fb679SSøren Schmidt 	UPRINTF("Executing %s binary\n", elf_brand_list[i]->brand);
609e1743d02SSøren Schmidt 
610e1743d02SSøren Schmidt 	/*
611e1743d02SSøren Schmidt 	 * Construct auxargs table (used by the fixup routine)
612e1743d02SSøren Schmidt 	 */
613ecbb00a2SDoug Rabson 	elf_auxargs = malloc(sizeof(Elf_Auxargs), M_TEMP, M_WAITOK);
614e1743d02SSøren Schmidt 	elf_auxargs->execfd = -1;
615e1743d02SSøren Schmidt 	elf_auxargs->phdr = proghdr;
616e1743d02SSøren Schmidt 	elf_auxargs->phent = hdr->e_phentsize;
617e1743d02SSøren Schmidt 	elf_auxargs->phnum = hdr->e_phnum;
618e1743d02SSøren Schmidt 	elf_auxargs->pagesz = PAGE_SIZE;
619e1743d02SSøren Schmidt 	elf_auxargs->base = addr;
620e1743d02SSøren Schmidt 	elf_auxargs->flags = 0;
621e1743d02SSøren Schmidt 	elf_auxargs->entry = entry;
622e1743d02SSøren Schmidt 	elf_auxargs->trace = elf_trace;
623e1743d02SSøren Schmidt 
624e1743d02SSøren Schmidt 	imgp->auxargs = elf_auxargs;
625e1743d02SSøren Schmidt 	imgp->interpreted = 0;
626e1743d02SSøren Schmidt 
627e1743d02SSøren Schmidt 	/* don't allow modifying the file while we run it */
628e1743d02SSøren Schmidt 	imgp->vp->v_flag |= VTEXT;
629e1743d02SSøren Schmidt 
630e1743d02SSøren Schmidt fail:
631e1743d02SSøren Schmidt 	return error;
632e1743d02SSøren Schmidt }
633e1743d02SSøren Schmidt 
634e1743d02SSøren Schmidt static int
635ecbb00a2SDoug Rabson elf_freebsd_fixup(long **stack_base, struct image_params *imgp)
636e1743d02SSøren Schmidt {
637ecbb00a2SDoug Rabson 	Elf_Auxargs *args = (Elf_Auxargs *)imgp->auxargs;
638ecbb00a2SDoug Rabson 	long *pos;
639e1743d02SSøren Schmidt 
640e1743d02SSøren Schmidt 	pos = *stack_base + (imgp->argc + imgp->envc + 2);
641e1743d02SSøren Schmidt 
642e1743d02SSøren Schmidt 	if (args->trace) {
643e1743d02SSøren Schmidt 		AUXARGS_ENTRY(pos, AT_DEBUG, 1);
644e1743d02SSøren Schmidt 	}
645e1743d02SSøren Schmidt 	if (args->execfd != -1) {
646e1743d02SSøren Schmidt 		AUXARGS_ENTRY(pos, AT_EXECFD, args->execfd);
647e1743d02SSøren Schmidt 	}
648e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_PHDR, args->phdr);
649e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_PHENT, args->phent);
650e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_PHNUM, args->phnum);
651e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_PAGESZ, args->pagesz);
652e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_FLAGS, args->flags);
653e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_ENTRY, args->entry);
654e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_BASE, args->base);
655e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_NULL, 0);
656e1743d02SSøren Schmidt 
657e1743d02SSøren Schmidt 	free(imgp->auxargs, M_TEMP);
658e1743d02SSøren Schmidt 	imgp->auxargs = NULL;
659e1743d02SSøren Schmidt 
660e1743d02SSøren Schmidt 	(*stack_base)--;
661ecbb00a2SDoug Rabson 	**stack_base = (long)imgp->argc;
662e1743d02SSøren Schmidt 	return 0;
663e1743d02SSøren Schmidt }
664e1743d02SSøren Schmidt 
665e1743d02SSøren Schmidt /*
666e1743d02SSøren Schmidt  * Tell kern_execve.c about it, with a little help from the linker.
667e1743d02SSøren Schmidt  * Since `const' objects end up in the text segment, TEXT_SET is the
668e1743d02SSøren Schmidt  * correct directive to use.
669e1743d02SSøren Schmidt  */
670d8a4f230SBruce Evans static const struct execsw elf_execsw = {exec_elf_imgact, "ELF"};
671e1743d02SSøren Schmidt TEXT_SET(execsw_set, elf_execsw);
672e1743d02SSøren Schmidt 
673