imgact_aout.c revision 50717
150974Swpaul/*
250974Swpaul * Copyright (c) 1993, David Greenman
350974Swpaul * All rights reserved.
450974Swpaul *
550974Swpaul * Redistribution and use in source and binary forms, with or without
650974Swpaul * modification, are permitted provided that the following conditions
750974Swpaul * are met:
850974Swpaul * 1. Redistributions of source code must retain the above copyright
950974Swpaul *    notice, this list of conditions and the following disclaimer.
1050974Swpaul * 2. Redistributions in binary form must reproduce the above copyright
1150974Swpaul *    notice, this list of conditions and the following disclaimer in the
1250974Swpaul *    documentation and/or other materials provided with the distribution.
1350974Swpaul *
1450974Swpaul * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1550974Swpaul * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1650974Swpaul * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1750974Swpaul * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1850974Swpaul * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1950974Swpaul * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2050974Swpaul * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2150974Swpaul * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2250974Swpaul * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2350974Swpaul * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2450974Swpaul * SUCH DAMAGE.
2550974Swpaul *
2650974Swpaul * $FreeBSD: head/sys/kern/imgact_aout.c 50717 1999-09-01 00:29:56Z julian $
2750974Swpaul */
2850974Swpaul
2950974Swpaul#include <sys/param.h>
3050974Swpaul#include <sys/acct.h>
3150974Swpaul#include <sys/resourcevar.h>
3250974Swpaul#include <sys/exec.h>
3350974Swpaul#include <sys/fcntl.h>
3450974Swpaul#include <sys/imgact.h>
3550974Swpaul#include <sys/imgact_aout.h>
3650974Swpaul#include <sys/kernel.h>
3750974Swpaul#include <sys/malloc.h>
3850974Swpaul#include <sys/namei.h>
3964963Swpaul#include <sys/pioctl.h>
4064963Swpaul#include <sys/proc.h>
4164963Swpaul#include <sys/signalvar.h>
4250974Swpaul#include <sys/stat.h>
4350974Swpaul#include <sys/sysent.h>
4450974Swpaul#include <sys/syscall.h>
4550974Swpaul#include <sys/vnode.h>
4650974Swpaul#include <sys/systm.h>
4750974Swpaul#include <machine/md_var.h>
4850974Swpaul
4950974Swpaul#include <vm/vm.h>
5050974Swpaul#include <vm/vm_param.h>
5150974Swpaul#include <vm/vm_prot.h>
5250974Swpaul#include <sys/lock.h>
5350974Swpaul#include <vm/pmap.h>
5450974Swpaul#include <vm/vm_map.h>
5550974Swpaul#include <vm/vm_object.h>
5650974Swpaul#include <sys/user.h>
5750974Swpaul
5850974Swpaulstatic int	exec_aout_imgact __P((struct image_params *imgp));
5950974Swpaul
6050974Swpaulstruct sysentvec aout_sysvec = {
6150974Swpaul	SYS_MAXSYSCALL,
6250974Swpaul	sysent,
6350974Swpaul	0,
6450974Swpaul	0,
6550974Swpaul	0,
6650974Swpaul	0,
6787059Sluigi	0,
6850974Swpaul	0,
6950974Swpaul	0,
7050974Swpaul	sendsig,
7150974Swpaul	sigcode,
7250974Swpaul	&szsigcode,
7350974Swpaul	0,
7487390Sjhay	"FreeBSD a.out",
7587390Sjhay	aout_coredump
7650974Swpaul};
7750974Swpaul
7850974Swpaulint
7950974Swpaulexec_aout_imgact(imgp)
8050974Swpaul	struct image_params *imgp;
8150974Swpaul{
8250974Swpaul	const struct exec *a_out = (const struct exec *) imgp->image_header;
8350974Swpaul	struct vmspace *vmspace;
8450974Swpaul	struct vnode *vp;
8550974Swpaul	vm_map_t map;
8650974Swpaul	vm_object_t object;
8750974Swpaul	vm_offset_t text_end, data_end;
8850974Swpaul	unsigned long virtual_offset;
8950974Swpaul	unsigned long file_offset;
9050974Swpaul	unsigned long bss_size;
9150974Swpaul	int error;
9250974Swpaul
9350974Swpaul	/*
9450974Swpaul	 * Linux and *BSD binaries look very much alike,
9550974Swpaul	 * only the machine id is different:
9659758Speter	 * 0x64 for Linux, 0x86 for *BSD, 0x00 for BSDI.
9759758Speter	 * NetBSD is in network byte order.. ugh.
9851089Speter	 */
9950974Swpaul	if (((a_out->a_magic >> 16) & 0xff) != 0x86 &&
10050974Swpaul	    ((a_out->a_magic >> 16) & 0xff) != 0 &&
10150974Swpaul	    ((((int)ntohl(a_out->a_magic)) >> 16) & 0xff) != 0x86)
10250974Swpaul                return -1;
10350974Swpaul
10450974Swpaul	/*
10550974Swpaul	 * Set file/virtual offset based on a.out variant.
10650974Swpaul	 *	We do two cases: host byte order and network byte order
10750974Swpaul	 *	(for NetBSD compatibility)
10850974Swpaul	 */
10950974Swpaul	switch ((int)(a_out->a_magic & 0xffff)) {
11050974Swpaul	case ZMAGIC:
11150974Swpaul		virtual_offset = 0;
11262672Swpaul		if (a_out->a_text) {
11350974Swpaul			file_offset = PAGE_SIZE;
11450974Swpaul		} else {
11550974Swpaul			/* Bill's "screwball mode" */
11692739Salfred			file_offset = 0;
11792739Salfred		}
11892739Salfred		break;
11950974Swpaul	case QMAGIC:
12092739Salfred		virtual_offset = PAGE_SIZE;
12192739Salfred		file_offset = 0;
12292739Salfred		/* Pass PS_STRINGS for BSD/OS binaries only. */
12392739Salfred		if (N_GETMID(*a_out) == MID_ZERO)
12492739Salfred			imgp->ps_strings = PS_STRINGS;
12592739Salfred		break;
12692739Salfred	default:
12792739Salfred		/* NetBSD compatibility */
12892739Salfred		switch ((int)(ntohl(a_out->a_magic) & 0xffff)) {
12992739Salfred		case ZMAGIC:
13092739Salfred		case QMAGIC:
13192739Salfred			virtual_offset = PAGE_SIZE;
13292739Salfred			file_offset = 0;
13392739Salfred			break;
13492739Salfred		default:
13592739Salfred			return (-1);
13692739Salfred		}
13750974Swpaul	}
13892739Salfred
13992739Salfred	bss_size = roundup(a_out->a_bss, PAGE_SIZE);
14092739Salfred
14192739Salfred	/*
14292739Salfred	 * Check various fields in header for validity/bounds.
14392739Salfred	 */
14472197Swpaul	if (/* entry point must lay with text region */
14592739Salfred	    a_out->a_entry < virtual_offset ||
14692739Salfred	    a_out->a_entry >= virtual_offset + a_out->a_text ||
14792739Salfred
14892739Salfred	    /* text and data size must each be page rounded */
14972197Swpaul	    a_out->a_text & PAGE_MASK || a_out->a_data & PAGE_MASK)
15072197Swpaul		return (-1);
15192739Salfred
15292739Salfred	/* text + data can't exceed file size */
15392739Salfred	if (a_out->a_data + a_out->a_text > imgp->attr->va_size)
15450974Swpaul		return (EFAULT);
15592739Salfred
15692739Salfred	/*
15792739Salfred	 * text/data/bss must not exceed limits
15892739Salfred	 */
15992739Salfred	if (/* text can't exceed maximum text size */
16092739Salfred	    a_out->a_text > MAXTSIZ ||
16150974Swpaul
16292739Salfred	    /* data + bss can't exceed rlimit */
16392739Salfred	    a_out->a_data + bss_size >
16492739Salfred		imgp->proc->p_rlimit[RLIMIT_DATA].rlim_cur)
16550974Swpaul			return (ENOMEM);
16650974Swpaul
16750974Swpaul	/* copy in arguments and/or environment from old process */
16850974Swpaul	error = exec_extract_strings(imgp);
16951030Swpaul	if (error)
17051030Swpaul		return (error);
17150974Swpaul
17250974Swpaul	/*
17350974Swpaul	 * Destroy old process VM and create a new one (with a new stack)
17450974Swpaul	 */
17550974Swpaul	exec_new_vmspace(imgp);
17650974Swpaul
17750974Swpaul	/*
17850974Swpaul	 * The vm space can be changed by exec_new_vmspace
17950974Swpaul	 */
18050974Swpaul	vmspace = imgp->proc->p_vmspace;
18150974Swpaul
18250974Swpaul	vp = imgp->vp;
18350974Swpaul	map = &vmspace->vm_map;
18450974Swpaul	vm_map_lock(map);
18550974Swpaul	object = vp->v_object;
18650974Swpaul	vm_object_reference(object);
18750974Swpaul
18850974Swpaul	text_end = virtual_offset + a_out->a_text;
18950974Swpaul	error = vm_map_insert(map, object,
19050974Swpaul		file_offset,
19150974Swpaul		virtual_offset, text_end,
19250974Swpaul		VM_PROT_READ | VM_PROT_EXECUTE, VM_PROT_ALL,
19351455Swpaul		MAP_COPY_ON_WRITE | MAP_PREFAULT);
19450974Swpaul	if (error) {
19550974Swpaul		vm_map_unlock(map);
19650974Swpaul		return (error);
19750974Swpaul	}
19850974Swpaul	data_end = text_end + a_out->a_data;
19950974Swpaul	if (a_out->a_data) {
20051533Swpaul		vm_object_reference(object);
20151473Swpaul		error = vm_map_insert(map, object,
20250974Swpaul			file_offset + a_out->a_text,
20350974Swpaul			text_end, data_end,
20450974Swpaul			VM_PROT_ALL, VM_PROT_ALL,
20550974Swpaul			MAP_COPY_ON_WRITE | MAP_PREFAULT);
20650974Swpaul		if (error) {
20750974Swpaul			vm_map_unlock(map);
20850974Swpaul			return (error);
20950974Swpaul		}
21050974Swpaul	}
21150974Swpaul
21250974Swpaul	if (bss_size) {
21350974Swpaul		error = vm_map_insert(map, NULL, 0,
21450974Swpaul			data_end, data_end + bss_size,
21550974Swpaul			VM_PROT_ALL, VM_PROT_ALL, 0);
21650974Swpaul		if (error) {
21781713Swpaul			vm_map_unlock(map);
21881713Swpaul			return (error);
21981713Swpaul		}
22081713Swpaul	}
22181713Swpaul	vm_map_unlock(map);
22281713Swpaul
22381713Swpaul	/* Fill in process VM information */
22481713Swpaul	vmspace->vm_tsize = a_out->a_text >> PAGE_SHIFT;
22581713Swpaul	vmspace->vm_dsize = (a_out->a_data + bss_size) >> PAGE_SHIFT;
22681713Swpaul	vmspace->vm_taddr = (caddr_t) (uintptr_t) virtual_offset;
22781713Swpaul	vmspace->vm_daddr = (caddr_t) (uintptr_t)
22881713Swpaul			    (virtual_offset + a_out->a_text);
22981713Swpaul
23081713Swpaul	/* Fill in image_params */
23181713Swpaul	imgp->interpreted = 0;
23281713Swpaul	imgp->entry_addr = a_out->a_entry;
23381713Swpaul
23481713Swpaul	imgp->proc->p_sysent = &aout_sysvec;
23581713Swpaul
23681713Swpaul	/* Indicate that this file should not be modified */
23781713Swpaul	imgp->vp->v_flag |= VTEXT;
23881713Swpaul
23981713Swpaul	return (0);
24081713Swpaul}
24181713Swpaul
24281713Swpaul/*
24381713Swpaul * Dump core, into a file named as described in the comments for
24481713Swpaul * expand_name(), unless the process was setuid/setgid.
24581713Swpaul */
24681713Swpaulint
24781713Swpaulaout_coredump(p, vp, limit)
24881713Swpaul	register struct proc *p;
24981713Swpaul	register struct vnode *vp;
25081713Swpaul	off_t limit;
25181713Swpaul{
25281713Swpaul	register struct ucred *cred = p->p_cred->pc_ucred;
25381713Swpaul	register struct vmspace *vm = p->p_vmspace;
25481713Swpaul	int error = 0;
25581713Swpaul
25681713Swpaul	if (ctob(UPAGES + vm->vm_dsize + vm->vm_ssize) >=
25781713Swpaul	    limit)
25881713Swpaul		return (EFAULT);
25962672Swpaul
26062672Swpaul	bcopy(p, &p->p_addr->u_kproc.kp_proc, sizeof(struct proc));
26162672Swpaul	fill_eproc(p, &p->p_addr->u_kproc.kp_eproc);
26262672Swpaul	error = cpu_coredump(p, vp, cred);
26362672Swpaul	if (error == 0)
26462672Swpaul		error = vn_rdwr(UIO_WRITE, vp, vm->vm_daddr,
26562672Swpaul		    (int)ctob(vm->vm_dsize), (off_t)ctob(UPAGES), UIO_USERSPACE,
26662672Swpaul		    IO_NODELOCKED|IO_UNIT, cred, (int *) NULL, p);
26762672Swpaul	if (error == 0)
26862672Swpaul		error = vn_rdwr(UIO_WRITE, vp,
26962672Swpaul		    (caddr_t) trunc_page(USRSTACK - ctob(vm->vm_ssize)),
27062672Swpaul		    round_page(ctob(vm->vm_ssize)),
27162672Swpaul		    (off_t)ctob(UPAGES) + ctob(vm->vm_dsize), UIO_USERSPACE,
27262672Swpaul		    IO_NODELOCKED|IO_UNIT, cred, (int *) NULL, p);
27362672Swpaul	return error;
27450974Swpaul}
27550974Swpaul
27650974Swpaul/*
27750974Swpaul * Tell kern_execve.c about it, with a little help from the linker.
27850974Swpaul */
27950974Swpaulstatic struct execsw aout_execsw = { exec_aout_imgact, "a.out" };
28050974SwpaulEXEC_SET(aout, aout_execsw);
28150974Swpaul