xref: /freebsd/sys/kern/imgact_aout.c (revision 91d5354a2ce810d848eca6ecf9da1027aeb2be6d)
1cfefd687SGarrett Wollman /*
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 #include <sys/user.h>
46fb919e4dSMark Murray 
47710ded3aSPeter Wemm #include <machine/frame.h>
48e5d6cd0cSBruce Evans #include <machine/md_var.h>
49cfefd687SGarrett Wollman 
5026f9a767SRodney W. Grimes #include <vm/vm.h>
51efeaf95aSDavid Greenman #include <vm/pmap.h>
52efeaf95aSDavid Greenman #include <vm/vm_map.h>
531616db3cSJohn Dyson #include <vm/vm_object.h>
54e5d6cd0cSBruce Evans #include <vm/vm_param.h>
55cfefd687SGarrett Wollman 
564d77a549SAlfred Perlstein static int	exec_aout_imgact(struct image_params *imgp);
57f36ba452SJake Burkholder static int	aout_fixup(register_t **stack_base, struct image_params *imgp);
587ee050b7SBruce Evans 
5922d4b0fbSJohn Polstra struct sysentvec aout_sysvec = {
6022d4b0fbSJohn Polstra 	SYS_MAXSYSCALL,
6122d4b0fbSJohn Polstra 	sysent,
6222d4b0fbSJohn Polstra 	0,
6322d4b0fbSJohn Polstra 	0,
64f36ba452SJake Burkholder 	NULL,
6522d4b0fbSJohn Polstra 	0,
66f36ba452SJake Burkholder 	NULL,
67f36ba452SJake Burkholder 	NULL,
68f36ba452SJake Burkholder 	aout_fixup,
6922d4b0fbSJohn Polstra 	sendsig,
7022d4b0fbSJohn Polstra 	sigcode,
7122d4b0fbSJohn Polstra 	&szsigcode,
72f36ba452SJake Burkholder 	NULL,
7322d4b0fbSJohn Polstra 	"FreeBSD a.out",
74806d7daaSMarcel Moolenaar 	aout_coredump,
75806d7daaSMarcel Moolenaar 	NULL,
76f36ba452SJake Burkholder 	MINSIGSTKSZ,
77f36ba452SJake Burkholder 	PAGE_SIZE,
78f36ba452SJake Burkholder 	VM_MIN_ADDRESS,
79f36ba452SJake Burkholder 	VM_MAXUSER_ADDRESS,
80f36ba452SJake Burkholder 	USRSTACK,
81f36ba452SJake Burkholder 	PS_STRINGS,
82f36ba452SJake Burkholder 	VM_PROT_ALL,
83f36ba452SJake Burkholder 	exec_copyout_strings,
84c460ac3aSPeter Wemm 	exec_setregs,
85c460ac3aSPeter Wemm 	NULL
8622d4b0fbSJohn Polstra };
8722d4b0fbSJohn Polstra 
88b9e91a85SBruce Evans static int
89f36ba452SJake Burkholder aout_fixup(stack_base, imgp)
90f36ba452SJake Burkholder 	register_t **stack_base;
91f36ba452SJake Burkholder 	struct image_params *imgp;
92f36ba452SJake Burkholder {
93f36ba452SJake Burkholder 
94f36ba452SJake Burkholder 	return (suword(--(*stack_base), imgp->argc));
95f36ba452SJake Burkholder }
96f36ba452SJake Burkholder 
97f36ba452SJake Burkholder static int
98c52007c2SDavid Greenman exec_aout_imgact(imgp)
99c52007c2SDavid Greenman 	struct image_params *imgp;
100cfefd687SGarrett Wollman {
101e0c95ed9SBruce Evans 	const struct exec *a_out = (const struct exec *) imgp->image_header;
1025856e12eSJohn Dyson 	struct vmspace *vmspace;
1031616db3cSJohn Dyson 	struct vnode *vp;
1042f33b2c0SAlan Cox 	vm_map_t map;
1051616db3cSJohn Dyson 	vm_object_t object;
1061616db3cSJohn Dyson 	vm_offset_t text_end, data_end;
107ede8dc43SBruce Evans 	unsigned long virtual_offset;
108a316d390SJohn Dyson 	unsigned long file_offset;
109cfefd687SGarrett Wollman 	unsigned long bss_size;
110bb56ec4aSPoul-Henning Kamp 	int error;
111cfefd687SGarrett Wollman 
1120cddd8f0SMatthew Dillon 	GIANT_REQUIRED;
1130cddd8f0SMatthew Dillon 
1141e1e0b44SSøren Schmidt 	/*
1151e1e0b44SSøren Schmidt 	 * Linux and *BSD binaries look very much alike,
1161e1e0b44SSøren Schmidt 	 * only the machine id is different:
117d3628763SRodney W. Grimes 	 * 0x64 for Linux, 0x86 for *BSD, 0x00 for BSDI.
118185dc761SPeter Wemm 	 * NetBSD is in network byte order.. ugh.
1191e1e0b44SSøren Schmidt 	 */
120d3628763SRodney W. Grimes 	if (((a_out->a_magic >> 16) & 0xff) != 0x86 &&
121185dc761SPeter Wemm 	    ((a_out->a_magic >> 16) & 0xff) != 0 &&
122185dc761SPeter Wemm 	    ((((int)ntohl(a_out->a_magic)) >> 16) & 0xff) != 0x86)
1231e1e0b44SSøren Schmidt                 return -1;
1241e1e0b44SSøren Schmidt 
125cfefd687SGarrett Wollman 	/*
126cfefd687SGarrett Wollman 	 * Set file/virtual offset based on a.out variant.
127cfefd687SGarrett Wollman 	 *	We do two cases: host byte order and network byte order
128cfefd687SGarrett Wollman 	 *	(for NetBSD compatibility)
129cfefd687SGarrett Wollman 	 */
130cfefd687SGarrett Wollman 	switch ((int)(a_out->a_magic & 0xffff)) {
131cfefd687SGarrett Wollman 	case ZMAGIC:
132cfefd687SGarrett Wollman 		virtual_offset = 0;
133cfefd687SGarrett Wollman 		if (a_out->a_text) {
134f8845af0SPoul-Henning Kamp 			file_offset = PAGE_SIZE;
135cfefd687SGarrett Wollman 		} else {
136cfefd687SGarrett Wollman 			/* Bill's "screwball mode" */
137cfefd687SGarrett Wollman 			file_offset = 0;
138cfefd687SGarrett Wollman 		}
139cfefd687SGarrett Wollman 		break;
140cfefd687SGarrett Wollman 	case QMAGIC:
141f8845af0SPoul-Henning Kamp 		virtual_offset = PAGE_SIZE;
142cfefd687SGarrett Wollman 		file_offset = 0;
1434fe88fe6SJohn Polstra 		/* Pass PS_STRINGS for BSD/OS binaries only. */
1444fe88fe6SJohn Polstra 		if (N_GETMID(*a_out) == MID_ZERO)
14505ba50f5SJake Burkholder 			imgp->ps_strings = aout_sysvec.sv_psstrings;
146cfefd687SGarrett Wollman 		break;
147cfefd687SGarrett Wollman 	default:
148cfefd687SGarrett Wollman 		/* NetBSD compatibility */
149cfefd687SGarrett Wollman 		switch ((int)(ntohl(a_out->a_magic) & 0xffff)) {
150cfefd687SGarrett Wollman 		case ZMAGIC:
151cfefd687SGarrett Wollman 		case QMAGIC:
152f8845af0SPoul-Henning Kamp 			virtual_offset = PAGE_SIZE;
153cfefd687SGarrett Wollman 			file_offset = 0;
154cfefd687SGarrett Wollman 			break;
155cfefd687SGarrett Wollman 		default:
156cfefd687SGarrett Wollman 			return (-1);
157cfefd687SGarrett Wollman 		}
158cfefd687SGarrett Wollman 	}
159cfefd687SGarrett Wollman 
160f8845af0SPoul-Henning Kamp 	bss_size = roundup(a_out->a_bss, PAGE_SIZE);
161cfefd687SGarrett Wollman 
162cfefd687SGarrett Wollman 	/*
163cfefd687SGarrett Wollman 	 * Check various fields in header for validity/bounds.
164cfefd687SGarrett Wollman 	 */
165cfefd687SGarrett Wollman 	if (/* entry point must lay with text region */
166cfefd687SGarrett Wollman 	    a_out->a_entry < virtual_offset ||
167cfefd687SGarrett Wollman 	    a_out->a_entry >= virtual_offset + a_out->a_text ||
168cfefd687SGarrett Wollman 
169cfefd687SGarrett Wollman 	    /* text and data size must each be page rounded */
170f8845af0SPoul-Henning Kamp 	    a_out->a_text & PAGE_MASK || a_out->a_data & PAGE_MASK)
171cfefd687SGarrett Wollman 		return (-1);
172cfefd687SGarrett Wollman 
173cfefd687SGarrett Wollman 	/* text + data can't exceed file size */
174c52007c2SDavid Greenman 	if (a_out->a_data + a_out->a_text > imgp->attr->va_size)
175cfefd687SGarrett Wollman 		return (EFAULT);
176cfefd687SGarrett Wollman 
177cfefd687SGarrett Wollman 	/*
178cfefd687SGarrett Wollman 	 * text/data/bss must not exceed limits
179cfefd687SGarrett Wollman 	 */
18091d5354aSJohn Baldwin 	PROC_LOCK(imgp->proc);
181cfefd687SGarrett Wollman 	if (/* text can't exceed maximum text size */
182cbc89bfbSPaul Saab 	    a_out->a_text > maxtsiz ||
183cfefd687SGarrett Wollman 
184cfefd687SGarrett Wollman 	    /* data + bss can't exceed rlimit */
18591d5354aSJohn Baldwin 	    a_out->a_data + bss_size > lim_cur(imgp->proc, RLIMIT_DATA)) {
18691d5354aSJohn Baldwin 			PROC_UNLOCK(imgp->proc);
187cfefd687SGarrett Wollman 			return (ENOMEM);
18891d5354aSJohn Baldwin 	}
18991d5354aSJohn Baldwin 	PROC_UNLOCK(imgp->proc);
190cfefd687SGarrett Wollman 
191cfefd687SGarrett Wollman 	/* copy in arguments and/or environment from old process */
192c52007c2SDavid Greenman 	error = exec_extract_strings(imgp);
193cfefd687SGarrett Wollman 	if (error)
194cfefd687SGarrett Wollman 		return (error);
195cfefd687SGarrett Wollman 
196cfefd687SGarrett Wollman 	/*
197cfefd687SGarrett Wollman 	 * Destroy old process VM and create a new one (with a new stack)
198cfefd687SGarrett Wollman 	 */
19905ba50f5SJake Burkholder 	exec_new_vmspace(imgp, &aout_sysvec);
200cfefd687SGarrett Wollman 
201cfefd687SGarrett Wollman 	/*
2025856e12eSJohn Dyson 	 * The vm space can be changed by exec_new_vmspace
2035856e12eSJohn Dyson 	 */
2045856e12eSJohn Dyson 	vmspace = imgp->proc->p_vmspace;
2055856e12eSJohn Dyson 
2061616db3cSJohn Dyson 	vp = imgp->vp;
2070b2ed1aeSJeff Roberson 	object = imgp->object;
2082f33b2c0SAlan Cox 	map = &vmspace->vm_map;
2092f33b2c0SAlan Cox 	vm_map_lock(map);
2101616db3cSJohn Dyson 	vm_object_reference(object);
2111616db3cSJohn Dyson 
2121616db3cSJohn Dyson 	text_end = virtual_offset + a_out->a_text;
2130a91231dSAlan Cox 	error = vm_map_insert(map, object,
2141616db3cSJohn Dyson 		file_offset,
2151616db3cSJohn Dyson 		virtual_offset, text_end,
2161616db3cSJohn Dyson 		VM_PROT_READ | VM_PROT_EXECUTE, VM_PROT_ALL,
217e972780aSAlan Cox 		MAP_COPY_ON_WRITE | MAP_PREFAULT);
2182f33b2c0SAlan Cox 	if (error) {
2192f33b2c0SAlan Cox 		vm_map_unlock(map);
220cfefd687SGarrett Wollman 		return (error);
2212f33b2c0SAlan Cox 	}
2221616db3cSJohn Dyson 	data_end = text_end + a_out->a_data;
2231616db3cSJohn Dyson 	if (a_out->a_data) {
2241616db3cSJohn Dyson 		vm_object_reference(object);
2250a91231dSAlan Cox 		error = vm_map_insert(map, object,
2261616db3cSJohn Dyson 			file_offset + a_out->a_text,
2271616db3cSJohn Dyson 			text_end, data_end,
2281616db3cSJohn Dyson 			VM_PROT_ALL, VM_PROT_ALL,
229e972780aSAlan Cox 			MAP_COPY_ON_WRITE | MAP_PREFAULT);
2302f33b2c0SAlan Cox 		if (error) {
2312f33b2c0SAlan Cox 			vm_map_unlock(map);
2321616db3cSJohn Dyson 			return (error);
2331616db3cSJohn Dyson 		}
2342f33b2c0SAlan Cox 	}
235cfefd687SGarrett Wollman 
2361616db3cSJohn Dyson 	if (bss_size) {
2370a91231dSAlan Cox 		error = vm_map_insert(map, NULL, 0,
2381616db3cSJohn Dyson 			data_end, data_end + bss_size,
2391616db3cSJohn Dyson 			VM_PROT_ALL, VM_PROT_ALL, 0);
2402f33b2c0SAlan Cox 		if (error) {
2412f33b2c0SAlan Cox 			vm_map_unlock(map);
242cfefd687SGarrett Wollman 			return (error);
24368940ac1SDavid Greenman 		}
2442f33b2c0SAlan Cox 	}
2452f33b2c0SAlan Cox 	vm_map_unlock(map);
246cfefd687SGarrett Wollman 
247cfefd687SGarrett Wollman 	/* Fill in process VM information */
248cfefd687SGarrett Wollman 	vmspace->vm_tsize = a_out->a_text >> PAGE_SHIFT;
249cfefd687SGarrett Wollman 	vmspace->vm_dsize = (a_out->a_data + bss_size) >> PAGE_SHIFT;
2507cd99438SBruce Evans 	vmspace->vm_taddr = (caddr_t) (uintptr_t) virtual_offset;
2517cd99438SBruce Evans 	vmspace->vm_daddr = (caddr_t) (uintptr_t)
2527cd99438SBruce Evans 			    (virtual_offset + a_out->a_text);
253cfefd687SGarrett Wollman 
254cfefd687SGarrett Wollman 	/* Fill in image_params */
255c52007c2SDavid Greenman 	imgp->interpreted = 0;
256c52007c2SDavid Greenman 	imgp->entry_addr = a_out->a_entry;
257cfefd687SGarrett Wollman 
258c52007c2SDavid Greenman 	imgp->proc->p_sysent = &aout_sysvec;
259c0e5de7dSDavid Greenman 
260cfefd687SGarrett Wollman 	return (0);
261cfefd687SGarrett Wollman }
26292d91f76SGarrett Wollman 
26392d91f76SGarrett Wollman /*
2649fe42598SBruce Evans  * Dump core, into a file named as described in the comments for
2659fe42598SBruce Evans  * expand_name(), unless the process was setuid/setgid.
26622d4b0fbSJohn Polstra  */
26722d4b0fbSJohn Polstra int
268b40ce416SJulian Elischer aout_coredump(td, vp, limit)
269b40ce416SJulian Elischer 	register struct thread *td;
27022d4b0fbSJohn Polstra 	register struct vnode *vp;
271fca666a1SJulian Elischer 	off_t limit;
272fca666a1SJulian Elischer {
273b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
274a854ed98SJohn Baldwin 	register struct ucred *cred = td->td_ucred;
27522d4b0fbSJohn Polstra 	register struct vmspace *vm = p->p_vmspace;
276a9f9df5dSPeter Wemm 	char *tempuser;
277b9e91a85SBruce Evans 	int error;
27822d4b0fbSJohn Polstra 
27999a17113SPeter Wemm 	if (ctob((uarea_pages + kstack_pages)
280b40ce416SJulian Elischer 	    + vm->vm_dsize + vm->vm_ssize) >= limit)
28122d4b0fbSJohn Polstra 		return (EFAULT);
28299a17113SPeter Wemm 	tempuser = malloc(ctob(uarea_pages + kstack_pages), M_TEMP,
283a163d034SWarner Losh 	    M_WAITOK | M_ZERO);
284710ded3aSPeter Wemm 	if (tempuser == NULL)
285710ded3aSPeter Wemm 		return (ENOMEM);
286a9f9df5dSPeter Wemm 	PROC_LOCK(p);
287a9f9df5dSPeter Wemm 	fill_kinfo_proc(p, &p->p_uarea->u_kproc);
288a9f9df5dSPeter Wemm 	PROC_UNLOCK(p);
289710ded3aSPeter Wemm 	bcopy(p->p_uarea, tempuser, sizeof(struct user));
290710ded3aSPeter Wemm 	bcopy(td->td_frame,
29199a17113SPeter Wemm 	    tempuser + ctob(uarea_pages) +
292710ded3aSPeter Wemm 	    ((caddr_t)td->td_frame - (caddr_t)td->td_kstack),
293710ded3aSPeter Wemm 	    sizeof(struct trapframe));
294710ded3aSPeter Wemm 	error = vn_rdwr(UIO_WRITE, vp, (caddr_t)tempuser,
29599a17113SPeter Wemm 	    ctob(uarea_pages + kstack_pages),
296710ded3aSPeter Wemm 	    (off_t)0, UIO_SYSSPACE, IO_UNIT, cred, NOCRED,
297710ded3aSPeter Wemm 	    (int *)NULL, td);
298710ded3aSPeter Wemm 	free(tempuser, M_TEMP);
29922d4b0fbSJohn Polstra 	if (error == 0)
300b40ce416SJulian Elischer 		error = vn_rdwr(UIO_WRITE, vp, vm->vm_daddr,
301b40ce416SJulian Elischer 		    (int)ctob(vm->vm_dsize),
30299a17113SPeter Wemm 		    (off_t)ctob(uarea_pages + kstack_pages), UIO_USERSPACE,
3039ca43589SRobert Watson 		    IO_UNIT | IO_DIRECT, cred, NOCRED, (int *) NULL, td);
30422d4b0fbSJohn Polstra 	if (error == 0)
30506ae1e91SMatthew Dillon 		error = vn_rdwr_inchunks(UIO_WRITE, vp,
30605ba50f5SJake Burkholder 		    (caddr_t)trunc_page(p->p_sysent->sv_usrstack -
30705ba50f5SJake Burkholder 		    ctob(vm->vm_ssize)), round_page(ctob(vm->vm_ssize)),
30899a17113SPeter Wemm 		    (off_t)ctob(uarea_pages + kstack_pages) +
309b40ce416SJulian Elischer 		        ctob(vm->vm_dsize), UIO_USERSPACE,
3109ca43589SRobert Watson 		    IO_UNIT | IO_DIRECT, cred, NOCRED, (int *) NULL, td);
311b9e91a85SBruce Evans 	return (error);
31222d4b0fbSJohn Polstra }
31322d4b0fbSJohn Polstra 
31422d4b0fbSJohn Polstra /*
31592d91f76SGarrett Wollman  * Tell kern_execve.c about it, with a little help from the linker.
31692d91f76SGarrett Wollman  */
317820ca326SMatthew Dillon static struct execsw aout_execsw = { exec_aout_imgact, "a.out" };
318aa855a59SPeter Wemm EXEC_SET(aout, aout_execsw);
319