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$"); 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> 35220238Skib#include <sys/limits.h> 3676166Smarkm#include <sys/lock.h> 37103181Sbde#include <sys/malloc.h> 3876166Smarkm#include <sys/mutex.h> 3915494Sbde#include <sys/proc.h> 40220373Strasz#include <sys/racct.h> 4176166Smarkm#include <sys/resourcevar.h> 4239154Sjdp#include <sys/signalvar.h> 43103181Sbde#include <sys/syscall.h> 442257Ssos#include <sys/sysent.h> 45103181Sbde#include <sys/systm.h> 4615494Sbde#include <sys/vnode.h> 4776166Smarkm 48103181Sbde#include <machine/frame.h> 4939154Sjdp#include <machine/md_var.h> 50885Swollman 511549Srgrimes#include <vm/vm.h> 5212662Sdg#include <vm/pmap.h> 5312662Sdg#include <vm/vm_map.h> 5432446Sdyson#include <vm/vm_object.h> 55103181Sbde#include <vm/vm_param.h> 56885Swollman 57220238Skib#ifdef __amd64__ 58220238Skib#include <compat/freebsd32/freebsd32_signal.h> 59220238Skib#include <compat/freebsd32/freebsd32_util.h> 60220238Skib#include <compat/freebsd32/freebsd32_proto.h> 61220238Skib#include <compat/freebsd32/freebsd32_syscall.h> 62220238Skib#include <compat/ia32/ia32_signal.h> 63220238Skib#endif 64220238Skib 6592723Salfredstatic int exec_aout_imgact(struct image_params *imgp); 66102808Sjakestatic int aout_fixup(register_t **stack_base, struct image_params *imgp); 6712568Sbde 68220238Skib#if defined(__i386__) 6939154Sjdpstruct sysentvec aout_sysvec = { 70183322Skib .sv_size = SYS_MAXSYSCALL, 71183322Skib .sv_table = sysent, 72183322Skib .sv_mask = 0, 73183322Skib .sv_sigsize = 0, 74183322Skib .sv_sigtbl = NULL, 75183322Skib .sv_errsize = 0, 76183322Skib .sv_errtbl = NULL, 77183322Skib .sv_transtrap = NULL, 78183322Skib .sv_fixup = aout_fixup, 79183322Skib .sv_sendsig = sendsig, 80183322Skib .sv_sigcode = sigcode, 81183322Skib .sv_szsigcode = &szsigcode, 82183322Skib .sv_prepsyscall = NULL, 83183322Skib .sv_name = "FreeBSD a.out", 84183322Skib .sv_coredump = NULL, 85183322Skib .sv_imgact_try = NULL, 86183322Skib .sv_minsigstksz = MINSIGSTKSZ, 87183322Skib .sv_pagesize = PAGE_SIZE, 88183322Skib .sv_minuser = VM_MIN_ADDRESS, 89183322Skib .sv_maxuser = VM_MAXUSER_ADDRESS, 90183322Skib .sv_usrstack = USRSTACK, 91183322Skib .sv_psstrings = PS_STRINGS, 92183322Skib .sv_stackprot = VM_PROT_ALL, 93183322Skib .sv_copyout_strings = exec_copyout_strings, 94183322Skib .sv_setregs = exec_setregs, 95183322Skib .sv_fixlimit = NULL, 96185169Skib .sv_maxssiz = NULL, 97220238Skib .sv_flags = SV_ABI_FREEBSD | SV_AOUT | SV_IA32 | SV_ILP32, 98208453Skib .sv_set_syscall_retval = cpu_set_syscall_retval, 99208453Skib .sv_fetch_syscall_args = cpu_fetch_syscall_args, 100208453Skib .sv_syscallnames = syscallnames, 101219405Sdchagin .sv_schedtail = NULL, 102293490Sdchagin .sv_thread_detach = NULL, 103294136Sdchagin .sv_trap = NULL, 10439154Sjdp}; 10539154Sjdp 106220238Skib#elif defined(__amd64__) 107220238Skib 108223164Skib#define AOUT32_USRSTACK 0xbfc00000 109220238Skib#define AOUT32_PS_STRINGS \ 110220238Skib (AOUT32_USRSTACK - sizeof(struct freebsd32_ps_strings)) 111238687Skib#define AOUT32_MINUSER FREEBSD32_MINUSER 112220238Skib 113220238Skibextern const char *freebsd32_syscallnames[]; 114220238Skibextern u_long ia32_maxssiz; 115220238Skib 116220238Skibstruct sysentvec aout_sysvec = { 117220238Skib .sv_size = FREEBSD32_SYS_MAXSYSCALL, 118220238Skib .sv_table = freebsd32_sysent, 119220238Skib .sv_mask = 0, 120220238Skib .sv_sigsize = 0, 121220238Skib .sv_sigtbl = NULL, 122220238Skib .sv_errsize = 0, 123220238Skib .sv_errtbl = NULL, 124220238Skib .sv_transtrap = NULL, 125220238Skib .sv_fixup = aout_fixup, 126220238Skib .sv_sendsig = ia32_sendsig, 127220238Skib .sv_sigcode = ia32_sigcode, 128220238Skib .sv_szsigcode = &sz_ia32_sigcode, 129220238Skib .sv_prepsyscall = NULL, 130220238Skib .sv_name = "FreeBSD a.out", 131220238Skib .sv_coredump = NULL, 132220238Skib .sv_imgact_try = NULL, 133220238Skib .sv_minsigstksz = MINSIGSTKSZ, 134220238Skib .sv_pagesize = IA32_PAGE_SIZE, 135238687Skib .sv_minuser = AOUT32_MINUSER, 136220238Skib .sv_maxuser = AOUT32_USRSTACK, 137220238Skib .sv_usrstack = AOUT32_USRSTACK, 138220238Skib .sv_psstrings = AOUT32_PS_STRINGS, 139220238Skib .sv_stackprot = VM_PROT_ALL, 140220238Skib .sv_copyout_strings = freebsd32_copyout_strings, 141220238Skib .sv_setregs = ia32_setregs, 142220238Skib .sv_fixlimit = ia32_fixlimit, 143220238Skib .sv_maxssiz = &ia32_maxssiz, 144220238Skib .sv_flags = SV_ABI_FREEBSD | SV_AOUT | SV_IA32 | SV_ILP32, 145220238Skib .sv_set_syscall_retval = ia32_set_syscall_retval, 146220238Skib .sv_fetch_syscall_args = ia32_fetch_syscall_args, 147220238Skib .sv_syscallnames = freebsd32_syscallnames, 148220238Skib}; 149220238Skib#else 150220238Skib#error "Port me" 151220238Skib#endif 152220238Skib 15350901Sbdestatic int 154220238Skibaout_fixup(register_t **stack_base, struct image_params *imgp) 155102808Sjake{ 156102808Sjake 157220238Skib *(char **)stack_base -= sizeof(uint32_t); 158223165Skib return (suword32(*stack_base, imgp->args->argc)); 159102808Sjake} 160102808Sjake 161102808Sjakestatic int 162220238Skibexec_aout_imgact(struct image_params *imgp) 163885Swollman{ 16417974Sbde const struct exec *a_out = (const struct exec *) imgp->image_header; 16524848Sdyson struct vmspace *vmspace; 16644469Salc vm_map_t map; 16732446Sdyson vm_object_t object; 16832446Sdyson vm_offset_t text_end, data_end; 16914703Sbde unsigned long virtual_offset; 17012767Sdyson unsigned long file_offset; 171885Swollman unsigned long bss_size; 1723098Sphk int error; 173885Swollman 174885Swollman /* 1756380Ssos * Linux and *BSD binaries look very much alike, 1768876Srgrimes * only the machine id is different: 1779202Srgrimes * 0x64 for Linux, 0x86 for *BSD, 0x00 for BSDI. 17814363Speter * NetBSD is in network byte order.. ugh. 1796380Ssos */ 180237694Simp if (((a_out->a_midmag >> 16) & 0xff) != 0x86 && 181237694Simp ((a_out->a_midmag >> 16) & 0xff) != 0 && 182237694Simp ((((int)ntohl(a_out->a_midmag)) >> 16) & 0xff) != 0x86) 1839202Srgrimes return -1; 1846380Ssos 1856380Ssos /* 186885Swollman * Set file/virtual offset based on a.out variant. 187885Swollman * We do two cases: host byte order and network byte order 188885Swollman * (for NetBSD compatibility) 189885Swollman */ 190237694Simp switch ((int)(a_out->a_midmag & 0xffff)) { 191885Swollman case ZMAGIC: 192885Swollman virtual_offset = 0; 193885Swollman if (a_out->a_text) { 19415538Sphk file_offset = PAGE_SIZE; 195885Swollman } else { 196885Swollman /* Bill's "screwball mode" */ 197885Swollman file_offset = 0; 198885Swollman } 199885Swollman break; 200885Swollman case QMAGIC: 20115538Sphk virtual_offset = PAGE_SIZE; 202885Swollman file_offset = 0; 20345270Sjdp /* Pass PS_STRINGS for BSD/OS binaries only. */ 20445270Sjdp if (N_GETMID(*a_out) == MID_ZERO) 205103767Sjake imgp->ps_strings = aout_sysvec.sv_psstrings; 206885Swollman break; 207885Swollman default: 208885Swollman /* NetBSD compatibility */ 209237694Simp switch ((int)(ntohl(a_out->a_midmag) & 0xffff)) { 210885Swollman case ZMAGIC: 211885Swollman case QMAGIC: 21215538Sphk virtual_offset = PAGE_SIZE; 213885Swollman file_offset = 0; 214885Swollman break; 215885Swollman default: 216885Swollman return (-1); 217885Swollman } 218885Swollman } 219885Swollman 22015538Sphk bss_size = roundup(a_out->a_bss, PAGE_SIZE); 221885Swollman 222885Swollman /* 223885Swollman * Check various fields in header for validity/bounds. 224885Swollman */ 225885Swollman if (/* entry point must lay with text region */ 226885Swollman a_out->a_entry < virtual_offset || 227885Swollman a_out->a_entry >= virtual_offset + a_out->a_text || 228885Swollman 229885Swollman /* text and data size must each be page rounded */ 230220238Skib a_out->a_text & PAGE_MASK || a_out->a_data & PAGE_MASK 231220238Skib 232220238Skib#ifdef __amd64__ 233220238Skib || 234220238Skib /* overflows */ 235220238Skib virtual_offset + a_out->a_text + a_out->a_data + bss_size > UINT_MAX 236220238Skib#endif 237220238Skib ) 238885Swollman return (-1); 239885Swollman 240885Swollman /* text + data can't exceed file size */ 24112130Sdg if (a_out->a_data + a_out->a_text > imgp->attr->va_size) 242885Swollman return (EFAULT); 243885Swollman 244885Swollman /* 245885Swollman * text/data/bss must not exceed limits 246885Swollman */ 247125454Sjhb PROC_LOCK(imgp->proc); 248885Swollman if (/* text can't exceed maximum text size */ 24984783Sps a_out->a_text > maxtsiz || 250885Swollman 251885Swollman /* data + bss can't exceed rlimit */ 252220373Strasz a_out->a_data + bss_size > lim_cur(imgp->proc, RLIMIT_DATA) || 253220373Strasz racct_set(imgp->proc, RACCT_DATA, a_out->a_data + bss_size) != 0) { 254125454Sjhb PROC_UNLOCK(imgp->proc); 255885Swollman return (ENOMEM); 256125454Sjhb } 257125454Sjhb PROC_UNLOCK(imgp->proc); 258885Swollman 259885Swollman /* 260153698Salc * Avoid a possible deadlock if the current address space is destroyed 261153698Salc * and that address space maps the locked vnode. In the common case, 262153698Salc * the locked vnode's v_usecount is decremented but remains greater 263153698Salc * than zero. Consequently, the vnode lock is not needed by vrele(). 264153698Salc * However, in cases where the vnode lock is external, such as nullfs, 265153698Salc * v_usecount may become zero. 266153698Salc */ 267175294Sattilio VOP_UNLOCK(imgp->vp, 0); 268153698Salc 269153698Salc /* 270885Swollman * Destroy old process VM and create a new one (with a new stack) 271885Swollman */ 272173361Skib error = exec_new_vmspace(imgp, &aout_sysvec); 273885Swollman 274175202Sattilio vn_lock(imgp->vp, LK_EXCLUSIVE | LK_RETRY); 275173361Skib if (error) 276173361Skib return (error); 277153698Salc 278885Swollman /* 27924848Sdyson * The vm space can be changed by exec_new_vmspace 28024848Sdyson */ 28124848Sdyson vmspace = imgp->proc->p_vmspace; 28224848Sdyson 28399487Sjeff object = imgp->object; 28444469Salc map = &vmspace->vm_map; 28544469Salc vm_map_lock(map); 28632446Sdyson vm_object_reference(object); 28732446Sdyson 28832446Sdyson text_end = virtual_offset + a_out->a_text; 28944626Salc error = vm_map_insert(map, object, 29032446Sdyson file_offset, 29132446Sdyson virtual_offset, text_end, 29232446Sdyson VM_PROT_READ | VM_PROT_EXECUTE, VM_PROT_ALL, 29347258Salc MAP_COPY_ON_WRITE | MAP_PREFAULT); 29444469Salc if (error) { 29544469Salc vm_map_unlock(map); 296156766Salc vm_object_deallocate(object); 297885Swollman return (error); 29844469Salc } 29932446Sdyson data_end = text_end + a_out->a_data; 30032446Sdyson if (a_out->a_data) { 30132446Sdyson vm_object_reference(object); 30244626Salc error = vm_map_insert(map, object, 30332446Sdyson file_offset + a_out->a_text, 30432446Sdyson text_end, data_end, 30532446Sdyson VM_PROT_ALL, VM_PROT_ALL, 30647258Salc MAP_COPY_ON_WRITE | MAP_PREFAULT); 30744469Salc if (error) { 30844469Salc vm_map_unlock(map); 309156766Salc vm_object_deallocate(object); 31032446Sdyson return (error); 31144469Salc } 31232446Sdyson } 313885Swollman 31432446Sdyson if (bss_size) { 31544626Salc error = vm_map_insert(map, NULL, 0, 31632446Sdyson data_end, data_end + bss_size, 31732446Sdyson VM_PROT_ALL, VM_PROT_ALL, 0); 31844469Salc if (error) { 31944469Salc vm_map_unlock(map); 3206579Sdg return (error); 32144469Salc } 3226579Sdg } 32344469Salc vm_map_unlock(map); 32444469Salc 325885Swollman /* Fill in process VM information */ 326885Swollman vmspace->vm_tsize = a_out->a_text >> PAGE_SHIFT; 327885Swollman vmspace->vm_dsize = (a_out->a_data + bss_size) >> PAGE_SHIFT; 32837656Sbde vmspace->vm_taddr = (caddr_t) (uintptr_t) virtual_offset; 32937656Sbde vmspace->vm_daddr = (caddr_t) (uintptr_t) 33037656Sbde (virtual_offset + a_out->a_text); 331885Swollman 332885Swollman /* Fill in image_params */ 33312130Sdg imgp->interpreted = 0; 33412130Sdg imgp->entry_addr = a_out->a_entry; 3358876Srgrimes 33612130Sdg imgp->proc->p_sysent = &aout_sysvec; 33710221Sdg 338885Swollman return (0); 339885Swollman} 340886Swollman 341886Swollman/* 342886Swollman * Tell kern_execve.c about it, with a little help from the linker. 343886Swollman */ 34443402Sdillonstatic struct execsw aout_execsw = { exec_aout_imgact, "a.out" }; 34540435SpeterEXEC_SET(aout, aout_execsw); 346