imgact_aout.c revision 138128
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 138128 2004-11-27 06:46:59Z das $");
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
46103181Sbde#include <machine/frame.h>
4739154Sjdp#include <machine/md_var.h>
48885Swollman
491549Srgrimes#include <vm/vm.h>
5012662Sdg#include <vm/pmap.h>
5112662Sdg#include <vm/vm_map.h>
5232446Sdyson#include <vm/vm_object.h>
53103181Sbde#include <vm/vm_param.h>
54885Swollman
5592723Salfredstatic int	exec_aout_imgact(struct image_params *imgp);
56102808Sjakestatic int	aout_fixup(register_t **stack_base, struct image_params *imgp);
5712568Sbde
5839154Sjdpstruct sysentvec aout_sysvec = {
5939154Sjdp	SYS_MAXSYSCALL,
6039154Sjdp	sysent,
6139154Sjdp	0,
6239154Sjdp	0,
63102808Sjake	NULL,
6439154Sjdp	0,
65102808Sjake	NULL,
66102808Sjake	NULL,
67102808Sjake	aout_fixup,
6839154Sjdp	sendsig,
6939154Sjdp	sigcode,
7039154Sjdp	&szsigcode,
71102808Sjake	NULL,
7239154Sjdp	"FreeBSD a.out",
7368520Smarcel	NULL,
74138128Sdas	NULL,
75102808Sjake	MINSIGSTKSZ,
76102808Sjake	PAGE_SIZE,
77102808Sjake	VM_MIN_ADDRESS,
78102808Sjake	VM_MAXUSER_ADDRESS,
79102808Sjake	USRSTACK,
80102808Sjake	PS_STRINGS,
81102808Sjake	VM_PROT_ALL,
82102808Sjake	exec_copyout_strings,
83120422Speter	exec_setregs,
84120422Speter	NULL
8539154Sjdp};
8639154Sjdp
8750901Sbdestatic int
88102808Sjakeaout_fixup(stack_base, imgp)
89102808Sjake	register_t **stack_base;
90102808Sjake	struct image_params *imgp;
91102808Sjake{
92102808Sjake
93102808Sjake	return (suword(--(*stack_base), imgp->argc));
94102808Sjake}
95102808Sjake
96102808Sjakestatic int
9712130Sdgexec_aout_imgact(imgp)
9812130Sdg	struct image_params *imgp;
99885Swollman{
10017974Sbde	const struct exec *a_out = (const struct exec *) imgp->image_header;
10124848Sdyson	struct vmspace *vmspace;
10232446Sdyson	struct vnode *vp;
10344469Salc	vm_map_t map;
10432446Sdyson	vm_object_t object;
10532446Sdyson	vm_offset_t text_end, data_end;
10614703Sbde	unsigned long virtual_offset;
10712767Sdyson	unsigned long file_offset;
108885Swollman	unsigned long bss_size;
1093098Sphk	int error;
110885Swollman
11179224Sdillon	GIANT_REQUIRED;
11279224Sdillon
113885Swollman	/*
1146380Ssos	 * Linux and *BSD binaries look very much alike,
1158876Srgrimes	 * only the machine id is different:
1169202Srgrimes	 * 0x64 for Linux, 0x86 for *BSD, 0x00 for BSDI.
11714363Speter	 * NetBSD is in network byte order.. ugh.
1186380Ssos	 */
1199202Srgrimes	if (((a_out->a_magic >> 16) & 0xff) != 0x86 &&
12014363Speter	    ((a_out->a_magic >> 16) & 0xff) != 0 &&
12114363Speter	    ((((int)ntohl(a_out->a_magic)) >> 16) & 0xff) != 0x86)
1229202Srgrimes                return -1;
1236380Ssos
1246380Ssos	/*
125885Swollman	 * Set file/virtual offset based on a.out variant.
126885Swollman	 *	We do two cases: host byte order and network byte order
127885Swollman	 *	(for NetBSD compatibility)
128885Swollman	 */
129885Swollman	switch ((int)(a_out->a_magic & 0xffff)) {
130885Swollman	case ZMAGIC:
131885Swollman		virtual_offset = 0;
132885Swollman		if (a_out->a_text) {
13315538Sphk			file_offset = PAGE_SIZE;
134885Swollman		} else {
135885Swollman			/* Bill's "screwball mode" */
136885Swollman			file_offset = 0;
137885Swollman		}
138885Swollman		break;
139885Swollman	case QMAGIC:
14015538Sphk		virtual_offset = PAGE_SIZE;
141885Swollman		file_offset = 0;
14245270Sjdp		/* Pass PS_STRINGS for BSD/OS binaries only. */
14345270Sjdp		if (N_GETMID(*a_out) == MID_ZERO)
144103767Sjake			imgp->ps_strings = aout_sysvec.sv_psstrings;
145885Swollman		break;
146885Swollman	default:
147885Swollman		/* NetBSD compatibility */
148885Swollman		switch ((int)(ntohl(a_out->a_magic) & 0xffff)) {
149885Swollman		case ZMAGIC:
150885Swollman		case QMAGIC:
15115538Sphk			virtual_offset = PAGE_SIZE;
152885Swollman			file_offset = 0;
153885Swollman			break;
154885Swollman		default:
155885Swollman			return (-1);
156885Swollman		}
157885Swollman	}
158885Swollman
15915538Sphk	bss_size = roundup(a_out->a_bss, PAGE_SIZE);
160885Swollman
161885Swollman	/*
162885Swollman	 * Check various fields in header for validity/bounds.
163885Swollman	 */
164885Swollman	if (/* entry point must lay with text region */
165885Swollman	    a_out->a_entry < virtual_offset ||
166885Swollman	    a_out->a_entry >= virtual_offset + a_out->a_text ||
167885Swollman
168885Swollman	    /* text and data size must each be page rounded */
16915538Sphk	    a_out->a_text & PAGE_MASK || a_out->a_data & PAGE_MASK)
170885Swollman		return (-1);
171885Swollman
172885Swollman	/* text + data can't exceed file size */
17312130Sdg	if (a_out->a_data + a_out->a_text > imgp->attr->va_size)
174885Swollman		return (EFAULT);
175885Swollman
176885Swollman	/*
177885Swollman	 * text/data/bss must not exceed limits
178885Swollman	 */
179125454Sjhb	PROC_LOCK(imgp->proc);
180885Swollman	if (/* text can't exceed maximum text size */
18184783Sps	    a_out->a_text > maxtsiz ||
182885Swollman
183885Swollman	    /* data + bss can't exceed rlimit */
184125454Sjhb	    a_out->a_data + bss_size > lim_cur(imgp->proc, RLIMIT_DATA)) {
185125454Sjhb			PROC_UNLOCK(imgp->proc);
186885Swollman			return (ENOMEM);
187125454Sjhb	}
188125454Sjhb	PROC_UNLOCK(imgp->proc);
189885Swollman
190885Swollman	/* copy in arguments and/or environment from old process */
19112130Sdg	error = exec_extract_strings(imgp);
192885Swollman	if (error)
193885Swollman		return (error);
194885Swollman
195885Swollman	/*
196885Swollman	 * Destroy old process VM and create a new one (with a new stack)
197885Swollman	 */
198103767Sjake	exec_new_vmspace(imgp, &aout_sysvec);
199885Swollman
200885Swollman	/*
20124848Sdyson	 * The vm space can be changed by exec_new_vmspace
20224848Sdyson	 */
20324848Sdyson	vmspace = imgp->proc->p_vmspace;
20424848Sdyson
20532446Sdyson	vp = imgp->vp;
20699487Sjeff	object = imgp->object;
20744469Salc	map = &vmspace->vm_map;
20844469Salc	vm_map_lock(map);
20932446Sdyson	vm_object_reference(object);
21032446Sdyson
21132446Sdyson	text_end = virtual_offset + a_out->a_text;
21244626Salc	error = vm_map_insert(map, object,
21332446Sdyson		file_offset,
21432446Sdyson		virtual_offset, text_end,
21532446Sdyson		VM_PROT_READ | VM_PROT_EXECUTE, VM_PROT_ALL,
21647258Salc		MAP_COPY_ON_WRITE | MAP_PREFAULT);
21744469Salc	if (error) {
21844469Salc		vm_map_unlock(map);
219885Swollman		return (error);
22044469Salc	}
22132446Sdyson	data_end = text_end + a_out->a_data;
22232446Sdyson	if (a_out->a_data) {
22332446Sdyson		vm_object_reference(object);
22444626Salc		error = vm_map_insert(map, object,
22532446Sdyson			file_offset + a_out->a_text,
22632446Sdyson			text_end, data_end,
22732446Sdyson			VM_PROT_ALL, VM_PROT_ALL,
22847258Salc			MAP_COPY_ON_WRITE | MAP_PREFAULT);
22944469Salc		if (error) {
23044469Salc			vm_map_unlock(map);
23132446Sdyson			return (error);
23244469Salc		}
23332446Sdyson	}
234885Swollman
23532446Sdyson	if (bss_size) {
23644626Salc		error = vm_map_insert(map, NULL, 0,
23732446Sdyson			data_end, data_end + bss_size,
23832446Sdyson			VM_PROT_ALL, VM_PROT_ALL, 0);
23944469Salc		if (error) {
24044469Salc			vm_map_unlock(map);
2416579Sdg			return (error);
24244469Salc		}
2436579Sdg	}
24444469Salc	vm_map_unlock(map);
24544469Salc
246885Swollman	/* Fill in process VM information */
247885Swollman	vmspace->vm_tsize = a_out->a_text >> PAGE_SHIFT;
248885Swollman	vmspace->vm_dsize = (a_out->a_data + bss_size) >> PAGE_SHIFT;
24937656Sbde	vmspace->vm_taddr = (caddr_t) (uintptr_t) virtual_offset;
25037656Sbde	vmspace->vm_daddr = (caddr_t) (uintptr_t)
25137656Sbde			    (virtual_offset + a_out->a_text);
252885Swollman
253885Swollman	/* Fill in image_params */
25412130Sdg	imgp->interpreted = 0;
25512130Sdg	imgp->entry_addr = a_out->a_entry;
2568876Srgrimes
25712130Sdg	imgp->proc->p_sysent = &aout_sysvec;
25810221Sdg
259885Swollman	return (0);
260885Swollman}
261886Swollman
262886Swollman/*
263886Swollman * Tell kern_execve.c about it, with a little help from the linker.
264886Swollman */
26543402Sdillonstatic struct execsw aout_execsw = { exec_aout_imgact, "a.out" };
26640435SpeterEXEC_SET(aout, aout_execsw);
267