imgact_aout.c revision 175202
1139804Simp/*-
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 175202 2008-01-10 01:10:58Z attilio $");
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
93140992Ssobomax	return (suword(--(*stack_base), imgp->args->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;
10244469Salc	vm_map_t map;
10332446Sdyson	vm_object_t object;
10432446Sdyson	vm_offset_t text_end, data_end;
10514703Sbde	unsigned long virtual_offset;
10612767Sdyson	unsigned long file_offset;
107885Swollman	unsigned long bss_size;
1083098Sphk	int error;
109885Swollman
110885Swollman	/*
1116380Ssos	 * Linux and *BSD binaries look very much alike,
1128876Srgrimes	 * only the machine id is different:
1139202Srgrimes	 * 0x64 for Linux, 0x86 for *BSD, 0x00 for BSDI.
11414363Speter	 * NetBSD is in network byte order.. ugh.
1156380Ssos	 */
1169202Srgrimes	if (((a_out->a_magic >> 16) & 0xff) != 0x86 &&
11714363Speter	    ((a_out->a_magic >> 16) & 0xff) != 0 &&
11814363Speter	    ((((int)ntohl(a_out->a_magic)) >> 16) & 0xff) != 0x86)
1199202Srgrimes                return -1;
1206380Ssos
1216380Ssos	/*
122885Swollman	 * Set file/virtual offset based on a.out variant.
123885Swollman	 *	We do two cases: host byte order and network byte order
124885Swollman	 *	(for NetBSD compatibility)
125885Swollman	 */
126885Swollman	switch ((int)(a_out->a_magic & 0xffff)) {
127885Swollman	case ZMAGIC:
128885Swollman		virtual_offset = 0;
129885Swollman		if (a_out->a_text) {
13015538Sphk			file_offset = PAGE_SIZE;
131885Swollman		} else {
132885Swollman			/* Bill's "screwball mode" */
133885Swollman			file_offset = 0;
134885Swollman		}
135885Swollman		break;
136885Swollman	case QMAGIC:
13715538Sphk		virtual_offset = PAGE_SIZE;
138885Swollman		file_offset = 0;
13945270Sjdp		/* Pass PS_STRINGS for BSD/OS binaries only. */
14045270Sjdp		if (N_GETMID(*a_out) == MID_ZERO)
141103767Sjake			imgp->ps_strings = aout_sysvec.sv_psstrings;
142885Swollman		break;
143885Swollman	default:
144885Swollman		/* NetBSD compatibility */
145885Swollman		switch ((int)(ntohl(a_out->a_magic) & 0xffff)) {
146885Swollman		case ZMAGIC:
147885Swollman		case QMAGIC:
14815538Sphk			virtual_offset = PAGE_SIZE;
149885Swollman			file_offset = 0;
150885Swollman			break;
151885Swollman		default:
152885Swollman			return (-1);
153885Swollman		}
154885Swollman	}
155885Swollman
15615538Sphk	bss_size = roundup(a_out->a_bss, PAGE_SIZE);
157885Swollman
158885Swollman	/*
159885Swollman	 * Check various fields in header for validity/bounds.
160885Swollman	 */
161885Swollman	if (/* entry point must lay with text region */
162885Swollman	    a_out->a_entry < virtual_offset ||
163885Swollman	    a_out->a_entry >= virtual_offset + a_out->a_text ||
164885Swollman
165885Swollman	    /* text and data size must each be page rounded */
16615538Sphk	    a_out->a_text & PAGE_MASK || a_out->a_data & PAGE_MASK)
167885Swollman		return (-1);
168885Swollman
169885Swollman	/* text + data can't exceed file size */
17012130Sdg	if (a_out->a_data + a_out->a_text > imgp->attr->va_size)
171885Swollman		return (EFAULT);
172885Swollman
173885Swollman	/*
174885Swollman	 * text/data/bss must not exceed limits
175885Swollman	 */
176125454Sjhb	PROC_LOCK(imgp->proc);
177885Swollman	if (/* text can't exceed maximum text size */
17884783Sps	    a_out->a_text > maxtsiz ||
179885Swollman
180885Swollman	    /* data + bss can't exceed rlimit */
181125454Sjhb	    a_out->a_data + bss_size > lim_cur(imgp->proc, RLIMIT_DATA)) {
182125454Sjhb			PROC_UNLOCK(imgp->proc);
183885Swollman			return (ENOMEM);
184125454Sjhb	}
185125454Sjhb	PROC_UNLOCK(imgp->proc);
186885Swollman
187885Swollman	/*
188153698Salc	 * Avoid a possible deadlock if the current address space is destroyed
189153698Salc	 * and that address space maps the locked vnode.  In the common case,
190153698Salc	 * the locked vnode's v_usecount is decremented but remains greater
191153698Salc	 * than zero.  Consequently, the vnode lock is not needed by vrele().
192153698Salc	 * However, in cases where the vnode lock is external, such as nullfs,
193153698Salc	 * v_usecount may become zero.
194153698Salc	 */
195175202Sattilio	VOP_UNLOCK(imgp->vp, 0, curthread);
196153698Salc
197153698Salc	/*
198885Swollman	 * Destroy old process VM and create a new one (with a new stack)
199885Swollman	 */
200173361Skib	error = exec_new_vmspace(imgp, &aout_sysvec);
201885Swollman
202175202Sattilio	vn_lock(imgp->vp, LK_EXCLUSIVE | LK_RETRY);
203173361Skib	if (error)
204173361Skib		return (error);
205153698Salc
206885Swollman	/*
20724848Sdyson	 * The vm space can be changed by exec_new_vmspace
20824848Sdyson	 */
20924848Sdyson	vmspace = imgp->proc->p_vmspace;
21024848Sdyson
21199487Sjeff	object = imgp->object;
21244469Salc	map = &vmspace->vm_map;
21344469Salc	vm_map_lock(map);
21432446Sdyson	vm_object_reference(object);
21532446Sdyson
21632446Sdyson	text_end = virtual_offset + a_out->a_text;
21744626Salc	error = vm_map_insert(map, object,
21832446Sdyson		file_offset,
21932446Sdyson		virtual_offset, text_end,
22032446Sdyson		VM_PROT_READ | VM_PROT_EXECUTE, VM_PROT_ALL,
22147258Salc		MAP_COPY_ON_WRITE | MAP_PREFAULT);
22244469Salc	if (error) {
22344469Salc		vm_map_unlock(map);
224156766Salc		vm_object_deallocate(object);
225885Swollman		return (error);
22644469Salc	}
22732446Sdyson	data_end = text_end + a_out->a_data;
22832446Sdyson	if (a_out->a_data) {
22932446Sdyson		vm_object_reference(object);
23044626Salc		error = vm_map_insert(map, object,
23132446Sdyson			file_offset + a_out->a_text,
23232446Sdyson			text_end, data_end,
23332446Sdyson			VM_PROT_ALL, VM_PROT_ALL,
23447258Salc			MAP_COPY_ON_WRITE | MAP_PREFAULT);
23544469Salc		if (error) {
23644469Salc			vm_map_unlock(map);
237156766Salc			vm_object_deallocate(object);
23832446Sdyson			return (error);
23944469Salc		}
24032446Sdyson	}
241885Swollman
24232446Sdyson	if (bss_size) {
24344626Salc		error = vm_map_insert(map, NULL, 0,
24432446Sdyson			data_end, data_end + bss_size,
24532446Sdyson			VM_PROT_ALL, VM_PROT_ALL, 0);
24644469Salc		if (error) {
24744469Salc			vm_map_unlock(map);
2486579Sdg			return (error);
24944469Salc		}
2506579Sdg	}
25144469Salc	vm_map_unlock(map);
25244469Salc
253885Swollman	/* Fill in process VM information */
254885Swollman	vmspace->vm_tsize = a_out->a_text >> PAGE_SHIFT;
255885Swollman	vmspace->vm_dsize = (a_out->a_data + bss_size) >> PAGE_SHIFT;
25637656Sbde	vmspace->vm_taddr = (caddr_t) (uintptr_t) virtual_offset;
25737656Sbde	vmspace->vm_daddr = (caddr_t) (uintptr_t)
25837656Sbde			    (virtual_offset + a_out->a_text);
259885Swollman
260885Swollman	/* Fill in image_params */
26112130Sdg	imgp->interpreted = 0;
26212130Sdg	imgp->entry_addr = a_out->a_entry;
2638876Srgrimes
26412130Sdg	imgp->proc->p_sysent = &aout_sysvec;
26510221Sdg
266885Swollman	return (0);
267885Swollman}
268886Swollman
269886Swollman/*
270886Swollman * Tell kern_execve.c about it, with a little help from the linker.
271886Swollman */
27243402Sdillonstatic struct execsw aout_execsw = { exec_aout_imgact, "a.out" };
27340435SpeterEXEC_SET(aout, aout_execsw);
274