11541Srgrimes/*-
21541Srgrimes * Copyright (c) 1993, David Greenman
31541Srgrimes * All rights reserved.
41541Srgrimes *
51541Srgrimes * Redistribution and use in source and binary forms, with or without
61541Srgrimes * modification, are permitted provided that the following conditions
71541Srgrimes * are met:
81541Srgrimes * 1. Redistributions of source code must retain the above copyright
91541Srgrimes *    notice, this list of conditions and the following disclaimer.
101541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111541Srgrimes *    notice, this list of conditions and the following disclaimer in the
121541Srgrimes *    documentation and/or other materials provided with the distribution.
131541Srgrimes *
141541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
151541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
161541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
171541Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
181541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
191541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
201541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
211541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
221541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
231541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
241541Srgrimes * SUCH DAMAGE.
251541Srgrimes */
261541Srgrimes
271541Srgrimes#include <sys/cdefs.h>
281541Srgrimes__FBSDID("$FreeBSD$");
2914505Shsu
3050477Speter#include <sys/param.h>
311541Srgrimes#include <sys/exec.h>
321541Srgrimes#include <sys/imgact.h>
332165Spaul#include <sys/imgact_aout.h>
342165Spaul#include <sys/kernel.h>
352165Spaul#include <sys/limits.h>
3615492Sbde#include <sys/lock.h>
3770834Swollman#include <sys/malloc.h>
38130380Srwatson#include <sys/mutex.h>
39130380Srwatson#include <sys/proc.h>
401541Srgrimes#include <sys/racct.h>
411541Srgrimes#include <sys/resourcevar.h>
421541Srgrimes#include <sys/signalvar.h>
431541Srgrimes#include <sys/syscall.h>
441541Srgrimes#include <sys/sysent.h>
451541Srgrimes#include <sys/systm.h>
461541Srgrimes#include <sys/vnode.h>
4736079Swollman
4836079Swollman#include <machine/frame.h>
49129958Srwatson#include <machine/md_var.h>
50129958Srwatson
51129958Srwatson#include <vm/vm.h>
52129958Srwatson#include <vm/pmap.h>
53129958Srwatson#include <vm/vm_map.h>
54129958Srwatson#include <vm/vm_object.h>
55129958Srwatson#include <vm/vm_param.h>
56129958Srwatson
57129958Srwatson#ifdef __amd64__
58131168Srwatson#include <compat/freebsd32/freebsd32_signal.h>
5995552Stanimura#include <compat/freebsd32/freebsd32_util.h>
601541Srgrimes#include <compat/freebsd32/freebsd32_proto.h>
61130387Srwatson#include <compat/freebsd32/freebsd32_syscall.h>
62129958Srwatson#include <compat/ia32/ia32_signal.h>
6397658Stanimura#endif
6497658Stanimura
65130818Srwatsonstatic int	exec_aout_imgact(struct image_params *imgp);
66129979Srwatsonstatic int	aout_fixup(register_t **stack_base, struct image_params *imgp);
6798993Salfred
68129958Srwatson#if defined(__i386__)
691541Srgrimesstruct sysentvec aout_sysvec = {
7013765Smpp	.sv_size	= SYS_MAXSYSCALL,
711541Srgrimes	.sv_table	= sysent,
721541Srgrimes	.sv_mask	= 0,
7378913Sjlemon	.sv_sigsize	= 0,
7478913Sjlemon	.sv_sigtbl	= NULL,
751541Srgrimes	.sv_errsize	= 0,
7678913Sjlemon	.sv_errtbl	= NULL,
771541Srgrimes	.sv_transtrap	= NULL,
781541Srgrimes	.sv_fixup	= aout_fixup,
791541Srgrimes	.sv_sendsig	= sendsig,
80160604Srwatson	.sv_sigcode	= sigcode,
81129979Srwatson	.sv_szsigcode	= &szsigcode,
82129979Srwatson	.sv_prepsyscall	= NULL,
83129979Srwatson	.sv_name	= "FreeBSD a.out",
84140730Sglebius	.sv_coredump	= NULL,
85140730Sglebius	.sv_imgact_try	= NULL,
8618787Spst	.sv_minsigstksz	= MINSIGSTKSZ,
87140730Sglebius	.sv_pagesize	= PAGE_SIZE,
88130527Srwatson	.sv_minuser	= VM_MIN_ADDRESS,
89131029Srwatson	.sv_maxuser	= VM_MAXUSER_ADDRESS,
9097658Stanimura	.sv_usrstack	= USRSTACK,
9141087Struckman	.sv_psstrings	= PS_STRINGS,
92131017Srwatson	.sv_stackprot	= VM_PROT_ALL,
9397658Stanimura	.sv_copyout_strings	= exec_copyout_strings,
941541Srgrimes	.sv_setregs	= exec_setregs,
951541Srgrimes	.sv_fixlimit	= NULL,
961541Srgrimes	.sv_maxssiz	= NULL,
9783421Sobrien	.sv_flags	= SV_ABI_FREEBSD | SV_AOUT | SV_IA32 | SV_ILP32,
98100591Sjdp	.sv_set_syscall_retval = cpu_set_syscall_retval,
99130380Srwatson	.sv_fetch_syscall_args = cpu_fetch_syscall_args,
100141052Sglebius	.sv_syscallnames = syscallnames,
101117708Srobert	.sv_schedtail	= NULL,
102130527Srwatson};
103130527Srwatson
104130527Srwatson#elif defined(__amd64__)
105130527Srwatson
106130527Srwatson#define	AOUT32_USRSTACK	0xbfc00000
107130527Srwatson#define	AOUT32_PS_STRINGS \
108130527Srwatson    (AOUT32_USRSTACK - sizeof(struct freebsd32_ps_strings))
109130527Srwatson#define	AOUT32_MINUSER	FREEBSD32_MINUSER
110130527Srwatson
111130527Srwatsonextern const char *freebsd32_syscallnames[];
112130527Srwatsonextern u_long ia32_maxssiz;
113130527Srwatson
1141541Srgrimesstruct sysentvec aout_sysvec = {
115130818Srwatson	.sv_size	= FREEBSD32_SYS_MAXSYSCALL,
116130818Srwatson	.sv_table	= freebsd32_sysent,
117130818Srwatson	.sv_mask	= 0,
1181541Srgrimes	.sv_sigsize	= 0,
119131022Srwatson	.sv_sigtbl	= NULL,
120131022Srwatson	.sv_errsize	= 0,
121131022Srwatson	.sv_errtbl	= NULL,
1221541Srgrimes	.sv_transtrap	= NULL,
1231541Srgrimes	.sv_fixup	= aout_fixup,
1241541Srgrimes	.sv_sendsig	= ia32_sendsig,
1251541Srgrimes	.sv_sigcode	= ia32_sigcode,
1261541Srgrimes	.sv_szsigcode	= &sz_ia32_sigcode,
12736527Speter	.sv_prepsyscall	= NULL,
1281541Srgrimes	.sv_name	= "FreeBSD a.out",
12955943Sjasone	.sv_coredump	= NULL,
13059288Sjlemon	.sv_imgact_try	= NULL,
131166404Sandre	.sv_minsigstksz	= MINSIGSTKSZ,
1321541Srgrimes	.sv_pagesize	= IA32_PAGE_SIZE,
13397658Stanimura	.sv_minuser	= AOUT32_MINUSER,
13497658Stanimura	.sv_maxuser	= AOUT32_USRSTACK,
135130527Srwatson	.sv_usrstack	= AOUT32_USRSTACK,
136130398Srwatson	.sv_psstrings	= AOUT32_PS_STRINGS,
137130398Srwatson	.sv_stackprot	= VM_PROT_ALL,
138160605Srwatson	.sv_copyout_strings	= freebsd32_copyout_strings,
139131168Srwatson	.sv_setregs	= ia32_setregs,
140147852Sjhb	.sv_fixlimit	= ia32_fixlimit,
14197658Stanimura	.sv_maxssiz	= &ia32_maxssiz,
14297658Stanimura	.sv_flags	= SV_ABI_FREEBSD | SV_AOUT | SV_IA32 | SV_ILP32,
14397658Stanimura	.sv_set_syscall_retval = ia32_set_syscall_retval,
14497658Stanimura	.sv_fetch_syscall_args = ia32_fetch_syscall_args,
14597658Stanimura	.sv_syscallnames = freebsd32_syscallnames,
1461541Srgrimes};
1471541Srgrimes#else
148121628Ssam#error "Port me"
149121628Ssam#endif
150121628Ssam
151121628Ssamstatic int
152121628Ssamaout_fixup(register_t **stack_base, struct image_params *imgp)
153121628Ssam{
154121628Ssam
1551541Srgrimes	*(char **)stack_base -= sizeof(uint32_t);
156129979Srwatson	return (suword32(*stack_base, imgp->args->argc));
157129979Srwatson}
158129979Srwatson
159129979Srwatsonstatic int
160129979Srwatsonexec_aout_imgact(struct image_params *imgp)
161129979Srwatson{
162136682Srwatson	const struct exec *a_out = (const struct exec *) imgp->image_header;
163136682Srwatson	struct vmspace *vmspace;
164130364Srwatson	vm_map_t map;
165130364Srwatson	vm_object_t object;
166129979Srwatson	vm_offset_t text_end, data_end;
167129979Srwatson	unsigned long virtual_offset;
168130380Srwatson	unsigned long file_offset;
169130380Srwatson	unsigned long bss_size;
170130380Srwatson	int error;
171130380Srwatson
172130380Srwatson	/*
173130380Srwatson	 * Linux and *BSD binaries look very much alike,
174130380Srwatson	 * only the machine id is different:
175130380Srwatson	 * 0x64 for Linux, 0x86 for *BSD, 0x00 for BSDI.
176130380Srwatson	 * NetBSD is in network byte order.. ugh.
177130380Srwatson	 */
178130380Srwatson	if (((a_out->a_magic >> 16) & 0xff) != 0x86 &&
179136326Srwatson	    ((a_out->a_magic >> 16) & 0xff) != 0 &&
180130380Srwatson	    ((((int)ntohl(a_out->a_magic)) >> 16) & 0xff) != 0x86)
181130380Srwatson                return -1;
182130380Srwatson
183130380Srwatson	/*
184130380Srwatson	 * Set file/virtual offset based on a.out variant.
185130380Srwatson	 *	We do two cases: host byte order and network byte order
186130380Srwatson	 *	(for NetBSD compatibility)
187130380Srwatson	 */
188130380Srwatson	switch ((int)(a_out->a_magic & 0xffff)) {
189130380Srwatson	case ZMAGIC:
190130380Srwatson		virtual_offset = 0;
191130380Srwatson		if (a_out->a_text) {
192130492Srwatson			file_offset = PAGE_SIZE;
1931541Srgrimes		} else {
194130480Srwatson			/* Bill's "screwball mode" */
195130480Srwatson			file_offset = 0;
196130480Srwatson		}
197130480Srwatson		break;
198130480Srwatson	case QMAGIC:
199130480Srwatson		virtual_offset = PAGE_SIZE;
200130480Srwatson		file_offset = 0;
201130480Srwatson		/* Pass PS_STRINGS for BSD/OS binaries only. */
202130480Srwatson		if (N_GETMID(*a_out) == MID_ZERO)
2031541Srgrimes			imgp->ps_strings = aout_sysvec.sv_psstrings;
20414547Sdg		break;
20514547Sdg	default:
20614547Sdg		/* NetBSD compatibility */
20714547Sdg		switch ((int)(ntohl(a_out->a_magic) & 0xffff)) {
20814547Sdg		case ZMAGIC:
20914547Sdg		case QMAGIC:
21014547Sdg			virtual_offset = PAGE_SIZE;
21143196Sfenner			file_offset = 0;
212157360Srwatson			break;
213157360Srwatson		default:
214157360Srwatson			return (-1);
215157360Srwatson		}
216157360Srwatson	}
217157360Srwatson
218157360Srwatson	bss_size = roundup(a_out->a_bss, PAGE_SIZE);
219156746Srwatson
2201541Srgrimes	/*
22136079Swollman	 * Check various fields in header for validity/bounds.
222130480Srwatson	 */
223130480Srwatson	if (/* entry point must lay with text region */
224130480Srwatson	    a_out->a_entry < virtual_offset ||
225130480Srwatson	    a_out->a_entry >= virtual_offset + a_out->a_text ||
226130480Srwatson
227130480Srwatson	    /* text and data size must each be page rounded */
228130480Srwatson	    a_out->a_text & PAGE_MASK || a_out->a_data & PAGE_MASK
229129916Srwatson
230129916Srwatson#ifdef __amd64__
231129916Srwatson	    ||
232129916Srwatson	    /* overflows */
233129916Srwatson	    virtual_offset + a_out->a_text + a_out->a_data + bss_size > UINT_MAX
234129916Srwatson#endif
23536079Swollman	    )
23636079Swollman		return (-1);
23783045Sobrien
23836079Swollman	/* text + data can't exceed file size */
23936079Swollman	if (a_out->a_data + a_out->a_text > imgp->attr->va_size)
24036079Swollman		return (EFAULT);
24136079Swollman
24236079Swollman	/*
24336079Swollman	 * text/data/bss must not exceed limits
24436079Swollman	 */
24536079Swollman	PROC_LOCK(imgp->proc);
24636079Swollman	if (/* text can't exceed maximum text size */
247140730Sglebius	    a_out->a_text > maxtsiz ||
248140730Sglebius
249140730Sglebius	    /* data + bss can't exceed rlimit */
25036079Swollman	    a_out->a_data + bss_size > lim_cur(imgp->proc, RLIMIT_DATA) ||
25136079Swollman	    racct_set(imgp->proc, RACCT_DATA, a_out->a_data + bss_size) != 0) {
25236079Swollman			PROC_UNLOCK(imgp->proc);
25336079Swollman			return (ENOMEM);
25483421Sobrien	}
255100591Sjdp	PROC_UNLOCK(imgp->proc);
256100591Sjdp
257100591Sjdp	/*
258100591Sjdp	 * Avoid a possible deadlock if the current address space is destroyed
259100591Sjdp	 * and that address space maps the locked vnode.  In the common case,
260100591Sjdp	 * the locked vnode's v_usecount is decremented but remains greater
26136079Swollman	 * than zero.  Consequently, the vnode lock is not needed by vrele().
26236079Swollman	 * However, in cases where the vnode lock is external, such as nullfs,
26336079Swollman	 * v_usecount may become zero.
26436079Swollman	 */
26514547Sdg	VOP_UNLOCK(imgp->vp, 0);
266130393Srwatson
267130393Srwatson	/*
2681541Srgrimes	 * Destroy old process VM and create a new one (with a new stack)
2691541Srgrimes	 */
2701541Srgrimes	error = exec_new_vmspace(imgp, &aout_sysvec);
2711541Srgrimes
2721541Srgrimes	vn_lock(imgp->vp, LK_EXCLUSIVE | LK_RETRY);
27336527Speter	if (error)
27436527Speter		return (error);
27555943Sjasone
27659288Sjlemon	/*
27736527Speter	 * The vm space can be changed by exec_new_vmspace
27836527Speter	 */
2791541Srgrimes	vmspace = imgp->proc->p_vmspace;
2801541Srgrimes
2811541Srgrimes	object = imgp->object;
2821541Srgrimes	map = &vmspace->vm_map;
2831541Srgrimes	vm_map_lock(map);
2841541Srgrimes	vm_object_reference(object);
2851541Srgrimes
2861541Srgrimes	text_end = virtual_offset + a_out->a_text;
2871541Srgrimes	error = vm_map_insert(map, object,
2881541Srgrimes		file_offset,
2891541Srgrimes		virtual_offset, text_end,
2901541Srgrimes		VM_PROT_READ | VM_PROT_EXECUTE, VM_PROT_ALL,
2911541Srgrimes		MAP_COPY_ON_WRITE | MAP_PREFAULT);
2921541Srgrimes	if (error) {
2931541Srgrimes		vm_map_unlock(map);
2941541Srgrimes		vm_object_deallocate(object);
295130480Srwatson		return (error);
29670536Sphk	}
2971541Srgrimes	data_end = text_end + a_out->a_data;
2981541Srgrimes	if (a_out->a_data) {
2991541Srgrimes		vm_object_reference(object);
3003304Sphk		error = vm_map_insert(map, object,
3011541Srgrimes			file_offset + a_out->a_text,
3023304Sphk			text_end, data_end,
303130480Srwatson			VM_PROT_ALL, VM_PROT_ALL,
3041541Srgrimes			MAP_COPY_ON_WRITE | MAP_PREFAULT);
3051541Srgrimes		if (error) {
3061541Srgrimes			vm_map_unlock(map);
3071541Srgrimes			vm_object_deallocate(object);
3081541Srgrimes			return (error);
309151967Sandre		}
310106313Skbyanc	}
3111541Srgrimes
3121541Srgrimes	if (bss_size) {
3131541Srgrimes		error = vm_map_insert(map, NULL, 0,
3141541Srgrimes			data_end, data_end + bss_size,
3151541Srgrimes			VM_PROT_ALL, VM_PROT_ALL, 0);
3161541Srgrimes		if (error) {
3171541Srgrimes			vm_map_unlock(map);
3181541Srgrimes			return (error);
319151967Sandre		}
320106313Skbyanc	}
3211541Srgrimes	vm_map_unlock(map);
3221541Srgrimes
3231541Srgrimes	/* Fill in process VM information */
3241541Srgrimes	vmspace->vm_tsize = a_out->a_text >> PAGE_SHIFT;
3251541Srgrimes	vmspace->vm_dsize = (a_out->a_data + bss_size) >> PAGE_SHIFT;
3261541Srgrimes	vmspace->vm_taddr = (caddr_t) (uintptr_t) virtual_offset;
3271541Srgrimes	vmspace->vm_daddr = (caddr_t) (uintptr_t)
3281541Srgrimes			    (virtual_offset + a_out->a_text);
3291541Srgrimes
3301541Srgrimes	/* Fill in image_params */
3311541Srgrimes	imgp->interpreted = 0;
332111119Simp	imgp->entry_addr = a_out->a_entry;
3331541Srgrimes
3341541Srgrimes	imgp->proc->p_sysent = &aout_sysvec;
3351541Srgrimes
336130831Srwatson	return (0);
337130831Srwatson}
3381541Srgrimes
3391541Srgrimes/*
3401541Srgrimes * Tell kern_execve.c about it, with a little help from the linker.
341111748Sdes */
3421541Srgrimesstatic struct execsw aout_execsw = { exec_aout_imgact, "a.out" };
343130831SrwatsonEXEC_SET(aout, aout_execsw);
3441541Srgrimes