imgact_aout.c revision 68520
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 *
2650477Speter * $FreeBSD: head/sys/kern/imgact_aout.c 68520 2000-11-09 08:25:48Z marcel $
27885Swollman */
28885Swollman
291549Srgrimes#include <sys/param.h>
301549Srgrimes#include <sys/resourcevar.h>
311549Srgrimes#include <sys/exec.h>
3239154Sjdp#include <sys/fcntl.h>
331549Srgrimes#include <sys/imgact.h>
343058Sdg#include <sys/imgact_aout.h>
351549Srgrimes#include <sys/kernel.h>
3639154Sjdp#include <sys/namei.h>
3739154Sjdp#include <sys/pioctl.h>
3815494Sbde#include <sys/proc.h>
3965681Sdfr#include <sys/systm.h>
4039154Sjdp#include <sys/signalvar.h>
4139154Sjdp#include <sys/stat.h>
422257Ssos#include <sys/sysent.h>
4339154Sjdp#include <sys/syscall.h>
4415494Sbde#include <sys/vnode.h>
4539154Sjdp#include <machine/md_var.h>
46885Swollman
471549Srgrimes#include <vm/vm.h>
4812662Sdg#include <vm/vm_param.h>
4922521Sdyson#include <sys/lock.h>
5012662Sdg#include <vm/pmap.h>
5112662Sdg#include <vm/vm_map.h>
5232446Sdyson#include <vm/vm_object.h>
5339154Sjdp#include <sys/user.h>
54885Swollman
5512568Sbdestatic int	exec_aout_imgact __P((struct image_params *imgp));
5612568Sbde
5739154Sjdpstruct sysentvec aout_sysvec = {
5839154Sjdp	SYS_MAXSYSCALL,
5939154Sjdp	sysent,
6039154Sjdp	0,
6139154Sjdp	0,
6239154Sjdp	0,
6339154Sjdp	0,
6439154Sjdp	0,
6539154Sjdp	0,
6639154Sjdp	0,
6739154Sjdp	sendsig,
6839154Sjdp	sigcode,
6939154Sjdp	&szsigcode,
7039154Sjdp	0,
7139154Sjdp	"FreeBSD a.out",
7268520Smarcel	aout_coredump,
7368520Smarcel	NULL,
7468520Smarcel	MINSIGSTKSZ
7539154Sjdp};
7639154Sjdp
7750901Sbdestatic int
7812130Sdgexec_aout_imgact(imgp)
7912130Sdg	struct image_params *imgp;
80885Swollman{
8117974Sbde	const struct exec *a_out = (const struct exec *) imgp->image_header;
8224848Sdyson	struct vmspace *vmspace;
8332446Sdyson	struct vnode *vp;
8444469Salc	vm_map_t map;
8532446Sdyson	vm_object_t object;
8632446Sdyson	vm_offset_t text_end, data_end;
8714703Sbde	unsigned long virtual_offset;
8812767Sdyson	unsigned long file_offset;
89885Swollman	unsigned long bss_size;
903098Sphk	int error;
91885Swollman
92885Swollman	/*
936380Ssos	 * Linux and *BSD binaries look very much alike,
948876Srgrimes	 * only the machine id is different:
959202Srgrimes	 * 0x64 for Linux, 0x86 for *BSD, 0x00 for BSDI.
9614363Speter	 * NetBSD is in network byte order.. ugh.
976380Ssos	 */
989202Srgrimes	if (((a_out->a_magic >> 16) & 0xff) != 0x86 &&
9914363Speter	    ((a_out->a_magic >> 16) & 0xff) != 0 &&
10014363Speter	    ((((int)ntohl(a_out->a_magic)) >> 16) & 0xff) != 0x86)
1019202Srgrimes                return -1;
1026380Ssos
1036380Ssos	/*
104885Swollman	 * Set file/virtual offset based on a.out variant.
105885Swollman	 *	We do two cases: host byte order and network byte order
106885Swollman	 *	(for NetBSD compatibility)
107885Swollman	 */
108885Swollman	switch ((int)(a_out->a_magic & 0xffff)) {
109885Swollman	case ZMAGIC:
110885Swollman		virtual_offset = 0;
111885Swollman		if (a_out->a_text) {
11215538Sphk			file_offset = PAGE_SIZE;
113885Swollman		} else {
114885Swollman			/* Bill's "screwball mode" */
115885Swollman			file_offset = 0;
116885Swollman		}
117885Swollman		break;
118885Swollman	case QMAGIC:
11915538Sphk		virtual_offset = PAGE_SIZE;
120885Swollman		file_offset = 0;
12145270Sjdp		/* Pass PS_STRINGS for BSD/OS binaries only. */
12245270Sjdp		if (N_GETMID(*a_out) == MID_ZERO)
12345270Sjdp			imgp->ps_strings = PS_STRINGS;
124885Swollman		break;
125885Swollman	default:
126885Swollman		/* NetBSD compatibility */
127885Swollman		switch ((int)(ntohl(a_out->a_magic) & 0xffff)) {
128885Swollman		case ZMAGIC:
129885Swollman		case QMAGIC:
13015538Sphk			virtual_offset = PAGE_SIZE;
131885Swollman			file_offset = 0;
132885Swollman			break;
133885Swollman		default:
134885Swollman			return (-1);
135885Swollman		}
136885Swollman	}
137885Swollman
13815538Sphk	bss_size = roundup(a_out->a_bss, PAGE_SIZE);
139885Swollman
140885Swollman	/*
141885Swollman	 * Check various fields in header for validity/bounds.
142885Swollman	 */
143885Swollman	if (/* entry point must lay with text region */
144885Swollman	    a_out->a_entry < virtual_offset ||
145885Swollman	    a_out->a_entry >= virtual_offset + a_out->a_text ||
146885Swollman
147885Swollman	    /* text and data size must each be page rounded */
14815538Sphk	    a_out->a_text & PAGE_MASK || a_out->a_data & PAGE_MASK)
149885Swollman		return (-1);
150885Swollman
151885Swollman	/* text + data can't exceed file size */
15212130Sdg	if (a_out->a_data + a_out->a_text > imgp->attr->va_size)
153885Swollman		return (EFAULT);
154885Swollman
155885Swollman	/*
156885Swollman	 * text/data/bss must not exceed limits
157885Swollman	 */
158885Swollman	if (/* text can't exceed maximum text size */
159885Swollman	    a_out->a_text > MAXTSIZ ||
160885Swollman
161885Swollman	    /* data + bss can't exceed rlimit */
162885Swollman	    a_out->a_data + bss_size >
16312130Sdg		imgp->proc->p_rlimit[RLIMIT_DATA].rlim_cur)
164885Swollman			return (ENOMEM);
165885Swollman
166885Swollman	/* copy in arguments and/or environment from old process */
16712130Sdg	error = exec_extract_strings(imgp);
168885Swollman	if (error)
169885Swollman		return (error);
170885Swollman
171885Swollman	/*
172885Swollman	 * Destroy old process VM and create a new one (with a new stack)
173885Swollman	 */
17412130Sdg	exec_new_vmspace(imgp);
175885Swollman
176885Swollman	/*
17724848Sdyson	 * The vm space can be changed by exec_new_vmspace
17824848Sdyson	 */
17924848Sdyson	vmspace = imgp->proc->p_vmspace;
18024848Sdyson
18132446Sdyson	vp = imgp->vp;
18244469Salc	map = &vmspace->vm_map;
18344469Salc	vm_map_lock(map);
18465770Sbp	VOP_GETVOBJECT(vp, &object);
18532446Sdyson	vm_object_reference(object);
18632446Sdyson
18732446Sdyson	text_end = virtual_offset + a_out->a_text;
18844626Salc	error = vm_map_insert(map, object,
18932446Sdyson		file_offset,
19032446Sdyson		virtual_offset, text_end,
19132446Sdyson		VM_PROT_READ | VM_PROT_EXECUTE, VM_PROT_ALL,
19247258Salc		MAP_COPY_ON_WRITE | MAP_PREFAULT);
19344469Salc	if (error) {
19444469Salc		vm_map_unlock(map);
195885Swollman		return (error);
19644469Salc	}
19732446Sdyson	data_end = text_end + a_out->a_data;
19832446Sdyson	if (a_out->a_data) {
19932446Sdyson		vm_object_reference(object);
20044626Salc		error = vm_map_insert(map, object,
20132446Sdyson			file_offset + a_out->a_text,
20232446Sdyson			text_end, data_end,
20332446Sdyson			VM_PROT_ALL, VM_PROT_ALL,
20447258Salc			MAP_COPY_ON_WRITE | MAP_PREFAULT);
20544469Salc		if (error) {
20644469Salc			vm_map_unlock(map);
20732446Sdyson			return (error);
20844469Salc		}
20932446Sdyson	}
210885Swollman
21132446Sdyson	if (bss_size) {
21244626Salc		error = vm_map_insert(map, NULL, 0,
21332446Sdyson			data_end, data_end + bss_size,
21432446Sdyson			VM_PROT_ALL, VM_PROT_ALL, 0);
21544469Salc		if (error) {
21644469Salc			vm_map_unlock(map);
2176579Sdg			return (error);
21844469Salc		}
2196579Sdg	}
22044469Salc	vm_map_unlock(map);
22144469Salc
222885Swollman	/* Fill in process VM information */
223885Swollman	vmspace->vm_tsize = a_out->a_text >> PAGE_SHIFT;
224885Swollman	vmspace->vm_dsize = (a_out->a_data + bss_size) >> PAGE_SHIFT;
22537656Sbde	vmspace->vm_taddr = (caddr_t) (uintptr_t) virtual_offset;
22637656Sbde	vmspace->vm_daddr = (caddr_t) (uintptr_t)
22737656Sbde			    (virtual_offset + a_out->a_text);
228885Swollman
229885Swollman	/* Fill in image_params */
23012130Sdg	imgp->interpreted = 0;
23112130Sdg	imgp->entry_addr = a_out->a_entry;
2328876Srgrimes
23312130Sdg	imgp->proc->p_sysent = &aout_sysvec;
23410221Sdg
23510221Sdg	/* Indicate that this file should not be modified */
23612130Sdg	imgp->vp->v_flag |= VTEXT;
23710221Sdg
238885Swollman	return (0);
239885Swollman}
240886Swollman
241886Swollman/*
24242237Sbde * Dump core, into a file named as described in the comments for
24342237Sbde * expand_name(), unless the process was setuid/setgid.
24439154Sjdp */
24539154Sjdpint
24650717Sjulianaout_coredump(p, vp, limit)
24739154Sjdp	register struct proc *p;
24850717Sjulian	register struct vnode *vp;
24950717Sjulian	off_t limit;
25039154Sjdp{
25153503Sphk	register struct ucred *cred = p->p_ucred;
25239154Sjdp	register struct vmspace *vm = p->p_vmspace;
25350901Sbde	int error;
25439154Sjdp
25550901Sbde	if (ctob(UPAGES + vm->vm_dsize + vm->vm_ssize) >= limit)
25639154Sjdp		return (EFAULT);
25739154Sjdp	bcopy(p, &p->p_addr->u_kproc.kp_proc, sizeof(struct proc));
25839154Sjdp	fill_eproc(p, &p->p_addr->u_kproc.kp_eproc);
25939154Sjdp	error = cpu_coredump(p, vp, cred);
26039154Sjdp	if (error == 0)
26139154Sjdp		error = vn_rdwr(UIO_WRITE, vp, vm->vm_daddr,
26239154Sjdp		    (int)ctob(vm->vm_dsize), (off_t)ctob(UPAGES), UIO_USERSPACE,
26339154Sjdp		    IO_NODELOCKED|IO_UNIT, cred, (int *) NULL, p);
26439154Sjdp	if (error == 0)
26539154Sjdp		error = vn_rdwr(UIO_WRITE, vp,
26639154Sjdp		    (caddr_t) trunc_page(USRSTACK - ctob(vm->vm_ssize)),
26739154Sjdp		    round_page(ctob(vm->vm_ssize)),
26839154Sjdp		    (off_t)ctob(UPAGES) + ctob(vm->vm_dsize), UIO_USERSPACE,
26939154Sjdp		    IO_NODELOCKED|IO_UNIT, cred, (int *) NULL, p);
27050901Sbde	return (error);
27139154Sjdp}
27239154Sjdp
27339154Sjdp/*
274886Swollman * Tell kern_execve.c about it, with a little help from the linker.
275886Swollman */
27643402Sdillonstatic struct execsw aout_execsw = { exec_aout_imgact, "a.out" };
27740435SpeterEXEC_SET(aout, aout_execsw);
278