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 */ 26cfefd687SGarrett Wollman 27677b542eSDavid E. O'Brien #include <sys/cdefs.h> 28677b542eSDavid E. O'Brien __FBSDID("$FreeBSD$"); 29677b542eSDavid E. O'Brien 3026f9a767SRodney W. Grimes #include <sys/param.h> 3126f9a767SRodney W. Grimes #include <sys/exec.h> 3226f9a767SRodney W. Grimes #include <sys/imgact.h> 33bc6d7444SDavid Greenman #include <sys/imgact_aout.h> 3426f9a767SRodney W. Grimes #include <sys/kernel.h> 35fb919e4dSMark Murray #include <sys/lock.h> 36e5d6cd0cSBruce Evans #include <sys/malloc.h> 37fb919e4dSMark Murray #include <sys/mutex.h> 38a794e791SBruce Evans #include <sys/proc.h> 39fb919e4dSMark Murray #include <sys/resourcevar.h> 4022d4b0fbSJohn Polstra #include <sys/signalvar.h> 4122d4b0fbSJohn Polstra #include <sys/syscall.h> 42e5d6cd0cSBruce Evans #include <sys/sysent.h> 43e5d6cd0cSBruce Evans #include <sys/systm.h> 44a794e791SBruce Evans #include <sys/vnode.h> 45fb919e4dSMark Murray #include <sys/user.h> 46fb919e4dSMark Murray 47710ded3aSPeter Wemm #include <machine/frame.h> 48e5d6cd0cSBruce Evans #include <machine/md_var.h> 49cfefd687SGarrett Wollman 5026f9a767SRodney W. Grimes #include <vm/vm.h> 51efeaf95aSDavid Greenman #include <vm/pmap.h> 52efeaf95aSDavid Greenman #include <vm/vm_map.h> 531616db3cSJohn Dyson #include <vm/vm_object.h> 54e5d6cd0cSBruce Evans #include <vm/vm_param.h> 55cfefd687SGarrett Wollman 564d77a549SAlfred Perlstein static int exec_aout_imgact(struct image_params *imgp); 57f36ba452SJake Burkholder static int aout_fixup(register_t **stack_base, struct image_params *imgp); 587ee050b7SBruce Evans 5922d4b0fbSJohn Polstra struct sysentvec aout_sysvec = { 6022d4b0fbSJohn Polstra SYS_MAXSYSCALL, 6122d4b0fbSJohn Polstra sysent, 6222d4b0fbSJohn Polstra 0, 6322d4b0fbSJohn Polstra 0, 64f36ba452SJake Burkholder NULL, 6522d4b0fbSJohn Polstra 0, 66f36ba452SJake Burkholder NULL, 67f36ba452SJake Burkholder NULL, 68f36ba452SJake Burkholder aout_fixup, 6922d4b0fbSJohn Polstra sendsig, 7022d4b0fbSJohn Polstra sigcode, 7122d4b0fbSJohn Polstra &szsigcode, 72f36ba452SJake Burkholder NULL, 7322d4b0fbSJohn Polstra "FreeBSD a.out", 74806d7daaSMarcel Moolenaar aout_coredump, 75806d7daaSMarcel Moolenaar NULL, 76f36ba452SJake Burkholder MINSIGSTKSZ, 77f36ba452SJake Burkholder PAGE_SIZE, 78f36ba452SJake Burkholder VM_MIN_ADDRESS, 79f36ba452SJake Burkholder VM_MAXUSER_ADDRESS, 80f36ba452SJake Burkholder USRSTACK, 81f36ba452SJake Burkholder PS_STRINGS, 82f36ba452SJake Burkholder VM_PROT_ALL, 83f36ba452SJake Burkholder exec_copyout_strings, 84c460ac3aSPeter Wemm exec_setregs, 85c460ac3aSPeter Wemm NULL 8622d4b0fbSJohn Polstra }; 8722d4b0fbSJohn Polstra 88b9e91a85SBruce Evans static int 89f36ba452SJake Burkholder aout_fixup(stack_base, imgp) 90f36ba452SJake Burkholder register_t **stack_base; 91f36ba452SJake Burkholder struct image_params *imgp; 92f36ba452SJake Burkholder { 93f36ba452SJake Burkholder 94f36ba452SJake Burkholder return (suword(--(*stack_base), imgp->argc)); 95f36ba452SJake Burkholder } 96f36ba452SJake Burkholder 97f36ba452SJake Burkholder static int 98c52007c2SDavid Greenman exec_aout_imgact(imgp) 99c52007c2SDavid Greenman struct image_params *imgp; 100cfefd687SGarrett Wollman { 101e0c95ed9SBruce Evans const struct exec *a_out = (const struct exec *) imgp->image_header; 1025856e12eSJohn Dyson struct vmspace *vmspace; 1031616db3cSJohn Dyson struct vnode *vp; 1042f33b2c0SAlan Cox vm_map_t map; 1051616db3cSJohn Dyson vm_object_t object; 1061616db3cSJohn Dyson vm_offset_t text_end, data_end; 107ede8dc43SBruce Evans unsigned long virtual_offset; 108a316d390SJohn Dyson unsigned long file_offset; 109cfefd687SGarrett Wollman unsigned long bss_size; 110bb56ec4aSPoul-Henning Kamp int error; 111cfefd687SGarrett Wollman 1120cddd8f0SMatthew Dillon GIANT_REQUIRED; 1130cddd8f0SMatthew Dillon 1141e1e0b44SSøren Schmidt /* 1151e1e0b44SSøren Schmidt * Linux and *BSD binaries look very much alike, 1161e1e0b44SSøren Schmidt * only the machine id is different: 117d3628763SRodney W. Grimes * 0x64 for Linux, 0x86 for *BSD, 0x00 for BSDI. 118185dc761SPeter Wemm * NetBSD is in network byte order.. ugh. 1191e1e0b44SSøren Schmidt */ 120d3628763SRodney W. Grimes if (((a_out->a_magic >> 16) & 0xff) != 0x86 && 121185dc761SPeter Wemm ((a_out->a_magic >> 16) & 0xff) != 0 && 122185dc761SPeter Wemm ((((int)ntohl(a_out->a_magic)) >> 16) & 0xff) != 0x86) 1231e1e0b44SSøren Schmidt return -1; 1241e1e0b44SSøren Schmidt 125cfefd687SGarrett Wollman /* 126cfefd687SGarrett Wollman * Set file/virtual offset based on a.out variant. 127cfefd687SGarrett Wollman * We do two cases: host byte order and network byte order 128cfefd687SGarrett Wollman * (for NetBSD compatibility) 129cfefd687SGarrett Wollman */ 130cfefd687SGarrett Wollman switch ((int)(a_out->a_magic & 0xffff)) { 131cfefd687SGarrett Wollman case ZMAGIC: 132cfefd687SGarrett Wollman virtual_offset = 0; 133cfefd687SGarrett Wollman if (a_out->a_text) { 134f8845af0SPoul-Henning Kamp file_offset = PAGE_SIZE; 135cfefd687SGarrett Wollman } else { 136cfefd687SGarrett Wollman /* Bill's "screwball mode" */ 137cfefd687SGarrett Wollman file_offset = 0; 138cfefd687SGarrett Wollman } 139cfefd687SGarrett Wollman break; 140cfefd687SGarrett Wollman case QMAGIC: 141f8845af0SPoul-Henning Kamp virtual_offset = PAGE_SIZE; 142cfefd687SGarrett Wollman file_offset = 0; 1434fe88fe6SJohn Polstra /* Pass PS_STRINGS for BSD/OS binaries only. */ 1444fe88fe6SJohn Polstra if (N_GETMID(*a_out) == MID_ZERO) 14505ba50f5SJake Burkholder imgp->ps_strings = aout_sysvec.sv_psstrings; 146cfefd687SGarrett Wollman break; 147cfefd687SGarrett Wollman default: 148cfefd687SGarrett Wollman /* NetBSD compatibility */ 149cfefd687SGarrett Wollman switch ((int)(ntohl(a_out->a_magic) & 0xffff)) { 150cfefd687SGarrett Wollman case ZMAGIC: 151cfefd687SGarrett Wollman case QMAGIC: 152f8845af0SPoul-Henning Kamp virtual_offset = PAGE_SIZE; 153cfefd687SGarrett Wollman file_offset = 0; 154cfefd687SGarrett Wollman break; 155cfefd687SGarrett Wollman default: 156cfefd687SGarrett Wollman return (-1); 157cfefd687SGarrett Wollman } 158cfefd687SGarrett Wollman } 159cfefd687SGarrett Wollman 160f8845af0SPoul-Henning Kamp bss_size = roundup(a_out->a_bss, PAGE_SIZE); 161cfefd687SGarrett Wollman 162cfefd687SGarrett Wollman /* 163cfefd687SGarrett Wollman * Check various fields in header for validity/bounds. 164cfefd687SGarrett Wollman */ 165cfefd687SGarrett Wollman if (/* entry point must lay with text region */ 166cfefd687SGarrett Wollman a_out->a_entry < virtual_offset || 167cfefd687SGarrett Wollman a_out->a_entry >= virtual_offset + a_out->a_text || 168cfefd687SGarrett Wollman 169cfefd687SGarrett Wollman /* text and data size must each be page rounded */ 170f8845af0SPoul-Henning Kamp a_out->a_text & PAGE_MASK || a_out->a_data & PAGE_MASK) 171cfefd687SGarrett Wollman return (-1); 172cfefd687SGarrett Wollman 173cfefd687SGarrett Wollman /* text + data can't exceed file size */ 174c52007c2SDavid Greenman if (a_out->a_data + a_out->a_text > imgp->attr->va_size) 175cfefd687SGarrett Wollman return (EFAULT); 176cfefd687SGarrett Wollman 177cfefd687SGarrett Wollman /* 178cfefd687SGarrett Wollman * text/data/bss must not exceed limits 179cfefd687SGarrett Wollman */ 18091d5354aSJohn Baldwin PROC_LOCK(imgp->proc); 181cfefd687SGarrett Wollman if (/* text can't exceed maximum text size */ 182cbc89bfbSPaul Saab a_out->a_text > maxtsiz || 183cfefd687SGarrett Wollman 184cfefd687SGarrett Wollman /* data + bss can't exceed rlimit */ 18591d5354aSJohn Baldwin a_out->a_data + bss_size > lim_cur(imgp->proc, RLIMIT_DATA)) { 18691d5354aSJohn Baldwin PROC_UNLOCK(imgp->proc); 187cfefd687SGarrett Wollman return (ENOMEM); 18891d5354aSJohn Baldwin } 18991d5354aSJohn Baldwin PROC_UNLOCK(imgp->proc); 190cfefd687SGarrett Wollman 191cfefd687SGarrett Wollman /* copy in arguments and/or environment from old process */ 192c52007c2SDavid Greenman error = exec_extract_strings(imgp); 193cfefd687SGarrett Wollman if (error) 194cfefd687SGarrett Wollman return (error); 195cfefd687SGarrett Wollman 196cfefd687SGarrett Wollman /* 197cfefd687SGarrett Wollman * Destroy old process VM and create a new one (with a new stack) 198cfefd687SGarrett Wollman */ 19905ba50f5SJake Burkholder exec_new_vmspace(imgp, &aout_sysvec); 200cfefd687SGarrett Wollman 201cfefd687SGarrett Wollman /* 2025856e12eSJohn Dyson * The vm space can be changed by exec_new_vmspace 2035856e12eSJohn Dyson */ 2045856e12eSJohn Dyson vmspace = imgp->proc->p_vmspace; 2055856e12eSJohn Dyson 2061616db3cSJohn Dyson vp = imgp->vp; 2070b2ed1aeSJeff Roberson object = imgp->object; 2082f33b2c0SAlan Cox map = &vmspace->vm_map; 2092f33b2c0SAlan Cox vm_map_lock(map); 2101616db3cSJohn Dyson vm_object_reference(object); 2111616db3cSJohn Dyson 2121616db3cSJohn Dyson text_end = virtual_offset + a_out->a_text; 2130a91231dSAlan Cox error = vm_map_insert(map, object, 2141616db3cSJohn Dyson file_offset, 2151616db3cSJohn Dyson virtual_offset, text_end, 2161616db3cSJohn Dyson VM_PROT_READ | VM_PROT_EXECUTE, VM_PROT_ALL, 217e972780aSAlan Cox MAP_COPY_ON_WRITE | MAP_PREFAULT); 2182f33b2c0SAlan Cox if (error) { 2192f33b2c0SAlan Cox vm_map_unlock(map); 220cfefd687SGarrett Wollman return (error); 2212f33b2c0SAlan Cox } 2221616db3cSJohn Dyson data_end = text_end + a_out->a_data; 2231616db3cSJohn Dyson if (a_out->a_data) { 2241616db3cSJohn Dyson vm_object_reference(object); 2250a91231dSAlan Cox error = vm_map_insert(map, object, 2261616db3cSJohn Dyson file_offset + a_out->a_text, 2271616db3cSJohn Dyson text_end, data_end, 2281616db3cSJohn Dyson VM_PROT_ALL, VM_PROT_ALL, 229e972780aSAlan Cox MAP_COPY_ON_WRITE | MAP_PREFAULT); 2302f33b2c0SAlan Cox if (error) { 2312f33b2c0SAlan Cox vm_map_unlock(map); 2321616db3cSJohn Dyson return (error); 2331616db3cSJohn Dyson } 2342f33b2c0SAlan Cox } 235cfefd687SGarrett Wollman 2361616db3cSJohn Dyson if (bss_size) { 2370a91231dSAlan Cox error = vm_map_insert(map, NULL, 0, 2381616db3cSJohn Dyson data_end, data_end + bss_size, 2391616db3cSJohn Dyson VM_PROT_ALL, VM_PROT_ALL, 0); 2402f33b2c0SAlan Cox if (error) { 2412f33b2c0SAlan Cox vm_map_unlock(map); 242cfefd687SGarrett Wollman return (error); 24368940ac1SDavid Greenman } 2442f33b2c0SAlan Cox } 2452f33b2c0SAlan Cox vm_map_unlock(map); 246cfefd687SGarrett Wollman 247cfefd687SGarrett Wollman /* Fill in process VM information */ 248cfefd687SGarrett Wollman vmspace->vm_tsize = a_out->a_text >> PAGE_SHIFT; 249cfefd687SGarrett Wollman vmspace->vm_dsize = (a_out->a_data + bss_size) >> PAGE_SHIFT; 2507cd99438SBruce Evans vmspace->vm_taddr = (caddr_t) (uintptr_t) virtual_offset; 2517cd99438SBruce Evans vmspace->vm_daddr = (caddr_t) (uintptr_t) 2527cd99438SBruce Evans (virtual_offset + a_out->a_text); 253cfefd687SGarrett Wollman 254cfefd687SGarrett Wollman /* Fill in image_params */ 255c52007c2SDavid Greenman imgp->interpreted = 0; 256c52007c2SDavid Greenman imgp->entry_addr = a_out->a_entry; 257cfefd687SGarrett Wollman 258c52007c2SDavid Greenman imgp->proc->p_sysent = &aout_sysvec; 259c0e5de7dSDavid Greenman 260cfefd687SGarrett Wollman return (0); 261cfefd687SGarrett Wollman } 26292d91f76SGarrett Wollman 26392d91f76SGarrett Wollman /* 2649fe42598SBruce Evans * Dump core, into a file named as described in the comments for 2659fe42598SBruce Evans * expand_name(), unless the process was setuid/setgid. 26622d4b0fbSJohn Polstra */ 26722d4b0fbSJohn Polstra int 268b40ce416SJulian Elischer aout_coredump(td, vp, limit) 269b40ce416SJulian Elischer register struct thread *td; 27022d4b0fbSJohn Polstra register struct vnode *vp; 271fca666a1SJulian Elischer off_t limit; 272fca666a1SJulian Elischer { 273b40ce416SJulian Elischer struct proc *p = td->td_proc; 274a854ed98SJohn Baldwin register struct ucred *cred = td->td_ucred; 27522d4b0fbSJohn Polstra register struct vmspace *vm = p->p_vmspace; 276a9f9df5dSPeter Wemm char *tempuser; 277b9e91a85SBruce Evans int error; 27822d4b0fbSJohn Polstra 27999a17113SPeter Wemm if (ctob((uarea_pages + kstack_pages) 280b40ce416SJulian Elischer + vm->vm_dsize + vm->vm_ssize) >= limit) 28122d4b0fbSJohn Polstra return (EFAULT); 28299a17113SPeter Wemm tempuser = malloc(ctob(uarea_pages + kstack_pages), M_TEMP, 283a163d034SWarner Losh M_WAITOK | M_ZERO); 284710ded3aSPeter Wemm if (tempuser == NULL) 285710ded3aSPeter Wemm return (ENOMEM); 286a9f9df5dSPeter Wemm PROC_LOCK(p); 287a9f9df5dSPeter Wemm fill_kinfo_proc(p, &p->p_uarea->u_kproc); 288a9f9df5dSPeter Wemm PROC_UNLOCK(p); 289710ded3aSPeter Wemm bcopy(p->p_uarea, tempuser, sizeof(struct user)); 290710ded3aSPeter Wemm bcopy(td->td_frame, 29199a17113SPeter Wemm tempuser + ctob(uarea_pages) + 292710ded3aSPeter Wemm ((caddr_t)td->td_frame - (caddr_t)td->td_kstack), 293710ded3aSPeter Wemm sizeof(struct trapframe)); 294710ded3aSPeter Wemm error = vn_rdwr(UIO_WRITE, vp, (caddr_t)tempuser, 29599a17113SPeter Wemm ctob(uarea_pages + kstack_pages), 296710ded3aSPeter Wemm (off_t)0, UIO_SYSSPACE, IO_UNIT, cred, NOCRED, 297710ded3aSPeter Wemm (int *)NULL, td); 298710ded3aSPeter Wemm free(tempuser, M_TEMP); 29922d4b0fbSJohn Polstra if (error == 0) 300b40ce416SJulian Elischer error = vn_rdwr(UIO_WRITE, vp, vm->vm_daddr, 301b40ce416SJulian Elischer (int)ctob(vm->vm_dsize), 30299a17113SPeter Wemm (off_t)ctob(uarea_pages + kstack_pages), UIO_USERSPACE, 3039ca43589SRobert Watson IO_UNIT | IO_DIRECT, cred, NOCRED, (int *) NULL, td); 30422d4b0fbSJohn Polstra if (error == 0) 30506ae1e91SMatthew Dillon error = vn_rdwr_inchunks(UIO_WRITE, vp, 30605ba50f5SJake Burkholder (caddr_t)trunc_page(p->p_sysent->sv_usrstack - 30705ba50f5SJake Burkholder ctob(vm->vm_ssize)), round_page(ctob(vm->vm_ssize)), 30899a17113SPeter Wemm (off_t)ctob(uarea_pages + kstack_pages) + 309b40ce416SJulian Elischer ctob(vm->vm_dsize), UIO_USERSPACE, 3109ca43589SRobert Watson IO_UNIT | IO_DIRECT, cred, NOCRED, (int *) NULL, td); 311b9e91a85SBruce Evans return (error); 31222d4b0fbSJohn Polstra } 31322d4b0fbSJohn Polstra 31422d4b0fbSJohn Polstra /* 31592d91f76SGarrett Wollman * Tell kern_execve.c about it, with a little help from the linker. 31692d91f76SGarrett Wollman */ 317820ca326SMatthew Dillon static struct execsw aout_execsw = { exec_aout_imgact, "a.out" }; 318aa855a59SPeter Wemm EXEC_SET(aout, aout_execsw); 319