imgact_aout.c revision 120422
1885Swollman/*
2885Swollman * Copyright (c) 1993, David Greenman
3885Swollman * All rights reserved.
4885Swollman *
5885Swollman * Redistribution and use in source and binary forms, with or without
6885Swollman * modification, are permitted provided that the following conditions
7885Swollman * are met:
8885Swollman * 1. Redistributions of source code must retain the above copyright
9885Swollman *    notice, this list of conditions and the following disclaimer.
10885Swollman * 2. Redistributions in binary form must reproduce the above copyright
11885Swollman *    notice, this list of conditions and the following disclaimer in the
12885Swollman *    documentation and/or other materials provided with the distribution.
13885Swollman *
14885Swollman * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15885Swollman * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16885Swollman * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1710625Sdg * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18885Swollman * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19885Swollman * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20885Swollman * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21885Swollman * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22885Swollman * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23885Swollman * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24885Swollman * SUCH DAMAGE.
25885Swollman */
26885Swollman
27116182Sobrien#include <sys/cdefs.h>
28116182Sobrien__FBSDID("$FreeBSD: head/sys/kern/imgact_aout.c 120422 2003-09-25 01:10:26Z peter $");
29116182Sobrien
301549Srgrimes#include <sys/param.h>
311549Srgrimes#include <sys/exec.h>
321549Srgrimes#include <sys/imgact.h>
333058Sdg#include <sys/imgact_aout.h>
341549Srgrimes#include <sys/kernel.h>
3576166Smarkm#include <sys/lock.h>
36103181Sbde#include <sys/malloc.h>
3776166Smarkm#include <sys/mutex.h>
3815494Sbde#include <sys/proc.h>
3976166Smarkm#include <sys/resourcevar.h>
4039154Sjdp#include <sys/signalvar.h>
41103181Sbde#include <sys/syscall.h>
422257Ssos#include <sys/sysent.h>
43103181Sbde#include <sys/systm.h>
4415494Sbde#include <sys/vnode.h>
4576166Smarkm#include <sys/user.h>
4676166Smarkm
47103181Sbde#include <machine/frame.h>
4839154Sjdp#include <machine/md_var.h>
49885Swollman
501549Srgrimes#include <vm/vm.h>
5112662Sdg#include <vm/pmap.h>
5212662Sdg#include <vm/vm_map.h>
5332446Sdyson#include <vm/vm_object.h>
54103181Sbde#include <vm/vm_param.h>
55885Swollman
5692723Salfredstatic int	exec_aout_imgact(struct image_params *imgp);
57102808Sjakestatic int	aout_fixup(register_t **stack_base, struct image_params *imgp);
5812568Sbde
5939154Sjdpstruct sysentvec aout_sysvec = {
6039154Sjdp	SYS_MAXSYSCALL,
6139154Sjdp	sysent,
6239154Sjdp	0,
6339154Sjdp	0,
64102808Sjake	NULL,
6539154Sjdp	0,
66102808Sjake	NULL,
67102808Sjake	NULL,
68102808Sjake	aout_fixup,
6939154Sjdp	sendsig,
7039154Sjdp	sigcode,
7139154Sjdp	&szsigcode,
72102808Sjake	NULL,
7339154Sjdp	"FreeBSD a.out",
7468520Smarcel	aout_coredump,
7568520Smarcel	NULL,
76102808Sjake	MINSIGSTKSZ,
77102808Sjake	PAGE_SIZE,
78102808Sjake	VM_MIN_ADDRESS,
79102808Sjake	VM_MAXUSER_ADDRESS,
80102808Sjake	USRSTACK,
81102808Sjake	PS_STRINGS,
82102808Sjake	VM_PROT_ALL,
83102808Sjake	exec_copyout_strings,
84120422Speter	exec_setregs,
85120422Speter	NULL
8639154Sjdp};
8739154Sjdp
8850901Sbdestatic int
89102808Sjakeaout_fixup(stack_base, imgp)
90102808Sjake	register_t **stack_base;
91102808Sjake	struct image_params *imgp;
92102808Sjake{
93102808Sjake
94102808Sjake	return (suword(--(*stack_base), imgp->argc));
95102808Sjake}
96102808Sjake
97102808Sjakestatic int
9812130Sdgexec_aout_imgact(imgp)
9912130Sdg	struct image_params *imgp;
100885Swollman{
10117974Sbde	const struct exec *a_out = (const struct exec *) imgp->image_header;
10224848Sdyson	struct vmspace *vmspace;
10332446Sdyson	struct vnode *vp;
10444469Salc	vm_map_t map;
10532446Sdyson	vm_object_t object;
10632446Sdyson	vm_offset_t text_end, data_end;
10714703Sbde	unsigned long virtual_offset;
10812767Sdyson	unsigned long file_offset;
109885Swollman	unsigned long bss_size;
1103098Sphk	int error;
111885Swollman
11279224Sdillon	GIANT_REQUIRED;
11379224Sdillon
114885Swollman	/*
1156380Ssos	 * Linux and *BSD binaries look very much alike,
1168876Srgrimes	 * only the machine id is different:
1179202Srgrimes	 * 0x64 for Linux, 0x86 for *BSD, 0x00 for BSDI.
11814363Speter	 * NetBSD is in network byte order.. ugh.
1196380Ssos	 */
1209202Srgrimes	if (((a_out->a_magic >> 16) & 0xff) != 0x86 &&
12114363Speter	    ((a_out->a_magic >> 16) & 0xff) != 0 &&
12214363Speter	    ((((int)ntohl(a_out->a_magic)) >> 16) & 0xff) != 0x86)
1239202Srgrimes                return -1;
1246380Ssos
1256380Ssos	/*
126885Swollman	 * Set file/virtual offset based on a.out variant.
127885Swollman	 *	We do two cases: host byte order and network byte order
128885Swollman	 *	(for NetBSD compatibility)
129885Swollman	 */
130885Swollman	switch ((int)(a_out->a_magic & 0xffff)) {
131885Swollman	case ZMAGIC:
132885Swollman		virtual_offset = 0;
133885Swollman		if (a_out->a_text) {
13415538Sphk			file_offset = PAGE_SIZE;
135885Swollman		} else {
136885Swollman			/* Bill's "screwball mode" */
137885Swollman			file_offset = 0;
138885Swollman		}
139885Swollman		break;
140885Swollman	case QMAGIC:
14115538Sphk		virtual_offset = PAGE_SIZE;
142885Swollman		file_offset = 0;
14345270Sjdp		/* Pass PS_STRINGS for BSD/OS binaries only. */
14445270Sjdp		if (N_GETMID(*a_out) == MID_ZERO)
145103767Sjake			imgp->ps_strings = aout_sysvec.sv_psstrings;
146885Swollman		break;
147885Swollman	default:
148885Swollman		/* NetBSD compatibility */
149885Swollman		switch ((int)(ntohl(a_out->a_magic) & 0xffff)) {
150885Swollman		case ZMAGIC:
151885Swollman		case QMAGIC:
15215538Sphk			virtual_offset = PAGE_SIZE;
153885Swollman			file_offset = 0;
154885Swollman			break;
155885Swollman		default:
156885Swollman			return (-1);
157885Swollman		}
158885Swollman	}
159885Swollman
16015538Sphk	bss_size = roundup(a_out->a_bss, PAGE_SIZE);
161885Swollman
162885Swollman	/*
163885Swollman	 * Check various fields in header for validity/bounds.
164885Swollman	 */
165885Swollman	if (/* entry point must lay with text region */
166885Swollman	    a_out->a_entry < virtual_offset ||
167885Swollman	    a_out->a_entry >= virtual_offset + a_out->a_text ||
168885Swollman
169885Swollman	    /* text and data size must each be page rounded */
17015538Sphk	    a_out->a_text & PAGE_MASK || a_out->a_data & PAGE_MASK)
171885Swollman		return (-1);
172885Swollman
173885Swollman	/* text + data can't exceed file size */
17412130Sdg	if (a_out->a_data + a_out->a_text > imgp->attr->va_size)
175885Swollman		return (EFAULT);
176885Swollman
177885Swollman	/*
178885Swollman	 * text/data/bss must not exceed limits
179885Swollman	 */
18071497Sjhb	mtx_assert(&Giant, MA_OWNED);
181885Swollman	if (/* text can't exceed maximum text size */
18284783Sps	    a_out->a_text > maxtsiz ||
183885Swollman
184885Swollman	    /* data + bss can't exceed rlimit */
185885Swollman	    a_out->a_data + bss_size >
18612130Sdg		imgp->proc->p_rlimit[RLIMIT_DATA].rlim_cur)
187885Swollman			return (ENOMEM);
188885Swollman
189885Swollman	/* copy in arguments and/or environment from old process */
19012130Sdg	error = exec_extract_strings(imgp);
191885Swollman	if (error)
192885Swollman		return (error);
193885Swollman
194885Swollman	/*
195885Swollman	 * Destroy old process VM and create a new one (with a new stack)
196885Swollman	 */
197103767Sjake	exec_new_vmspace(imgp, &aout_sysvec);
198885Swollman
199885Swollman	/*
20024848Sdyson	 * The vm space can be changed by exec_new_vmspace
20124848Sdyson	 */
20224848Sdyson	vmspace = imgp->proc->p_vmspace;
20324848Sdyson
20432446Sdyson	vp = imgp->vp;
20599487Sjeff	object = imgp->object;
20644469Salc	map = &vmspace->vm_map;
20744469Salc	vm_map_lock(map);
20832446Sdyson	vm_object_reference(object);
20932446Sdyson
21032446Sdyson	text_end = virtual_offset + a_out->a_text;
21144626Salc	error = vm_map_insert(map, object,
21232446Sdyson		file_offset,
21332446Sdyson		virtual_offset, text_end,
21432446Sdyson		VM_PROT_READ | VM_PROT_EXECUTE, VM_PROT_ALL,
21547258Salc		MAP_COPY_ON_WRITE | MAP_PREFAULT);
21644469Salc	if (error) {
21744469Salc		vm_map_unlock(map);
218885Swollman		return (error);
21944469Salc	}
22032446Sdyson	data_end = text_end + a_out->a_data;
22132446Sdyson	if (a_out->a_data) {
22232446Sdyson		vm_object_reference(object);
22344626Salc		error = vm_map_insert(map, object,
22432446Sdyson			file_offset + a_out->a_text,
22532446Sdyson			text_end, data_end,
22632446Sdyson			VM_PROT_ALL, VM_PROT_ALL,
22747258Salc			MAP_COPY_ON_WRITE | MAP_PREFAULT);
22844469Salc		if (error) {
22944469Salc			vm_map_unlock(map);
23032446Sdyson			return (error);
23144469Salc		}
23232446Sdyson	}
233885Swollman
23432446Sdyson	if (bss_size) {
23544626Salc		error = vm_map_insert(map, NULL, 0,
23632446Sdyson			data_end, data_end + bss_size,
23732446Sdyson			VM_PROT_ALL, VM_PROT_ALL, 0);
23844469Salc		if (error) {
23944469Salc			vm_map_unlock(map);
2406579Sdg			return (error);
24144469Salc		}
2426579Sdg	}
24344469Salc	vm_map_unlock(map);
24444469Salc
245885Swollman	/* Fill in process VM information */
246885Swollman	vmspace->vm_tsize = a_out->a_text >> PAGE_SHIFT;
247885Swollman	vmspace->vm_dsize = (a_out->a_data + bss_size) >> PAGE_SHIFT;
24837656Sbde	vmspace->vm_taddr = (caddr_t) (uintptr_t) virtual_offset;
24937656Sbde	vmspace->vm_daddr = (caddr_t) (uintptr_t)
25037656Sbde			    (virtual_offset + a_out->a_text);
251885Swollman
252885Swollman	/* Fill in image_params */
25312130Sdg	imgp->interpreted = 0;
25412130Sdg	imgp->entry_addr = a_out->a_entry;
2558876Srgrimes
25612130Sdg	imgp->proc->p_sysent = &aout_sysvec;
25710221Sdg
258885Swollman	return (0);
259885Swollman}
260886Swollman
261886Swollman/*
26242237Sbde * Dump core, into a file named as described in the comments for
26342237Sbde * expand_name(), unless the process was setuid/setgid.
26439154Sjdp */
26539154Sjdpint
26683366Sjulianaout_coredump(td, vp, limit)
26783366Sjulian	register struct thread *td;
26850717Sjulian	register struct vnode *vp;
26950717Sjulian	off_t limit;
27039154Sjdp{
27183366Sjulian	struct proc *p = td->td_proc;
27291406Sjhb	register struct ucred *cred = td->td_ucred;
27339154Sjdp	register struct vmspace *vm = p->p_vmspace;
274103086Speter	char *tempuser;
27550901Sbde	int error;
27639154Sjdp
277103084Speter	if (ctob((uarea_pages + kstack_pages)
27883366Sjulian	    + vm->vm_dsize + vm->vm_ssize) >= limit)
27939154Sjdp		return (EFAULT);
280103084Speter	tempuser = malloc(ctob(uarea_pages + kstack_pages), M_TEMP,
281111119Simp	    M_WAITOK | M_ZERO);
282103047Speter	if (tempuser == NULL)
283103047Speter		return (ENOMEM);
284103086Speter	PROC_LOCK(p);
285103086Speter	fill_kinfo_proc(p, &p->p_uarea->u_kproc);
286103086Speter	PROC_UNLOCK(p);
287103047Speter	bcopy(p->p_uarea, tempuser, sizeof(struct user));
288103047Speter	bcopy(td->td_frame,
289103084Speter	    tempuser + ctob(uarea_pages) +
290103086Speter	    ((caddr_t)td->td_frame - (caddr_t)td->td_kstack),
291103047Speter	    sizeof(struct trapframe));
292103086Speter	error = vn_rdwr(UIO_WRITE, vp, (caddr_t)tempuser,
293103084Speter	    ctob(uarea_pages + kstack_pages),
294103047Speter	    (off_t)0, UIO_SYSSPACE, IO_UNIT, cred, NOCRED,
295103047Speter	    (int *)NULL, td);
296103047Speter	free(tempuser, M_TEMP);
29739154Sjdp	if (error == 0)
29883366Sjulian		error = vn_rdwr(UIO_WRITE, vp, vm->vm_daddr,
29983366Sjulian		    (int)ctob(vm->vm_dsize),
300103084Speter		    (off_t)ctob(uarea_pages + kstack_pages), UIO_USERSPACE,
301101941Srwatson		    IO_UNIT | IO_DIRECT, cred, NOCRED, (int *) NULL, td);
30239154Sjdp	if (error == 0)
30383222Sdillon		error = vn_rdwr_inchunks(UIO_WRITE, vp,
304103767Sjake		    (caddr_t)trunc_page(p->p_sysent->sv_usrstack -
305103767Sjake		    ctob(vm->vm_ssize)), round_page(ctob(vm->vm_ssize)),
306103084Speter		    (off_t)ctob(uarea_pages + kstack_pages) +
30783366Sjulian		        ctob(vm->vm_dsize), UIO_USERSPACE,
308101941Srwatson		    IO_UNIT | IO_DIRECT, cred, NOCRED, (int *) NULL, td);
30950901Sbde	return (error);
31039154Sjdp}
31139154Sjdp
31239154Sjdp/*
313886Swollman * Tell kern_execve.c about it, with a little help from the linker.
314886Swollman */
31543402Sdillonstatic struct execsw aout_execsw = { exec_aout_imgact, "a.out" };
31640435SpeterEXEC_SET(aout, aout_execsw);
317