imgact_aout.c revision 140992
154359Sroberto/*-
254359Sroberto * Copyright (c) 1993, David Greenman
354359Sroberto * All rights reserved.
454359Sroberto *
554359Sroberto * Redistribution and use in source and binary forms, with or without
682498Sroberto * modification, are permitted provided that the following conditions
754359Sroberto * are met:
854359Sroberto * 1. Redistributions of source code must retain the above copyright
954359Sroberto *    notice, this list of conditions and the following disclaimer.
1054359Sroberto * 2. Redistributions in binary form must reproduce the above copyright
1154359Sroberto *    notice, this list of conditions and the following disclaimer in the
1254359Sroberto *    documentation and/or other materials provided with the distribution.
1354359Sroberto *
1454359Sroberto * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1554359Sroberto * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1654359Sroberto * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1754359Sroberto * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1854359Sroberto * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1954359Sroberto * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2054359Sroberto * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2154359Sroberto * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2254359Sroberto * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2354359Sroberto * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2454359Sroberto * SUCH DAMAGE.
2554359Sroberto */
2654359Sroberto
2754359Sroberto#include <sys/cdefs.h>
2854359Sroberto__FBSDID("$FreeBSD: head/sys/kern/imgact_aout.c 140992 2005-01-29 23:12:00Z sobomax $");
2954359Sroberto
3054359Sroberto#include <sys/param.h>
3154359Sroberto#include <sys/exec.h>
3254359Sroberto#include <sys/imgact.h>
3354359Sroberto#include <sys/imgact_aout.h>
3454359Sroberto#include <sys/kernel.h>
3554359Sroberto#include <sys/lock.h>
3654359Sroberto#include <sys/malloc.h>
3754359Sroberto#include <sys/mutex.h>
3854359Sroberto#include <sys/proc.h>
3954359Sroberto#include <sys/resourcevar.h>
4054359Sroberto#include <sys/signalvar.h>
4154359Sroberto#include <sys/syscall.h>
4254359Sroberto#include <sys/sysent.h>
4354359Sroberto#include <sys/systm.h>
4454359Sroberto#include <sys/vnode.h>
4554359Sroberto
4654359Sroberto#include <machine/frame.h>
4754359Sroberto#include <machine/md_var.h>
4854359Sroberto
4954359Sroberto#include <vm/vm.h>
5054359Sroberto#include <vm/pmap.h>
5154359Sroberto#include <vm/vm_map.h>
5254359Sroberto#include <vm/vm_object.h>
5354359Sroberto#include <vm/vm_param.h>
5454359Sroberto
5554359Srobertostatic int	exec_aout_imgact(struct image_params *imgp);
5654359Srobertostatic int	aout_fixup(register_t **stack_base, struct image_params *imgp);
5754359Sroberto
5854359Srobertostruct sysentvec aout_sysvec = {
5954359Sroberto	SYS_MAXSYSCALL,
6054359Sroberto	sysent,
6154359Sroberto	0,
6254359Sroberto	0,
6354359Sroberto	NULL,
6454359Sroberto	0,
6554359Sroberto	NULL,
6654359Sroberto	NULL,
6754359Sroberto	aout_fixup,
6854359Sroberto	sendsig,
6954359Sroberto	sigcode,
7054359Sroberto	&szsigcode,
7154359Sroberto	NULL,
7254359Sroberto	"FreeBSD a.out",
7354359Sroberto	NULL,
7454359Sroberto	NULL,
7554359Sroberto	MINSIGSTKSZ,
7654359Sroberto	PAGE_SIZE,
7754359Sroberto	VM_MIN_ADDRESS,
7854359Sroberto	VM_MAXUSER_ADDRESS,
7954359Sroberto	USRSTACK,
8054359Sroberto	PS_STRINGS,
8154359Sroberto	VM_PROT_ALL,
8254359Sroberto	exec_copyout_strings,
8354359Sroberto	exec_setregs,
8454359Sroberto	NULL
8554359Sroberto};
8654359Sroberto
8754359Srobertostatic int
8854359Srobertoaout_fixup(stack_base, imgp)
8954359Sroberto	register_t **stack_base;
9054359Sroberto	struct image_params *imgp;
9154359Sroberto{
9254359Sroberto
9354359Sroberto	return (suword(--(*stack_base), imgp->args->argc));
9454359Sroberto}
9554359Sroberto
9654359Srobertostatic int
9754359Srobertoexec_aout_imgact(imgp)
9854359Sroberto	struct image_params *imgp;
9954359Sroberto{
10054359Sroberto	const struct exec *a_out = (const struct exec *) imgp->image_header;
10154359Sroberto	struct vmspace *vmspace;
10254359Sroberto	struct vnode *vp;
10354359Sroberto	vm_map_t map;
10454359Sroberto	vm_object_t object;
10554359Sroberto	vm_offset_t text_end, data_end;
10654359Sroberto	unsigned long virtual_offset;
10754359Sroberto	unsigned long file_offset;
10854359Sroberto	unsigned long bss_size;
10954359Sroberto	int error;
11054359Sroberto
11154359Sroberto	GIANT_REQUIRED;
11254359Sroberto
11354359Sroberto	/*
11454359Sroberto	 * Linux and *BSD binaries look very much alike,
11554359Sroberto	 * only the machine id is different:
11654359Sroberto	 * 0x64 for Linux, 0x86 for *BSD, 0x00 for BSDI.
11754359Sroberto	 * NetBSD is in network byte order.. ugh.
11854359Sroberto	 */
11954359Sroberto	if (((a_out->a_magic >> 16) & 0xff) != 0x86 &&
12054359Sroberto	    ((a_out->a_magic >> 16) & 0xff) != 0 &&
12154359Sroberto	    ((((int)ntohl(a_out->a_magic)) >> 16) & 0xff) != 0x86)
12254359Sroberto                return -1;
12354359Sroberto
12454359Sroberto	/*
12554359Sroberto	 * Set file/virtual offset based on a.out variant.
12654359Sroberto	 *	We do two cases: host byte order and network byte order
12754359Sroberto	 *	(for NetBSD compatibility)
12854359Sroberto	 */
12954359Sroberto	switch ((int)(a_out->a_magic & 0xffff)) {
13054359Sroberto	case ZMAGIC:
13154359Sroberto		virtual_offset = 0;
13254359Sroberto		if (a_out->a_text) {
13354359Sroberto			file_offset = PAGE_SIZE;
13454359Sroberto		} else {
13554359Sroberto			/* Bill's "screwball mode" */
13654359Sroberto			file_offset = 0;
13754359Sroberto		}
13854359Sroberto		break;
13954359Sroberto	case QMAGIC:
14054359Sroberto		virtual_offset = PAGE_SIZE;
14154359Sroberto		file_offset = 0;
14254359Sroberto		/* Pass PS_STRINGS for BSD/OS binaries only. */
14354359Sroberto		if (N_GETMID(*a_out) == MID_ZERO)
14454359Sroberto			imgp->ps_strings = aout_sysvec.sv_psstrings;
14554359Sroberto		break;
14654359Sroberto	default:
14754359Sroberto		/* NetBSD compatibility */
14854359Sroberto		switch ((int)(ntohl(a_out->a_magic) & 0xffff)) {
14954359Sroberto		case ZMAGIC:
15054359Sroberto		case QMAGIC:
15154359Sroberto			virtual_offset = PAGE_SIZE;
15254359Sroberto			file_offset = 0;
15354359Sroberto			break;
15454359Sroberto		default:
15554359Sroberto			return (-1);
15654359Sroberto		}
15754359Sroberto	}
15854359Sroberto
15954359Sroberto	bss_size = roundup(a_out->a_bss, PAGE_SIZE);
16054359Sroberto
16154359Sroberto	/*
16254359Sroberto	 * Check various fields in header for validity/bounds.
16354359Sroberto	 */
16454359Sroberto	if (/* entry point must lay with text region */
16554359Sroberto	    a_out->a_entry < virtual_offset ||
16654359Sroberto	    a_out->a_entry >= virtual_offset + a_out->a_text ||
16754359Sroberto
16854359Sroberto	    /* text and data size must each be page rounded */
16954359Sroberto	    a_out->a_text & PAGE_MASK || a_out->a_data & PAGE_MASK)
17054359Sroberto		return (-1);
17154359Sroberto
17254359Sroberto	/* text + data can't exceed file size */
17354359Sroberto	if (a_out->a_data + a_out->a_text > imgp->attr->va_size)
17454359Sroberto		return (EFAULT);
17554359Sroberto
17654359Sroberto	/*
17754359Sroberto	 * text/data/bss must not exceed limits
17854359Sroberto	 */
17954359Sroberto	PROC_LOCK(imgp->proc);
18054359Sroberto	if (/* text can't exceed maximum text size */
18154359Sroberto	    a_out->a_text > maxtsiz ||
18254359Sroberto
18354359Sroberto	    /* data + bss can't exceed rlimit */
18454359Sroberto	    a_out->a_data + bss_size > lim_cur(imgp->proc, RLIMIT_DATA)) {
18554359Sroberto			PROC_UNLOCK(imgp->proc);
18654359Sroberto			return (ENOMEM);
18754359Sroberto	}
18854359Sroberto	PROC_UNLOCK(imgp->proc);
18954359Sroberto
19054359Sroberto	/*
19154359Sroberto	 * Destroy old process VM and create a new one (with a new stack)
19254359Sroberto	 */
19354359Sroberto	exec_new_vmspace(imgp, &aout_sysvec);
19454359Sroberto
19554359Sroberto	/*
19654359Sroberto	 * The vm space can be changed by exec_new_vmspace
19754359Sroberto	 */
19854359Sroberto	vmspace = imgp->proc->p_vmspace;
19954359Sroberto
20054359Sroberto	vp = imgp->vp;
20154359Sroberto	object = imgp->object;
20254359Sroberto	map = &vmspace->vm_map;
20354359Sroberto	vm_map_lock(map);
20454359Sroberto	vm_object_reference(object);
20554359Sroberto
20654359Sroberto	text_end = virtual_offset + a_out->a_text;
20754359Sroberto	error = vm_map_insert(map, object,
20854359Sroberto		file_offset,
20954359Sroberto		virtual_offset, text_end,
21054359Sroberto		VM_PROT_READ | VM_PROT_EXECUTE, VM_PROT_ALL,
21154359Sroberto		MAP_COPY_ON_WRITE | MAP_PREFAULT);
21254359Sroberto	if (error) {
21354359Sroberto		vm_map_unlock(map);
21454359Sroberto		return (error);
21554359Sroberto	}
21654359Sroberto	data_end = text_end + a_out->a_data;
21754359Sroberto	if (a_out->a_data) {
21854359Sroberto		vm_object_reference(object);
21954359Sroberto		error = vm_map_insert(map, object,
22054359Sroberto			file_offset + a_out->a_text,
22154359Sroberto			text_end, data_end,
22254359Sroberto			VM_PROT_ALL, VM_PROT_ALL,
22354359Sroberto			MAP_COPY_ON_WRITE | MAP_PREFAULT);
22454359Sroberto		if (error) {
22554359Sroberto			vm_map_unlock(map);
226			return (error);
227		}
228	}
229
230	if (bss_size) {
231		error = vm_map_insert(map, NULL, 0,
232			data_end, data_end + bss_size,
233			VM_PROT_ALL, VM_PROT_ALL, 0);
234		if (error) {
235			vm_map_unlock(map);
236			return (error);
237		}
238	}
239	vm_map_unlock(map);
240
241	/* Fill in process VM information */
242	vmspace->vm_tsize = a_out->a_text >> PAGE_SHIFT;
243	vmspace->vm_dsize = (a_out->a_data + bss_size) >> PAGE_SHIFT;
244	vmspace->vm_taddr = (caddr_t) (uintptr_t) virtual_offset;
245	vmspace->vm_daddr = (caddr_t) (uintptr_t)
246			    (virtual_offset + a_out->a_text);
247
248	/* Fill in image_params */
249	imgp->interpreted = 0;
250	imgp->entry_addr = a_out->a_entry;
251
252	imgp->proc->p_sysent = &aout_sysvec;
253
254	return (0);
255}
256
257/*
258 * Tell kern_execve.c about it, with a little help from the linker.
259 */
260static struct execsw aout_execsw = { exec_aout_imgact, "a.out" };
261EXEC_SET(aout, aout_execsw);
262