xref: /freebsd/sys/kern/imgact_aout.c (revision 0a91231d3be7476eeff8710033ad63436e928ba3)
1cfefd687SGarrett Wollman /*
2cfefd687SGarrett Wollman  * Copyright (c) 1993, David Greenman
3cfefd687SGarrett Wollman  * All rights reserved.
4cfefd687SGarrett Wollman  *
5cfefd687SGarrett Wollman  * Redistribution and use in source and binary forms, with or without
6cfefd687SGarrett Wollman  * modification, are permitted provided that the following conditions
7cfefd687SGarrett Wollman  * are met:
8cfefd687SGarrett Wollman  * 1. Redistributions of source code must retain the above copyright
9cfefd687SGarrett Wollman  *    notice, this list of conditions and the following disclaimer.
10cfefd687SGarrett Wollman  * 2. Redistributions in binary form must reproduce the above copyright
11cfefd687SGarrett Wollman  *    notice, this list of conditions and the following disclaimer in the
12cfefd687SGarrett Wollman  *    documentation and/or other materials provided with the distribution.
13cfefd687SGarrett Wollman  *
14cfefd687SGarrett Wollman  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15cfefd687SGarrett Wollman  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16cfefd687SGarrett Wollman  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
171984b014SDavid Greenman  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18cfefd687SGarrett Wollman  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19cfefd687SGarrett Wollman  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20cfefd687SGarrett Wollman  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21cfefd687SGarrett Wollman  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22cfefd687SGarrett Wollman  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23cfefd687SGarrett Wollman  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24cfefd687SGarrett Wollman  * SUCH DAMAGE.
25cfefd687SGarrett Wollman  *
260a91231dSAlan Cox  *	$Id: imgact_aout.c,v 1.47 1999/03/04 18:04:40 alc Exp $
27cfefd687SGarrett Wollman  */
28cfefd687SGarrett Wollman 
2926f9a767SRodney W. Grimes #include <sys/param.h>
3022d4b0fbSJohn Polstra #include <sys/acct.h>
3126f9a767SRodney W. Grimes #include <sys/resourcevar.h>
3226f9a767SRodney W. Grimes #include <sys/exec.h>
3322d4b0fbSJohn Polstra #include <sys/fcntl.h>
3426f9a767SRodney W. Grimes #include <sys/imgact.h>
35bc6d7444SDavid Greenman #include <sys/imgact_aout.h>
3626f9a767SRodney W. Grimes #include <sys/kernel.h>
3722d4b0fbSJohn Polstra #include <sys/malloc.h>
3822d4b0fbSJohn Polstra #include <sys/namei.h>
3922d4b0fbSJohn Polstra #include <sys/pioctl.h>
40a794e791SBruce Evans #include <sys/proc.h>
4122d4b0fbSJohn Polstra #include <sys/signalvar.h>
4222d4b0fbSJohn Polstra #include <sys/stat.h>
43f3f0ca60SSøren Schmidt #include <sys/sysent.h>
4422d4b0fbSJohn Polstra #include <sys/syscall.h>
45a794e791SBruce Evans #include <sys/vnode.h>
461616db3cSJohn Dyson #include <sys/systm.h>
4722d4b0fbSJohn Polstra #include <machine/md_var.h>
48cfefd687SGarrett Wollman 
4926f9a767SRodney W. Grimes #include <vm/vm.h>
50efeaf95aSDavid Greenman #include <vm/vm_param.h>
51efeaf95aSDavid Greenman #include <vm/vm_prot.h>
52996c772fSJohn Dyson #include <sys/lock.h>
53efeaf95aSDavid Greenman #include <vm/pmap.h>
54efeaf95aSDavid Greenman #include <vm/vm_map.h>
551616db3cSJohn Dyson #include <vm/vm_object.h>
5622d4b0fbSJohn Polstra #include <sys/user.h>
57cfefd687SGarrett Wollman 
587ee050b7SBruce Evans static int	exec_aout_imgact __P((struct image_params *imgp));
597ee050b7SBruce Evans 
6022d4b0fbSJohn Polstra struct sysentvec aout_sysvec = {
6122d4b0fbSJohn Polstra 	SYS_MAXSYSCALL,
6222d4b0fbSJohn Polstra 	sysent,
6322d4b0fbSJohn Polstra 	0,
6422d4b0fbSJohn Polstra 	0,
6522d4b0fbSJohn Polstra 	0,
6622d4b0fbSJohn Polstra 	0,
6722d4b0fbSJohn Polstra 	0,
6822d4b0fbSJohn Polstra 	0,
6922d4b0fbSJohn Polstra 	0,
7022d4b0fbSJohn Polstra 	sendsig,
7122d4b0fbSJohn Polstra 	sigcode,
7222d4b0fbSJohn Polstra 	&szsigcode,
7322d4b0fbSJohn Polstra 	0,
7422d4b0fbSJohn Polstra 	"FreeBSD a.out",
7522d4b0fbSJohn Polstra 	aout_coredump
7622d4b0fbSJohn Polstra };
7722d4b0fbSJohn Polstra 
78a3bdf7a3SBruce Evans static int
79c52007c2SDavid Greenman exec_aout_imgact(imgp)
80c52007c2SDavid Greenman 	struct image_params *imgp;
81cfefd687SGarrett Wollman {
82e0c95ed9SBruce Evans 	const struct exec *a_out = (const struct exec *) imgp->image_header;
835856e12eSJohn Dyson 	struct vmspace *vmspace;
841616db3cSJohn Dyson 	struct vnode *vp;
852f33b2c0SAlan Cox 	vm_map_t map;
861616db3cSJohn Dyson 	vm_object_t object;
871616db3cSJohn Dyson 	vm_offset_t text_end, data_end;
88ede8dc43SBruce Evans 	unsigned long virtual_offset;
89a316d390SJohn Dyson 	unsigned long file_offset;
90cfefd687SGarrett Wollman 	unsigned long bss_size;
91bb56ec4aSPoul-Henning Kamp 	int error;
92cfefd687SGarrett Wollman 
931e1e0b44SSøren Schmidt 	/*
941e1e0b44SSøren Schmidt 	 * Linux and *BSD binaries look very much alike,
951e1e0b44SSøren Schmidt 	 * only the machine id is different:
96d3628763SRodney W. Grimes 	 * 0x64 for Linux, 0x86 for *BSD, 0x00 for BSDI.
97185dc761SPeter Wemm 	 * NetBSD is in network byte order.. ugh.
981e1e0b44SSøren Schmidt 	 */
99d3628763SRodney W. Grimes 	if (((a_out->a_magic >> 16) & 0xff) != 0x86 &&
100185dc761SPeter Wemm 	    ((a_out->a_magic >> 16) & 0xff) != 0 &&
101185dc761SPeter Wemm 	    ((((int)ntohl(a_out->a_magic)) >> 16) & 0xff) != 0x86)
1021e1e0b44SSøren Schmidt                 return -1;
1031e1e0b44SSøren Schmidt 
104cfefd687SGarrett Wollman 	/*
105cfefd687SGarrett Wollman 	 * Set file/virtual offset based on a.out variant.
106cfefd687SGarrett Wollman 	 *	We do two cases: host byte order and network byte order
107cfefd687SGarrett Wollman 	 *	(for NetBSD compatibility)
108cfefd687SGarrett Wollman 	 */
109cfefd687SGarrett Wollman 	switch ((int)(a_out->a_magic & 0xffff)) {
110cfefd687SGarrett Wollman 	case ZMAGIC:
111cfefd687SGarrett Wollman 		virtual_offset = 0;
112cfefd687SGarrett Wollman 		if (a_out->a_text) {
113f8845af0SPoul-Henning Kamp 			file_offset = PAGE_SIZE;
114cfefd687SGarrett Wollman 		} else {
115cfefd687SGarrett Wollman 			/* Bill's "screwball mode" */
116cfefd687SGarrett Wollman 			file_offset = 0;
117cfefd687SGarrett Wollman 		}
118cfefd687SGarrett Wollman 		break;
119cfefd687SGarrett Wollman 	case QMAGIC:
120f8845af0SPoul-Henning Kamp 		virtual_offset = PAGE_SIZE;
121cfefd687SGarrett Wollman 		file_offset = 0;
122cfefd687SGarrett Wollman 		break;
123cfefd687SGarrett Wollman 	default:
124cfefd687SGarrett Wollman 		/* NetBSD compatibility */
125cfefd687SGarrett Wollman 		switch ((int)(ntohl(a_out->a_magic) & 0xffff)) {
126cfefd687SGarrett Wollman 		case ZMAGIC:
127cfefd687SGarrett Wollman 		case QMAGIC:
128f8845af0SPoul-Henning Kamp 			virtual_offset = PAGE_SIZE;
129cfefd687SGarrett Wollman 			file_offset = 0;
130cfefd687SGarrett Wollman 			break;
131cfefd687SGarrett Wollman 		default:
132cfefd687SGarrett Wollman 			return (-1);
133cfefd687SGarrett Wollman 		}
134cfefd687SGarrett Wollman 	}
135cfefd687SGarrett Wollman 
136f8845af0SPoul-Henning Kamp 	bss_size = roundup(a_out->a_bss, PAGE_SIZE);
137cfefd687SGarrett Wollman 
138cfefd687SGarrett Wollman 	/*
139cfefd687SGarrett Wollman 	 * Check various fields in header for validity/bounds.
140cfefd687SGarrett Wollman 	 */
141cfefd687SGarrett Wollman 	if (/* entry point must lay with text region */
142cfefd687SGarrett Wollman 	    a_out->a_entry < virtual_offset ||
143cfefd687SGarrett Wollman 	    a_out->a_entry >= virtual_offset + a_out->a_text ||
144cfefd687SGarrett Wollman 
145cfefd687SGarrett Wollman 	    /* text and data size must each be page rounded */
146f8845af0SPoul-Henning Kamp 	    a_out->a_text & PAGE_MASK || a_out->a_data & PAGE_MASK)
147cfefd687SGarrett Wollman 		return (-1);
148cfefd687SGarrett Wollman 
149cfefd687SGarrett Wollman 	/* text + data can't exceed file size */
150c52007c2SDavid Greenman 	if (a_out->a_data + a_out->a_text > imgp->attr->va_size)
151cfefd687SGarrett Wollman 		return (EFAULT);
152cfefd687SGarrett Wollman 
153cfefd687SGarrett Wollman 	/*
154cfefd687SGarrett Wollman 	 * text/data/bss must not exceed limits
155cfefd687SGarrett Wollman 	 */
156cfefd687SGarrett Wollman 	if (/* text can't exceed maximum text size */
157cfefd687SGarrett Wollman 	    a_out->a_text > MAXTSIZ ||
158cfefd687SGarrett Wollman 
159cfefd687SGarrett Wollman 	    /* data + bss can't exceed rlimit */
160cfefd687SGarrett Wollman 	    a_out->a_data + bss_size >
161c52007c2SDavid Greenman 		imgp->proc->p_rlimit[RLIMIT_DATA].rlim_cur)
162cfefd687SGarrett Wollman 			return (ENOMEM);
163cfefd687SGarrett Wollman 
164cfefd687SGarrett Wollman 	/* copy in arguments and/or environment from old process */
165c52007c2SDavid Greenman 	error = exec_extract_strings(imgp);
166cfefd687SGarrett Wollman 	if (error)
167cfefd687SGarrett Wollman 		return (error);
168cfefd687SGarrett Wollman 
169cfefd687SGarrett Wollman 	/*
170cfefd687SGarrett Wollman 	 * Destroy old process VM and create a new one (with a new stack)
171cfefd687SGarrett Wollman 	 */
172c52007c2SDavid Greenman 	exec_new_vmspace(imgp);
173cfefd687SGarrett Wollman 
174cfefd687SGarrett Wollman 	/*
1755856e12eSJohn Dyson 	 * The vm space can be changed by exec_new_vmspace
1765856e12eSJohn Dyson 	 */
1775856e12eSJohn Dyson 	vmspace = imgp->proc->p_vmspace;
1785856e12eSJohn Dyson 
1791616db3cSJohn Dyson 	vp = imgp->vp;
1802f33b2c0SAlan Cox 	map = &vmspace->vm_map;
1812f33b2c0SAlan Cox 	vm_map_lock(map);
1821616db3cSJohn Dyson 	object = vp->v_object;
1831616db3cSJohn Dyson 	vm_object_reference(object);
1841616db3cSJohn Dyson 
1851616db3cSJohn Dyson 	text_end = virtual_offset + a_out->a_text;
1860a91231dSAlan Cox 	error = vm_map_insert(map, object,
1871616db3cSJohn Dyson 		file_offset,
1881616db3cSJohn Dyson 		virtual_offset, text_end,
1891616db3cSJohn Dyson 		VM_PROT_READ | VM_PROT_EXECUTE, VM_PROT_ALL,
1901616db3cSJohn Dyson 		MAP_COPY_NEEDED | MAP_COPY_ON_WRITE);
1912f33b2c0SAlan Cox 	if (error) {
1922f33b2c0SAlan Cox 		vm_map_unlock(map);
193cfefd687SGarrett Wollman 		return (error);
1942f33b2c0SAlan Cox 	}
1951616db3cSJohn Dyson 	data_end = text_end + a_out->a_data;
1961616db3cSJohn Dyson 	if (a_out->a_data) {
1971616db3cSJohn Dyson 		vm_object_reference(object);
1980a91231dSAlan Cox 		error = vm_map_insert(map, object,
1991616db3cSJohn Dyson 			file_offset + a_out->a_text,
2001616db3cSJohn Dyson 			text_end, data_end,
2011616db3cSJohn Dyson 			VM_PROT_ALL, VM_PROT_ALL,
2021616db3cSJohn Dyson 			MAP_COPY_NEEDED | MAP_COPY_ON_WRITE);
2032f33b2c0SAlan Cox 		if (error) {
2042f33b2c0SAlan Cox 			vm_map_unlock(map);
2051616db3cSJohn Dyson 			return (error);
2061616db3cSJohn Dyson 		}
2072f33b2c0SAlan Cox 	}
208cfefd687SGarrett Wollman 
2090a91231dSAlan Cox 	pmap_object_init_pt(vm_map_pmap(map), virtual_offset,
2101616db3cSJohn Dyson 		object, (vm_pindex_t) OFF_TO_IDX(file_offset),
2111616db3cSJohn Dyson 		a_out->a_text + a_out->a_data, 0);
2121616db3cSJohn Dyson 
2131616db3cSJohn Dyson 	if (bss_size) {
2140a91231dSAlan Cox 		error = vm_map_insert(map, NULL, 0,
2151616db3cSJohn Dyson 			data_end, data_end + bss_size,
2161616db3cSJohn Dyson 			VM_PROT_ALL, VM_PROT_ALL, 0);
2172f33b2c0SAlan Cox 		if (error) {
2182f33b2c0SAlan Cox 			vm_map_unlock(map);
219cfefd687SGarrett Wollman 			return (error);
22068940ac1SDavid Greenman 		}
2212f33b2c0SAlan Cox 	}
2222f33b2c0SAlan Cox 	vm_map_unlock(map);
223cfefd687SGarrett Wollman 
224cfefd687SGarrett Wollman 	/* Fill in process VM information */
225cfefd687SGarrett Wollman 	vmspace->vm_tsize = a_out->a_text >> PAGE_SHIFT;
226cfefd687SGarrett Wollman 	vmspace->vm_dsize = (a_out->a_data + bss_size) >> PAGE_SHIFT;
2277cd99438SBruce Evans 	vmspace->vm_taddr = (caddr_t) (uintptr_t) virtual_offset;
2287cd99438SBruce Evans 	vmspace->vm_daddr = (caddr_t) (uintptr_t)
2297cd99438SBruce Evans 			    (virtual_offset + a_out->a_text);
230cfefd687SGarrett Wollman 
231cfefd687SGarrett Wollman 	/* Fill in image_params */
232c52007c2SDavid Greenman 	imgp->interpreted = 0;
233c52007c2SDavid Greenman 	imgp->entry_addr = a_out->a_entry;
234cfefd687SGarrett Wollman 
235c52007c2SDavid Greenman 	imgp->proc->p_sysent = &aout_sysvec;
236c0e5de7dSDavid Greenman 
237c0e5de7dSDavid Greenman 	/* Indicate that this file should not be modified */
238c52007c2SDavid Greenman 	imgp->vp->v_flag |= VTEXT;
239c0e5de7dSDavid Greenman 
240cfefd687SGarrett Wollman 	return (0);
241cfefd687SGarrett Wollman }
24292d91f76SGarrett Wollman 
24392d91f76SGarrett Wollman /*
2449fe42598SBruce Evans  * Dump core, into a file named as described in the comments for
2459fe42598SBruce Evans  * expand_name(), unless the process was setuid/setgid.
24622d4b0fbSJohn Polstra  */
24722d4b0fbSJohn Polstra int
24822d4b0fbSJohn Polstra aout_coredump(p)
24922d4b0fbSJohn Polstra 	register struct proc *p;
25022d4b0fbSJohn Polstra {
25122d4b0fbSJohn Polstra 	register struct vnode *vp;
25222d4b0fbSJohn Polstra 	register struct ucred *cred = p->p_cred->pc_ucred;
25322d4b0fbSJohn Polstra 	register struct vmspace *vm = p->p_vmspace;
25422d4b0fbSJohn Polstra 	struct nameidata nd;
25522d4b0fbSJohn Polstra 	struct vattr vattr;
25622d4b0fbSJohn Polstra 	int error, error1;
25722d4b0fbSJohn Polstra 	char *name;			/* name of corefile */
25822d4b0fbSJohn Polstra 
25922d4b0fbSJohn Polstra 	STOPEVENT(p, S_CORE, 0);
26022d4b0fbSJohn Polstra 	if (sugid_coredump == 0 && p->p_flag & P_SUGID)
26122d4b0fbSJohn Polstra 		return (EFAULT);
26222d4b0fbSJohn Polstra 	if (ctob(UPAGES + vm->vm_dsize + vm->vm_ssize) >=
26322d4b0fbSJohn Polstra 	    p->p_rlimit[RLIMIT_CORE].rlim_cur)
26422d4b0fbSJohn Polstra 		return (EFAULT);
26522d4b0fbSJohn Polstra 	name = expand_name(p->p_comm, p->p_ucred->cr_uid, p->p_pid);
26622d4b0fbSJohn Polstra 	if (name == NULL)
26722d4b0fbSJohn Polstra 		return (EFAULT);	/* XXX -- not the best error */
26822d4b0fbSJohn Polstra 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, name, p);
26922d4b0fbSJohn Polstra 	error = vn_open(&nd, O_CREAT | FWRITE, S_IRUSR | S_IWUSR);
27022d4b0fbSJohn Polstra 	free(name, M_TEMP);
27122d4b0fbSJohn Polstra 	if (error)
27222d4b0fbSJohn Polstra 		return (error);
27322d4b0fbSJohn Polstra 	vp = nd.ni_vp;
27422d4b0fbSJohn Polstra 
27522d4b0fbSJohn Polstra 	/* Don't dump to non-regular files or files with links. */
27622d4b0fbSJohn Polstra 	if (vp->v_type != VREG ||
27722d4b0fbSJohn Polstra 	    VOP_GETATTR(vp, &vattr, cred, p) || vattr.va_nlink != 1) {
27822d4b0fbSJohn Polstra 		error = EFAULT;
27922d4b0fbSJohn Polstra 		goto out;
28022d4b0fbSJohn Polstra 	}
28122d4b0fbSJohn Polstra 	VATTR_NULL(&vattr);
28222d4b0fbSJohn Polstra 	vattr.va_size = 0;
28322d4b0fbSJohn Polstra 	VOP_LEASE(vp, p, cred, LEASE_WRITE);
28422d4b0fbSJohn Polstra 	VOP_SETATTR(vp, &vattr, cred, p);
28522d4b0fbSJohn Polstra 	p->p_acflag |= ACORE;
28622d4b0fbSJohn Polstra 	bcopy(p, &p->p_addr->u_kproc.kp_proc, sizeof(struct proc));
28722d4b0fbSJohn Polstra 	fill_eproc(p, &p->p_addr->u_kproc.kp_eproc);
28822d4b0fbSJohn Polstra 	error = cpu_coredump(p, vp, cred);
28922d4b0fbSJohn Polstra 	if (error == 0)
29022d4b0fbSJohn Polstra 		error = vn_rdwr(UIO_WRITE, vp, vm->vm_daddr,
29122d4b0fbSJohn Polstra 		    (int)ctob(vm->vm_dsize), (off_t)ctob(UPAGES), UIO_USERSPACE,
29222d4b0fbSJohn Polstra 		    IO_NODELOCKED|IO_UNIT, cred, (int *) NULL, p);
29322d4b0fbSJohn Polstra 	if (error == 0)
29422d4b0fbSJohn Polstra 		error = vn_rdwr(UIO_WRITE, vp,
29522d4b0fbSJohn Polstra 		    (caddr_t) trunc_page(USRSTACK - ctob(vm->vm_ssize)),
29622d4b0fbSJohn Polstra 		    round_page(ctob(vm->vm_ssize)),
29722d4b0fbSJohn Polstra 		    (off_t)ctob(UPAGES) + ctob(vm->vm_dsize), UIO_USERSPACE,
29822d4b0fbSJohn Polstra 		    IO_NODELOCKED|IO_UNIT, cred, (int *) NULL, p);
29922d4b0fbSJohn Polstra out:
30022d4b0fbSJohn Polstra 	VOP_UNLOCK(vp, 0, p);
30122d4b0fbSJohn Polstra 	error1 = vn_close(vp, FWRITE, cred, p);
30222d4b0fbSJohn Polstra 	if (error == 0)
30322d4b0fbSJohn Polstra 		error = error1;
30422d4b0fbSJohn Polstra 	return (error);
30522d4b0fbSJohn Polstra }
30622d4b0fbSJohn Polstra 
30722d4b0fbSJohn Polstra /*
30892d91f76SGarrett Wollman  * Tell kern_execve.c about it, with a little help from the linker.
30992d91f76SGarrett Wollman  * Since `const' objects end up in the text segment, TEXT_SET is the
31092d91f76SGarrett Wollman  * correct directive to use.
31192d91f76SGarrett Wollman  */
312820ca326SMatthew Dillon static struct execsw aout_execsw = { exec_aout_imgact, "a.out" };
313aa855a59SPeter Wemm EXEC_SET(aout, aout_execsw);
314