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_errsize = 0, 74183322Skib .sv_errtbl = NULL, 75183322Skib .sv_transtrap = NULL, 76183322Skib .sv_fixup = aout_fixup, 77183322Skib .sv_sendsig = sendsig, 78183322Skib .sv_sigcode = sigcode, 79183322Skib .sv_szsigcode = &szsigcode, 80183322Skib .sv_name = "FreeBSD a.out", 81183322Skib .sv_coredump = NULL, 82183322Skib .sv_imgact_try = NULL, 83183322Skib .sv_minsigstksz = MINSIGSTKSZ, 84183322Skib .sv_pagesize = PAGE_SIZE, 85183322Skib .sv_minuser = VM_MIN_ADDRESS, 86183322Skib .sv_maxuser = VM_MAXUSER_ADDRESS, 87183322Skib .sv_usrstack = USRSTACK, 88183322Skib .sv_psstrings = PS_STRINGS, 89183322Skib .sv_stackprot = VM_PROT_ALL, 90183322Skib .sv_copyout_strings = exec_copyout_strings, 91183322Skib .sv_setregs = exec_setregs, 92183322Skib .sv_fixlimit = NULL, 93185169Skib .sv_maxssiz = NULL, 94220238Skib .sv_flags = SV_ABI_FREEBSD | SV_AOUT | SV_IA32 | SV_ILP32, 95208453Skib .sv_set_syscall_retval = cpu_set_syscall_retval, 96208453Skib .sv_fetch_syscall_args = cpu_fetch_syscall_args, 97208453Skib .sv_syscallnames = syscallnames, 98219405Sdchagin .sv_schedtail = NULL, 99283382Sdchagin .sv_thread_detach = NULL, 100293613Sdchagin .sv_trap = NULL, 10139154Sjdp}; 10239154Sjdp 103220238Skib#elif defined(__amd64__) 104220238Skib 105223164Skib#define AOUT32_USRSTACK 0xbfc00000 106220238Skib#define AOUT32_PS_STRINGS \ 107220238Skib (AOUT32_USRSTACK - sizeof(struct freebsd32_ps_strings)) 108238687Skib#define AOUT32_MINUSER FREEBSD32_MINUSER 109220238Skib 110220238Skibextern const char *freebsd32_syscallnames[]; 111220238Skibextern u_long ia32_maxssiz; 112220238Skib 113220238Skibstruct sysentvec aout_sysvec = { 114220238Skib .sv_size = FREEBSD32_SYS_MAXSYSCALL, 115220238Skib .sv_table = freebsd32_sysent, 116220238Skib .sv_mask = 0, 117220238Skib .sv_errsize = 0, 118220238Skib .sv_errtbl = NULL, 119220238Skib .sv_transtrap = NULL, 120220238Skib .sv_fixup = aout_fixup, 121220238Skib .sv_sendsig = ia32_sendsig, 122220238Skib .sv_sigcode = ia32_sigcode, 123220238Skib .sv_szsigcode = &sz_ia32_sigcode, 124220238Skib .sv_name = "FreeBSD a.out", 125220238Skib .sv_coredump = NULL, 126220238Skib .sv_imgact_try = NULL, 127220238Skib .sv_minsigstksz = MINSIGSTKSZ, 128220238Skib .sv_pagesize = IA32_PAGE_SIZE, 129238687Skib .sv_minuser = AOUT32_MINUSER, 130220238Skib .sv_maxuser = AOUT32_USRSTACK, 131220238Skib .sv_usrstack = AOUT32_USRSTACK, 132220238Skib .sv_psstrings = AOUT32_PS_STRINGS, 133220238Skib .sv_stackprot = VM_PROT_ALL, 134220238Skib .sv_copyout_strings = freebsd32_copyout_strings, 135220238Skib .sv_setregs = ia32_setregs, 136220238Skib .sv_fixlimit = ia32_fixlimit, 137220238Skib .sv_maxssiz = &ia32_maxssiz, 138220238Skib .sv_flags = SV_ABI_FREEBSD | SV_AOUT | SV_IA32 | SV_ILP32, 139220238Skib .sv_set_syscall_retval = ia32_set_syscall_retval, 140220238Skib .sv_fetch_syscall_args = ia32_fetch_syscall_args, 141220238Skib .sv_syscallnames = freebsd32_syscallnames, 142220238Skib}; 143220238Skib#else 144220238Skib#error "Port me" 145220238Skib#endif 146220238Skib 14750901Sbdestatic int 148220238Skibaout_fixup(register_t **stack_base, struct image_params *imgp) 149102808Sjake{ 150102808Sjake 151220238Skib *(char **)stack_base -= sizeof(uint32_t); 152223165Skib return (suword32(*stack_base, imgp->args->argc)); 153102808Sjake} 154102808Sjake 155102808Sjakestatic int 156220238Skibexec_aout_imgact(struct image_params *imgp) 157885Swollman{ 15817974Sbde const struct exec *a_out = (const struct exec *) imgp->image_header; 15924848Sdyson struct vmspace *vmspace; 16044469Salc vm_map_t map; 16132446Sdyson vm_object_t object; 16232446Sdyson vm_offset_t text_end, data_end; 16314703Sbde unsigned long virtual_offset; 16412767Sdyson unsigned long file_offset; 165885Swollman unsigned long bss_size; 1663098Sphk int error; 167885Swollman 168885Swollman /* 1696380Ssos * Linux and *BSD binaries look very much alike, 1708876Srgrimes * only the machine id is different: 1719202Srgrimes * 0x64 for Linux, 0x86 for *BSD, 0x00 for BSDI. 17214363Speter * NetBSD is in network byte order.. ugh. 1736380Ssos */ 174237694Simp if (((a_out->a_midmag >> 16) & 0xff) != 0x86 && 175237694Simp ((a_out->a_midmag >> 16) & 0xff) != 0 && 176237694Simp ((((int)ntohl(a_out->a_midmag)) >> 16) & 0xff) != 0x86) 1779202Srgrimes return -1; 1786380Ssos 1796380Ssos /* 180885Swollman * Set file/virtual offset based on a.out variant. 181885Swollman * We do two cases: host byte order and network byte order 182885Swollman * (for NetBSD compatibility) 183885Swollman */ 184237694Simp switch ((int)(a_out->a_midmag & 0xffff)) { 185885Swollman case ZMAGIC: 186885Swollman virtual_offset = 0; 187885Swollman if (a_out->a_text) { 18815538Sphk file_offset = PAGE_SIZE; 189885Swollman } else { 190885Swollman /* Bill's "screwball mode" */ 191885Swollman file_offset = 0; 192885Swollman } 193885Swollman break; 194885Swollman case QMAGIC: 19515538Sphk virtual_offset = PAGE_SIZE; 196885Swollman file_offset = 0; 19745270Sjdp /* Pass PS_STRINGS for BSD/OS binaries only. */ 19845270Sjdp if (N_GETMID(*a_out) == MID_ZERO) 199103767Sjake imgp->ps_strings = aout_sysvec.sv_psstrings; 200885Swollman break; 201885Swollman default: 202885Swollman /* NetBSD compatibility */ 203237694Simp switch ((int)(ntohl(a_out->a_midmag) & 0xffff)) { 204885Swollman case ZMAGIC: 205885Swollman case QMAGIC: 20615538Sphk virtual_offset = PAGE_SIZE; 207885Swollman file_offset = 0; 208885Swollman break; 209885Swollman default: 210885Swollman return (-1); 211885Swollman } 212885Swollman } 213885Swollman 21415538Sphk bss_size = roundup(a_out->a_bss, PAGE_SIZE); 215885Swollman 216885Swollman /* 217885Swollman * Check various fields in header for validity/bounds. 218885Swollman */ 219885Swollman if (/* entry point must lay with text region */ 220885Swollman a_out->a_entry < virtual_offset || 221885Swollman a_out->a_entry >= virtual_offset + a_out->a_text || 222885Swollman 223885Swollman /* text and data size must each be page rounded */ 224220238Skib a_out->a_text & PAGE_MASK || a_out->a_data & PAGE_MASK 225220238Skib 226220238Skib#ifdef __amd64__ 227220238Skib || 228220238Skib /* overflows */ 229220238Skib virtual_offset + a_out->a_text + a_out->a_data + bss_size > UINT_MAX 230220238Skib#endif 231220238Skib ) 232885Swollman return (-1); 233885Swollman 234885Swollman /* text + data can't exceed file size */ 23512130Sdg if (a_out->a_data + a_out->a_text > imgp->attr->va_size) 236885Swollman return (EFAULT); 237885Swollman 238885Swollman /* 239885Swollman * text/data/bss must not exceed limits 240885Swollman */ 241125454Sjhb PROC_LOCK(imgp->proc); 242885Swollman if (/* text can't exceed maximum text size */ 24384783Sps a_out->a_text > maxtsiz || 244885Swollman 245885Swollman /* data + bss can't exceed rlimit */ 246284215Smjg a_out->a_data + bss_size > lim_cur_proc(imgp->proc, RLIMIT_DATA) || 247220373Strasz racct_set(imgp->proc, RACCT_DATA, a_out->a_data + bss_size) != 0) { 248125454Sjhb PROC_UNLOCK(imgp->proc); 249885Swollman return (ENOMEM); 250125454Sjhb } 251125454Sjhb PROC_UNLOCK(imgp->proc); 252885Swollman 253885Swollman /* 254153698Salc * Avoid a possible deadlock if the current address space is destroyed 255153698Salc * and that address space maps the locked vnode. In the common case, 256153698Salc * the locked vnode's v_usecount is decremented but remains greater 257153698Salc * than zero. Consequently, the vnode lock is not needed by vrele(). 258153698Salc * However, in cases where the vnode lock is external, such as nullfs, 259153698Salc * v_usecount may become zero. 260153698Salc */ 261175294Sattilio VOP_UNLOCK(imgp->vp, 0); 262153698Salc 263153698Salc /* 264885Swollman * Destroy old process VM and create a new one (with a new stack) 265885Swollman */ 266173361Skib error = exec_new_vmspace(imgp, &aout_sysvec); 267885Swollman 268175202Sattilio vn_lock(imgp->vp, LK_EXCLUSIVE | LK_RETRY); 269173361Skib if (error) 270173361Skib return (error); 271153698Salc 272885Swollman /* 27324848Sdyson * The vm space can be changed by exec_new_vmspace 27424848Sdyson */ 27524848Sdyson vmspace = imgp->proc->p_vmspace; 27624848Sdyson 27799487Sjeff object = imgp->object; 27844469Salc map = &vmspace->vm_map; 27944469Salc vm_map_lock(map); 28032446Sdyson vm_object_reference(object); 28132446Sdyson 28232446Sdyson text_end = virtual_offset + a_out->a_text; 28344626Salc error = vm_map_insert(map, object, 28432446Sdyson file_offset, 28532446Sdyson virtual_offset, text_end, 28632446Sdyson VM_PROT_READ | VM_PROT_EXECUTE, VM_PROT_ALL, 28747258Salc MAP_COPY_ON_WRITE | MAP_PREFAULT); 28844469Salc if (error) { 28944469Salc vm_map_unlock(map); 290156766Salc vm_object_deallocate(object); 291885Swollman return (error); 29244469Salc } 29332446Sdyson data_end = text_end + a_out->a_data; 29432446Sdyson if (a_out->a_data) { 29532446Sdyson vm_object_reference(object); 29644626Salc error = vm_map_insert(map, object, 29732446Sdyson file_offset + a_out->a_text, 29832446Sdyson text_end, data_end, 29932446Sdyson VM_PROT_ALL, VM_PROT_ALL, 30047258Salc MAP_COPY_ON_WRITE | MAP_PREFAULT); 30144469Salc if (error) { 30244469Salc vm_map_unlock(map); 303156766Salc vm_object_deallocate(object); 30432446Sdyson return (error); 30544469Salc } 30632446Sdyson } 307885Swollman 30832446Sdyson if (bss_size) { 30944626Salc error = vm_map_insert(map, NULL, 0, 31032446Sdyson data_end, data_end + bss_size, 31132446Sdyson VM_PROT_ALL, VM_PROT_ALL, 0); 31244469Salc if (error) { 31344469Salc vm_map_unlock(map); 3146579Sdg return (error); 31544469Salc } 3166579Sdg } 31744469Salc vm_map_unlock(map); 31844469Salc 319885Swollman /* Fill in process VM information */ 320885Swollman vmspace->vm_tsize = a_out->a_text >> PAGE_SHIFT; 321885Swollman vmspace->vm_dsize = (a_out->a_data + bss_size) >> PAGE_SHIFT; 32237656Sbde vmspace->vm_taddr = (caddr_t) (uintptr_t) virtual_offset; 32337656Sbde vmspace->vm_daddr = (caddr_t) (uintptr_t) 32437656Sbde (virtual_offset + a_out->a_text); 325885Swollman 326885Swollman /* Fill in image_params */ 32712130Sdg imgp->interpreted = 0; 32812130Sdg imgp->entry_addr = a_out->a_entry; 3298876Srgrimes 33012130Sdg imgp->proc->p_sysent = &aout_sysvec; 33110221Sdg 332885Swollman return (0); 333885Swollman} 334886Swollman 335886Swollman/* 336886Swollman * Tell kern_execve.c about it, with a little help from the linker. 337886Swollman */ 33843402Sdillonstatic struct execsw aout_execsw = { exec_aout_imgact, "a.out" }; 33940435SpeterEXEC_SET(aout, aout_execsw); 340