xref: /freebsd/sys/kern/imgact_aout.c (revision e5d81ef1b54984374275ca5e414f80689b491f70)
19454b2d8SWarner Losh /*-
2cfefd687SGarrett Wollman  * Copyright (c) 1993, David Greenman
3cfefd687SGarrett Wollman  * All rights reserved.
4cfefd687SGarrett Wollman  *
5cfefd687SGarrett Wollman  * Redistribution and use in source and binary forms, with or without
6cfefd687SGarrett Wollman  * modification, are permitted provided that the following conditions
7cfefd687SGarrett Wollman  * are met:
8cfefd687SGarrett Wollman  * 1. Redistributions of source code must retain the above copyright
9cfefd687SGarrett Wollman  *    notice, this list of conditions and the following disclaimer.
10cfefd687SGarrett Wollman  * 2. Redistributions in binary form must reproduce the above copyright
11cfefd687SGarrett Wollman  *    notice, this list of conditions and the following disclaimer in the
12cfefd687SGarrett Wollman  *    documentation and/or other materials provided with the distribution.
13cfefd687SGarrett Wollman  *
14cfefd687SGarrett Wollman  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15cfefd687SGarrett Wollman  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16cfefd687SGarrett Wollman  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
171984b014SDavid Greenman  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18cfefd687SGarrett Wollman  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19cfefd687SGarrett Wollman  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20cfefd687SGarrett Wollman  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21cfefd687SGarrett Wollman  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22cfefd687SGarrett Wollman  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23cfefd687SGarrett Wollman  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24cfefd687SGarrett Wollman  * SUCH DAMAGE.
25cfefd687SGarrett Wollman  */
26cfefd687SGarrett Wollman 
27677b542eSDavid E. O'Brien #include <sys/cdefs.h>
28677b542eSDavid E. O'Brien __FBSDID("$FreeBSD$");
29677b542eSDavid E. O'Brien 
3026f9a767SRodney W. Grimes #include <sys/param.h>
3126f9a767SRodney W. Grimes #include <sys/exec.h>
3226f9a767SRodney W. Grimes #include <sys/imgact.h>
33bc6d7444SDavid Greenman #include <sys/imgact_aout.h>
3426f9a767SRodney W. Grimes #include <sys/kernel.h>
35fb919e4dSMark Murray #include <sys/lock.h>
36e5d6cd0cSBruce Evans #include <sys/malloc.h>
37fb919e4dSMark Murray #include <sys/mutex.h>
38a794e791SBruce Evans #include <sys/proc.h>
39fb919e4dSMark Murray #include <sys/resourcevar.h>
4022d4b0fbSJohn Polstra #include <sys/signalvar.h>
4122d4b0fbSJohn Polstra #include <sys/syscall.h>
42e5d6cd0cSBruce Evans #include <sys/sysent.h>
43e5d6cd0cSBruce Evans #include <sys/systm.h>
44a794e791SBruce Evans #include <sys/vnode.h>
45fb919e4dSMark Murray 
46710ded3aSPeter Wemm #include <machine/frame.h>
47e5d6cd0cSBruce Evans #include <machine/md_var.h>
48cfefd687SGarrett Wollman 
4926f9a767SRodney W. Grimes #include <vm/vm.h>
50efeaf95aSDavid Greenman #include <vm/pmap.h>
51efeaf95aSDavid Greenman #include <vm/vm_map.h>
521616db3cSJohn Dyson #include <vm/vm_object.h>
53e5d6cd0cSBruce Evans #include <vm/vm_param.h>
54cfefd687SGarrett Wollman 
554d77a549SAlfred Perlstein static int	exec_aout_imgact(struct image_params *imgp);
56f36ba452SJake Burkholder static int	aout_fixup(register_t **stack_base, struct image_params *imgp);
577ee050b7SBruce Evans 
5822d4b0fbSJohn Polstra struct sysentvec aout_sysvec = {
59a8d403e1SKonstantin Belousov 	.sv_size	= SYS_MAXSYSCALL,
60a8d403e1SKonstantin Belousov 	.sv_table	= sysent,
61a8d403e1SKonstantin Belousov 	.sv_mask	= 0,
62a8d403e1SKonstantin Belousov 	.sv_sigsize	= 0,
63a8d403e1SKonstantin Belousov 	.sv_sigtbl	= NULL,
64a8d403e1SKonstantin Belousov 	.sv_errsize	= 0,
65a8d403e1SKonstantin Belousov 	.sv_errtbl	= NULL,
66a8d403e1SKonstantin Belousov 	.sv_transtrap	= NULL,
67a8d403e1SKonstantin Belousov 	.sv_fixup	= aout_fixup,
68a8d403e1SKonstantin Belousov 	.sv_sendsig	= sendsig,
69a8d403e1SKonstantin Belousov 	.sv_sigcode	= sigcode,
70a8d403e1SKonstantin Belousov 	.sv_szsigcode	= &szsigcode,
71a8d403e1SKonstantin Belousov 	.sv_prepsyscall	= NULL,
72a8d403e1SKonstantin Belousov 	.sv_name	= "FreeBSD a.out",
73a8d403e1SKonstantin Belousov 	.sv_coredump	= NULL,
74a8d403e1SKonstantin Belousov 	.sv_imgact_try	= NULL,
75a8d403e1SKonstantin Belousov 	.sv_minsigstksz	= MINSIGSTKSZ,
76a8d403e1SKonstantin Belousov 	.sv_pagesize	= PAGE_SIZE,
77a8d403e1SKonstantin Belousov 	.sv_minuser	= VM_MIN_ADDRESS,
78a8d403e1SKonstantin Belousov 	.sv_maxuser	= VM_MAXUSER_ADDRESS,
79a8d403e1SKonstantin Belousov 	.sv_usrstack	= USRSTACK,
80a8d403e1SKonstantin Belousov 	.sv_psstrings	= PS_STRINGS,
81a8d403e1SKonstantin Belousov 	.sv_stackprot	= VM_PROT_ALL,
82a8d403e1SKonstantin Belousov 	.sv_copyout_strings	= exec_copyout_strings,
83a8d403e1SKonstantin Belousov 	.sv_setregs	= exec_setregs,
84a8d403e1SKonstantin Belousov 	.sv_fixlimit	= NULL,
85b4cf0e62SKonstantin Belousov 	.sv_maxssiz	= NULL,
86b4cf0e62SKonstantin Belousov 	.sv_flags	= SV_ABI_FREEBSD | SV_AOUT |
87b4cf0e62SKonstantin Belousov #if defined(__i386__)
88b4cf0e62SKonstantin Belousov 	SV_IA32 | SV_ILP32
89b4cf0e62SKonstantin Belousov #else
90b4cf0e62SKonstantin Belousov #error Choose SV_XXX flags for the platform
91b4cf0e62SKonstantin Belousov #endif
92afe1a688SKonstantin Belousov 	,
93afe1a688SKonstantin Belousov 	.sv_set_syscall_retval = cpu_set_syscall_retval,
94afe1a688SKonstantin Belousov 	.sv_fetch_syscall_args = cpu_fetch_syscall_args,
95afe1a688SKonstantin Belousov 	.sv_syscallnames = syscallnames,
96*e5d81ef1SDmitry Chagin 	.sv_schedtail	= NULL,
9722d4b0fbSJohn Polstra };
9822d4b0fbSJohn Polstra 
99b9e91a85SBruce Evans static int
100f36ba452SJake Burkholder aout_fixup(stack_base, imgp)
101f36ba452SJake Burkholder 	register_t **stack_base;
102f36ba452SJake Burkholder 	struct image_params *imgp;
103f36ba452SJake Burkholder {
104f36ba452SJake Burkholder 
105610ecfe0SMaxim Sobolev 	return (suword(--(*stack_base), imgp->args->argc));
106f36ba452SJake Burkholder }
107f36ba452SJake Burkholder 
108f36ba452SJake Burkholder static int
109c52007c2SDavid Greenman exec_aout_imgact(imgp)
110c52007c2SDavid Greenman 	struct image_params *imgp;
111cfefd687SGarrett Wollman {
112e0c95ed9SBruce Evans 	const struct exec *a_out = (const struct exec *) imgp->image_header;
1135856e12eSJohn Dyson 	struct vmspace *vmspace;
1142f33b2c0SAlan Cox 	vm_map_t map;
1151616db3cSJohn Dyson 	vm_object_t object;
1161616db3cSJohn Dyson 	vm_offset_t text_end, data_end;
117ede8dc43SBruce Evans 	unsigned long virtual_offset;
118a316d390SJohn Dyson 	unsigned long file_offset;
119cfefd687SGarrett Wollman 	unsigned long bss_size;
120bb56ec4aSPoul-Henning Kamp 	int error;
121cfefd687SGarrett Wollman 
1221e1e0b44SSøren Schmidt 	/*
1231e1e0b44SSøren Schmidt 	 * Linux and *BSD binaries look very much alike,
1241e1e0b44SSøren Schmidt 	 * only the machine id is different:
125d3628763SRodney W. Grimes 	 * 0x64 for Linux, 0x86 for *BSD, 0x00 for BSDI.
126185dc761SPeter Wemm 	 * NetBSD is in network byte order.. ugh.
1271e1e0b44SSøren Schmidt 	 */
128d3628763SRodney W. Grimes 	if (((a_out->a_magic >> 16) & 0xff) != 0x86 &&
129185dc761SPeter Wemm 	    ((a_out->a_magic >> 16) & 0xff) != 0 &&
130185dc761SPeter Wemm 	    ((((int)ntohl(a_out->a_magic)) >> 16) & 0xff) != 0x86)
1311e1e0b44SSøren Schmidt                 return -1;
1321e1e0b44SSøren Schmidt 
133cfefd687SGarrett Wollman 	/*
134cfefd687SGarrett Wollman 	 * Set file/virtual offset based on a.out variant.
135cfefd687SGarrett Wollman 	 *	We do two cases: host byte order and network byte order
136cfefd687SGarrett Wollman 	 *	(for NetBSD compatibility)
137cfefd687SGarrett Wollman 	 */
138cfefd687SGarrett Wollman 	switch ((int)(a_out->a_magic & 0xffff)) {
139cfefd687SGarrett Wollman 	case ZMAGIC:
140cfefd687SGarrett Wollman 		virtual_offset = 0;
141cfefd687SGarrett Wollman 		if (a_out->a_text) {
142f8845af0SPoul-Henning Kamp 			file_offset = PAGE_SIZE;
143cfefd687SGarrett Wollman 		} else {
144cfefd687SGarrett Wollman 			/* Bill's "screwball mode" */
145cfefd687SGarrett Wollman 			file_offset = 0;
146cfefd687SGarrett Wollman 		}
147cfefd687SGarrett Wollman 		break;
148cfefd687SGarrett Wollman 	case QMAGIC:
149f8845af0SPoul-Henning Kamp 		virtual_offset = PAGE_SIZE;
150cfefd687SGarrett Wollman 		file_offset = 0;
1514fe88fe6SJohn Polstra 		/* Pass PS_STRINGS for BSD/OS binaries only. */
1524fe88fe6SJohn Polstra 		if (N_GETMID(*a_out) == MID_ZERO)
15305ba50f5SJake Burkholder 			imgp->ps_strings = aout_sysvec.sv_psstrings;
154cfefd687SGarrett Wollman 		break;
155cfefd687SGarrett Wollman 	default:
156cfefd687SGarrett Wollman 		/* NetBSD compatibility */
157cfefd687SGarrett Wollman 		switch ((int)(ntohl(a_out->a_magic) & 0xffff)) {
158cfefd687SGarrett Wollman 		case ZMAGIC:
159cfefd687SGarrett Wollman 		case QMAGIC:
160f8845af0SPoul-Henning Kamp 			virtual_offset = PAGE_SIZE;
161cfefd687SGarrett Wollman 			file_offset = 0;
162cfefd687SGarrett Wollman 			break;
163cfefd687SGarrett Wollman 		default:
164cfefd687SGarrett Wollman 			return (-1);
165cfefd687SGarrett Wollman 		}
166cfefd687SGarrett Wollman 	}
167cfefd687SGarrett Wollman 
168f8845af0SPoul-Henning Kamp 	bss_size = roundup(a_out->a_bss, PAGE_SIZE);
169cfefd687SGarrett Wollman 
170cfefd687SGarrett Wollman 	/*
171cfefd687SGarrett Wollman 	 * Check various fields in header for validity/bounds.
172cfefd687SGarrett Wollman 	 */
173cfefd687SGarrett Wollman 	if (/* entry point must lay with text region */
174cfefd687SGarrett Wollman 	    a_out->a_entry < virtual_offset ||
175cfefd687SGarrett Wollman 	    a_out->a_entry >= virtual_offset + a_out->a_text ||
176cfefd687SGarrett Wollman 
177cfefd687SGarrett Wollman 	    /* text and data size must each be page rounded */
178f8845af0SPoul-Henning Kamp 	    a_out->a_text & PAGE_MASK || a_out->a_data & PAGE_MASK)
179cfefd687SGarrett Wollman 		return (-1);
180cfefd687SGarrett Wollman 
181cfefd687SGarrett Wollman 	/* text + data can't exceed file size */
182c52007c2SDavid Greenman 	if (a_out->a_data + a_out->a_text > imgp->attr->va_size)
183cfefd687SGarrett Wollman 		return (EFAULT);
184cfefd687SGarrett Wollman 
185cfefd687SGarrett Wollman 	/*
186cfefd687SGarrett Wollman 	 * text/data/bss must not exceed limits
187cfefd687SGarrett Wollman 	 */
18891d5354aSJohn Baldwin 	PROC_LOCK(imgp->proc);
189cfefd687SGarrett Wollman 	if (/* text can't exceed maximum text size */
190cbc89bfbSPaul Saab 	    a_out->a_text > maxtsiz ||
191cfefd687SGarrett Wollman 
192cfefd687SGarrett Wollman 	    /* data + bss can't exceed rlimit */
19391d5354aSJohn Baldwin 	    a_out->a_data + bss_size > lim_cur(imgp->proc, RLIMIT_DATA)) {
19491d5354aSJohn Baldwin 			PROC_UNLOCK(imgp->proc);
195cfefd687SGarrett Wollman 			return (ENOMEM);
19691d5354aSJohn Baldwin 	}
19791d5354aSJohn Baldwin 	PROC_UNLOCK(imgp->proc);
198cfefd687SGarrett Wollman 
199cfefd687SGarrett Wollman 	/*
20060bb3943SAlan Cox 	 * Avoid a possible deadlock if the current address space is destroyed
20160bb3943SAlan Cox 	 * and that address space maps the locked vnode.  In the common case,
20260bb3943SAlan Cox 	 * the locked vnode's v_usecount is decremented but remains greater
20360bb3943SAlan Cox 	 * than zero.  Consequently, the vnode lock is not needed by vrele().
20460bb3943SAlan Cox 	 * However, in cases where the vnode lock is external, such as nullfs,
20560bb3943SAlan Cox 	 * v_usecount may become zero.
20660bb3943SAlan Cox 	 */
20722db15c0SAttilio Rao 	VOP_UNLOCK(imgp->vp, 0);
20860bb3943SAlan Cox 
20960bb3943SAlan Cox 	/*
210cfefd687SGarrett Wollman 	 * Destroy old process VM and create a new one (with a new stack)
211cfefd687SGarrett Wollman 	 */
21289b57fcfSKonstantin Belousov 	error = exec_new_vmspace(imgp, &aout_sysvec);
213cfefd687SGarrett Wollman 
214cb05b60aSAttilio Rao 	vn_lock(imgp->vp, LK_EXCLUSIVE | LK_RETRY);
21589b57fcfSKonstantin Belousov 	if (error)
21689b57fcfSKonstantin Belousov 		return (error);
21760bb3943SAlan Cox 
218cfefd687SGarrett Wollman 	/*
2195856e12eSJohn Dyson 	 * The vm space can be changed by exec_new_vmspace
2205856e12eSJohn Dyson 	 */
2215856e12eSJohn Dyson 	vmspace = imgp->proc->p_vmspace;
2225856e12eSJohn Dyson 
2230b2ed1aeSJeff Roberson 	object = imgp->object;
2242f33b2c0SAlan Cox 	map = &vmspace->vm_map;
2252f33b2c0SAlan Cox 	vm_map_lock(map);
2261616db3cSJohn Dyson 	vm_object_reference(object);
2271616db3cSJohn Dyson 
2281616db3cSJohn Dyson 	text_end = virtual_offset + a_out->a_text;
2290a91231dSAlan Cox 	error = vm_map_insert(map, object,
2301616db3cSJohn Dyson 		file_offset,
2311616db3cSJohn Dyson 		virtual_offset, text_end,
2321616db3cSJohn Dyson 		VM_PROT_READ | VM_PROT_EXECUTE, VM_PROT_ALL,
233e972780aSAlan Cox 		MAP_COPY_ON_WRITE | MAP_PREFAULT);
2342f33b2c0SAlan Cox 	if (error) {
2352f33b2c0SAlan Cox 		vm_map_unlock(map);
23641634e2eSAlan Cox 		vm_object_deallocate(object);
237cfefd687SGarrett Wollman 		return (error);
2382f33b2c0SAlan Cox 	}
2391616db3cSJohn Dyson 	data_end = text_end + a_out->a_data;
2401616db3cSJohn Dyson 	if (a_out->a_data) {
2411616db3cSJohn Dyson 		vm_object_reference(object);
2420a91231dSAlan Cox 		error = vm_map_insert(map, object,
2431616db3cSJohn Dyson 			file_offset + a_out->a_text,
2441616db3cSJohn Dyson 			text_end, data_end,
2451616db3cSJohn Dyson 			VM_PROT_ALL, VM_PROT_ALL,
246e972780aSAlan Cox 			MAP_COPY_ON_WRITE | MAP_PREFAULT);
2472f33b2c0SAlan Cox 		if (error) {
2482f33b2c0SAlan Cox 			vm_map_unlock(map);
24941634e2eSAlan Cox 			vm_object_deallocate(object);
2501616db3cSJohn Dyson 			return (error);
2511616db3cSJohn Dyson 		}
2522f33b2c0SAlan Cox 	}
253cfefd687SGarrett Wollman 
2541616db3cSJohn Dyson 	if (bss_size) {
2550a91231dSAlan Cox 		error = vm_map_insert(map, NULL, 0,
2561616db3cSJohn Dyson 			data_end, data_end + bss_size,
2571616db3cSJohn Dyson 			VM_PROT_ALL, VM_PROT_ALL, 0);
2582f33b2c0SAlan Cox 		if (error) {
2592f33b2c0SAlan Cox 			vm_map_unlock(map);
260cfefd687SGarrett Wollman 			return (error);
26168940ac1SDavid Greenman 		}
2622f33b2c0SAlan Cox 	}
2632f33b2c0SAlan Cox 	vm_map_unlock(map);
264cfefd687SGarrett Wollman 
265cfefd687SGarrett Wollman 	/* Fill in process VM information */
266cfefd687SGarrett Wollman 	vmspace->vm_tsize = a_out->a_text >> PAGE_SHIFT;
267cfefd687SGarrett Wollman 	vmspace->vm_dsize = (a_out->a_data + bss_size) >> PAGE_SHIFT;
2687cd99438SBruce Evans 	vmspace->vm_taddr = (caddr_t) (uintptr_t) virtual_offset;
2697cd99438SBruce Evans 	vmspace->vm_daddr = (caddr_t) (uintptr_t)
2707cd99438SBruce Evans 			    (virtual_offset + a_out->a_text);
271cfefd687SGarrett Wollman 
272cfefd687SGarrett Wollman 	/* Fill in image_params */
273c52007c2SDavid Greenman 	imgp->interpreted = 0;
274c52007c2SDavid Greenman 	imgp->entry_addr = a_out->a_entry;
275cfefd687SGarrett Wollman 
276c52007c2SDavid Greenman 	imgp->proc->p_sysent = &aout_sysvec;
277c0e5de7dSDavid Greenman 
278cfefd687SGarrett Wollman 	return (0);
279cfefd687SGarrett Wollman }
28092d91f76SGarrett Wollman 
28192d91f76SGarrett Wollman /*
28292d91f76SGarrett Wollman  * Tell kern_execve.c about it, with a little help from the linker.
28392d91f76SGarrett Wollman  */
284820ca326SMatthew Dillon static struct execsw aout_execsw = { exec_aout_imgact, "a.out" };
285aa855a59SPeter Wemm EXEC_SET(aout, aout_execsw);
286