xref: /freebsd/sys/kern/imgact_aout.c (revision 41634e2e8d2bf5ccad70d4a7e75e71a8729e7f69)
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 = {
5922d4b0fbSJohn Polstra 	SYS_MAXSYSCALL,
6022d4b0fbSJohn Polstra 	sysent,
6122d4b0fbSJohn Polstra 	0,
6222d4b0fbSJohn Polstra 	0,
63f36ba452SJake Burkholder 	NULL,
6422d4b0fbSJohn Polstra 	0,
65f36ba452SJake Burkholder 	NULL,
66f36ba452SJake Burkholder 	NULL,
67f36ba452SJake Burkholder 	aout_fixup,
6822d4b0fbSJohn Polstra 	sendsig,
6922d4b0fbSJohn Polstra 	sigcode,
7022d4b0fbSJohn Polstra 	&szsigcode,
71f36ba452SJake Burkholder 	NULL,
7222d4b0fbSJohn Polstra 	"FreeBSD a.out",
731eecfae3SDavid Schultz 	NULL,
74806d7daaSMarcel Moolenaar 	NULL,
75f36ba452SJake Burkholder 	MINSIGSTKSZ,
76f36ba452SJake Burkholder 	PAGE_SIZE,
77f36ba452SJake Burkholder 	VM_MIN_ADDRESS,
78f36ba452SJake Burkholder 	VM_MAXUSER_ADDRESS,
79f36ba452SJake Burkholder 	USRSTACK,
80f36ba452SJake Burkholder 	PS_STRINGS,
81f36ba452SJake Burkholder 	VM_PROT_ALL,
82f36ba452SJake Burkholder 	exec_copyout_strings,
83c460ac3aSPeter Wemm 	exec_setregs,
84c460ac3aSPeter Wemm 	NULL
8522d4b0fbSJohn Polstra };
8622d4b0fbSJohn Polstra 
87b9e91a85SBruce Evans static int
88f36ba452SJake Burkholder aout_fixup(stack_base, imgp)
89f36ba452SJake Burkholder 	register_t **stack_base;
90f36ba452SJake Burkholder 	struct image_params *imgp;
91f36ba452SJake Burkholder {
92f36ba452SJake Burkholder 
93610ecfe0SMaxim Sobolev 	return (suword(--(*stack_base), imgp->args->argc));
94f36ba452SJake Burkholder }
95f36ba452SJake Burkholder 
96f36ba452SJake Burkholder static int
97c52007c2SDavid Greenman exec_aout_imgact(imgp)
98c52007c2SDavid Greenman 	struct image_params *imgp;
99cfefd687SGarrett Wollman {
100e0c95ed9SBruce Evans 	const struct exec *a_out = (const struct exec *) imgp->image_header;
10160bb3943SAlan Cox 	struct thread *td = curthread;
1025856e12eSJohn Dyson 	struct vmspace *vmspace;
1032f33b2c0SAlan Cox 	vm_map_t map;
1041616db3cSJohn Dyson 	vm_object_t object;
1051616db3cSJohn Dyson 	vm_offset_t text_end, data_end;
106ede8dc43SBruce Evans 	unsigned long virtual_offset;
107a316d390SJohn Dyson 	unsigned long file_offset;
108cfefd687SGarrett Wollman 	unsigned long bss_size;
109bb56ec4aSPoul-Henning Kamp 	int error;
110cfefd687SGarrett Wollman 
1111e1e0b44SSøren Schmidt 	/*
1121e1e0b44SSøren Schmidt 	 * Linux and *BSD binaries look very much alike,
1131e1e0b44SSøren Schmidt 	 * only the machine id is different:
114d3628763SRodney W. Grimes 	 * 0x64 for Linux, 0x86 for *BSD, 0x00 for BSDI.
115185dc761SPeter Wemm 	 * NetBSD is in network byte order.. ugh.
1161e1e0b44SSøren Schmidt 	 */
117d3628763SRodney W. Grimes 	if (((a_out->a_magic >> 16) & 0xff) != 0x86 &&
118185dc761SPeter Wemm 	    ((a_out->a_magic >> 16) & 0xff) != 0 &&
119185dc761SPeter Wemm 	    ((((int)ntohl(a_out->a_magic)) >> 16) & 0xff) != 0x86)
1201e1e0b44SSøren Schmidt                 return -1;
1211e1e0b44SSøren Schmidt 
122cfefd687SGarrett Wollman 	/*
123cfefd687SGarrett Wollman 	 * Set file/virtual offset based on a.out variant.
124cfefd687SGarrett Wollman 	 *	We do two cases: host byte order and network byte order
125cfefd687SGarrett Wollman 	 *	(for NetBSD compatibility)
126cfefd687SGarrett Wollman 	 */
127cfefd687SGarrett Wollman 	switch ((int)(a_out->a_magic & 0xffff)) {
128cfefd687SGarrett Wollman 	case ZMAGIC:
129cfefd687SGarrett Wollman 		virtual_offset = 0;
130cfefd687SGarrett Wollman 		if (a_out->a_text) {
131f8845af0SPoul-Henning Kamp 			file_offset = PAGE_SIZE;
132cfefd687SGarrett Wollman 		} else {
133cfefd687SGarrett Wollman 			/* Bill's "screwball mode" */
134cfefd687SGarrett Wollman 			file_offset = 0;
135cfefd687SGarrett Wollman 		}
136cfefd687SGarrett Wollman 		break;
137cfefd687SGarrett Wollman 	case QMAGIC:
138f8845af0SPoul-Henning Kamp 		virtual_offset = PAGE_SIZE;
139cfefd687SGarrett Wollman 		file_offset = 0;
1404fe88fe6SJohn Polstra 		/* Pass PS_STRINGS for BSD/OS binaries only. */
1414fe88fe6SJohn Polstra 		if (N_GETMID(*a_out) == MID_ZERO)
14205ba50f5SJake Burkholder 			imgp->ps_strings = aout_sysvec.sv_psstrings;
143cfefd687SGarrett Wollman 		break;
144cfefd687SGarrett Wollman 	default:
145cfefd687SGarrett Wollman 		/* NetBSD compatibility */
146cfefd687SGarrett Wollman 		switch ((int)(ntohl(a_out->a_magic) & 0xffff)) {
147cfefd687SGarrett Wollman 		case ZMAGIC:
148cfefd687SGarrett Wollman 		case QMAGIC:
149f8845af0SPoul-Henning Kamp 			virtual_offset = PAGE_SIZE;
150cfefd687SGarrett Wollman 			file_offset = 0;
151cfefd687SGarrett Wollman 			break;
152cfefd687SGarrett Wollman 		default:
153cfefd687SGarrett Wollman 			return (-1);
154cfefd687SGarrett Wollman 		}
155cfefd687SGarrett Wollman 	}
156cfefd687SGarrett Wollman 
157f8845af0SPoul-Henning Kamp 	bss_size = roundup(a_out->a_bss, PAGE_SIZE);
158cfefd687SGarrett Wollman 
159cfefd687SGarrett Wollman 	/*
160cfefd687SGarrett Wollman 	 * Check various fields in header for validity/bounds.
161cfefd687SGarrett Wollman 	 */
162cfefd687SGarrett Wollman 	if (/* entry point must lay with text region */
163cfefd687SGarrett Wollman 	    a_out->a_entry < virtual_offset ||
164cfefd687SGarrett Wollman 	    a_out->a_entry >= virtual_offset + a_out->a_text ||
165cfefd687SGarrett Wollman 
166cfefd687SGarrett Wollman 	    /* text and data size must each be page rounded */
167f8845af0SPoul-Henning Kamp 	    a_out->a_text & PAGE_MASK || a_out->a_data & PAGE_MASK)
168cfefd687SGarrett Wollman 		return (-1);
169cfefd687SGarrett Wollman 
170cfefd687SGarrett Wollman 	/* text + data can't exceed file size */
171c52007c2SDavid Greenman 	if (a_out->a_data + a_out->a_text > imgp->attr->va_size)
172cfefd687SGarrett Wollman 		return (EFAULT);
173cfefd687SGarrett Wollman 
174cfefd687SGarrett Wollman 	/*
175cfefd687SGarrett Wollman 	 * text/data/bss must not exceed limits
176cfefd687SGarrett Wollman 	 */
17791d5354aSJohn Baldwin 	PROC_LOCK(imgp->proc);
178cfefd687SGarrett Wollman 	if (/* text can't exceed maximum text size */
179cbc89bfbSPaul Saab 	    a_out->a_text > maxtsiz ||
180cfefd687SGarrett Wollman 
181cfefd687SGarrett Wollman 	    /* data + bss can't exceed rlimit */
18291d5354aSJohn Baldwin 	    a_out->a_data + bss_size > lim_cur(imgp->proc, RLIMIT_DATA)) {
18391d5354aSJohn Baldwin 			PROC_UNLOCK(imgp->proc);
184cfefd687SGarrett Wollman 			return (ENOMEM);
18591d5354aSJohn Baldwin 	}
18691d5354aSJohn Baldwin 	PROC_UNLOCK(imgp->proc);
187cfefd687SGarrett Wollman 
188cfefd687SGarrett Wollman 	/*
18960bb3943SAlan Cox 	 * Avoid a possible deadlock if the current address space is destroyed
19060bb3943SAlan Cox 	 * and that address space maps the locked vnode.  In the common case,
19160bb3943SAlan Cox 	 * the locked vnode's v_usecount is decremented but remains greater
19260bb3943SAlan Cox 	 * than zero.  Consequently, the vnode lock is not needed by vrele().
19360bb3943SAlan Cox 	 * However, in cases where the vnode lock is external, such as nullfs,
19460bb3943SAlan Cox 	 * v_usecount may become zero.
19560bb3943SAlan Cox 	 */
19660bb3943SAlan Cox 	VOP_UNLOCK(imgp->vp, 0, td);
19760bb3943SAlan Cox 
19860bb3943SAlan Cox 	/*
199cfefd687SGarrett Wollman 	 * Destroy old process VM and create a new one (with a new stack)
200cfefd687SGarrett Wollman 	 */
20105ba50f5SJake Burkholder 	exec_new_vmspace(imgp, &aout_sysvec);
202cfefd687SGarrett Wollman 
20360bb3943SAlan Cox 	vn_lock(imgp->vp, LK_EXCLUSIVE | LK_RETRY, td);
20460bb3943SAlan Cox 
205cfefd687SGarrett Wollman 	/*
2065856e12eSJohn Dyson 	 * The vm space can be changed by exec_new_vmspace
2075856e12eSJohn Dyson 	 */
2085856e12eSJohn Dyson 	vmspace = imgp->proc->p_vmspace;
2095856e12eSJohn Dyson 
2100b2ed1aeSJeff Roberson 	object = imgp->object;
2112f33b2c0SAlan Cox 	map = &vmspace->vm_map;
2122f33b2c0SAlan Cox 	vm_map_lock(map);
2131616db3cSJohn Dyson 	vm_object_reference(object);
2141616db3cSJohn Dyson 
2151616db3cSJohn Dyson 	text_end = virtual_offset + a_out->a_text;
2160a91231dSAlan Cox 	error = vm_map_insert(map, object,
2171616db3cSJohn Dyson 		file_offset,
2181616db3cSJohn Dyson 		virtual_offset, text_end,
2191616db3cSJohn Dyson 		VM_PROT_READ | VM_PROT_EXECUTE, VM_PROT_ALL,
220e972780aSAlan Cox 		MAP_COPY_ON_WRITE | MAP_PREFAULT);
2212f33b2c0SAlan Cox 	if (error) {
2222f33b2c0SAlan Cox 		vm_map_unlock(map);
22341634e2eSAlan Cox 		vm_object_deallocate(object);
224cfefd687SGarrett Wollman 		return (error);
2252f33b2c0SAlan Cox 	}
2261616db3cSJohn Dyson 	data_end = text_end + a_out->a_data;
2271616db3cSJohn Dyson 	if (a_out->a_data) {
2281616db3cSJohn Dyson 		vm_object_reference(object);
2290a91231dSAlan Cox 		error = vm_map_insert(map, object,
2301616db3cSJohn Dyson 			file_offset + a_out->a_text,
2311616db3cSJohn Dyson 			text_end, data_end,
2321616db3cSJohn Dyson 			VM_PROT_ALL, 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);
2371616db3cSJohn Dyson 			return (error);
2381616db3cSJohn Dyson 		}
2392f33b2c0SAlan Cox 	}
240cfefd687SGarrett Wollman 
2411616db3cSJohn Dyson 	if (bss_size) {
2420a91231dSAlan Cox 		error = vm_map_insert(map, NULL, 0,
2431616db3cSJohn Dyson 			data_end, data_end + bss_size,
2441616db3cSJohn Dyson 			VM_PROT_ALL, VM_PROT_ALL, 0);
2452f33b2c0SAlan Cox 		if (error) {
2462f33b2c0SAlan Cox 			vm_map_unlock(map);
247cfefd687SGarrett Wollman 			return (error);
24868940ac1SDavid Greenman 		}
2492f33b2c0SAlan Cox 	}
2502f33b2c0SAlan Cox 	vm_map_unlock(map);
251cfefd687SGarrett Wollman 
252cfefd687SGarrett Wollman 	/* Fill in process VM information */
253cfefd687SGarrett Wollman 	vmspace->vm_tsize = a_out->a_text >> PAGE_SHIFT;
254cfefd687SGarrett Wollman 	vmspace->vm_dsize = (a_out->a_data + bss_size) >> PAGE_SHIFT;
2557cd99438SBruce Evans 	vmspace->vm_taddr = (caddr_t) (uintptr_t) virtual_offset;
2567cd99438SBruce Evans 	vmspace->vm_daddr = (caddr_t) (uintptr_t)
2577cd99438SBruce Evans 			    (virtual_offset + a_out->a_text);
258cfefd687SGarrett Wollman 
259cfefd687SGarrett Wollman 	/* Fill in image_params */
260c52007c2SDavid Greenman 	imgp->interpreted = 0;
261c52007c2SDavid Greenman 	imgp->entry_addr = a_out->a_entry;
262cfefd687SGarrett Wollman 
263c52007c2SDavid Greenman 	imgp->proc->p_sysent = &aout_sysvec;
264c0e5de7dSDavid Greenman 
265cfefd687SGarrett Wollman 	return (0);
266cfefd687SGarrett Wollman }
26792d91f76SGarrett Wollman 
26892d91f76SGarrett Wollman /*
26992d91f76SGarrett Wollman  * Tell kern_execve.c about it, with a little help from the linker.
27092d91f76SGarrett Wollman  */
271820ca326SMatthew Dillon static struct execsw aout_execsw = { exec_aout_imgact, "a.out" };
272aa855a59SPeter Wemm EXEC_SET(aout, aout_execsw);
273