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 * 26c3aac50fSPeter Wemm * $FreeBSD$ 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 78b9e91a85SBruce 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; 1224fe88fe6SJohn Polstra /* Pass PS_STRINGS for BSD/OS binaries only. */ 1234fe88fe6SJohn Polstra if (N_GETMID(*a_out) == MID_ZERO) 1244fe88fe6SJohn Polstra imgp->ps_strings = PS_STRINGS; 125cfefd687SGarrett Wollman break; 126cfefd687SGarrett Wollman default: 127cfefd687SGarrett Wollman /* NetBSD compatibility */ 128cfefd687SGarrett Wollman switch ((int)(ntohl(a_out->a_magic) & 0xffff)) { 129cfefd687SGarrett Wollman case ZMAGIC: 130cfefd687SGarrett Wollman case QMAGIC: 131f8845af0SPoul-Henning Kamp virtual_offset = PAGE_SIZE; 132cfefd687SGarrett Wollman file_offset = 0; 133cfefd687SGarrett Wollman break; 134cfefd687SGarrett Wollman default: 135cfefd687SGarrett Wollman return (-1); 136cfefd687SGarrett Wollman } 137cfefd687SGarrett Wollman } 138cfefd687SGarrett Wollman 139f8845af0SPoul-Henning Kamp bss_size = roundup(a_out->a_bss, PAGE_SIZE); 140cfefd687SGarrett Wollman 141cfefd687SGarrett Wollman /* 142cfefd687SGarrett Wollman * Check various fields in header for validity/bounds. 143cfefd687SGarrett Wollman */ 144cfefd687SGarrett Wollman if (/* entry point must lay with text region */ 145cfefd687SGarrett Wollman a_out->a_entry < virtual_offset || 146cfefd687SGarrett Wollman a_out->a_entry >= virtual_offset + a_out->a_text || 147cfefd687SGarrett Wollman 148cfefd687SGarrett Wollman /* text and data size must each be page rounded */ 149f8845af0SPoul-Henning Kamp a_out->a_text & PAGE_MASK || a_out->a_data & PAGE_MASK) 150cfefd687SGarrett Wollman return (-1); 151cfefd687SGarrett Wollman 152cfefd687SGarrett Wollman /* text + data can't exceed file size */ 153c52007c2SDavid Greenman if (a_out->a_data + a_out->a_text > imgp->attr->va_size) 154cfefd687SGarrett Wollman return (EFAULT); 155cfefd687SGarrett Wollman 156cfefd687SGarrett Wollman /* 157cfefd687SGarrett Wollman * text/data/bss must not exceed limits 158cfefd687SGarrett Wollman */ 159cfefd687SGarrett Wollman if (/* text can't exceed maximum text size */ 160cfefd687SGarrett Wollman a_out->a_text > MAXTSIZ || 161cfefd687SGarrett Wollman 162cfefd687SGarrett Wollman /* data + bss can't exceed rlimit */ 163cfefd687SGarrett Wollman a_out->a_data + bss_size > 164c52007c2SDavid Greenman imgp->proc->p_rlimit[RLIMIT_DATA].rlim_cur) 165cfefd687SGarrett Wollman return (ENOMEM); 166cfefd687SGarrett Wollman 167cfefd687SGarrett Wollman /* copy in arguments and/or environment from old process */ 168c52007c2SDavid Greenman error = exec_extract_strings(imgp); 169cfefd687SGarrett Wollman if (error) 170cfefd687SGarrett Wollman return (error); 171cfefd687SGarrett Wollman 172cfefd687SGarrett Wollman /* 173cfefd687SGarrett Wollman * Destroy old process VM and create a new one (with a new stack) 174cfefd687SGarrett Wollman */ 175c52007c2SDavid Greenman exec_new_vmspace(imgp); 176cfefd687SGarrett Wollman 177cfefd687SGarrett Wollman /* 1785856e12eSJohn Dyson * The vm space can be changed by exec_new_vmspace 1795856e12eSJohn Dyson */ 1805856e12eSJohn Dyson vmspace = imgp->proc->p_vmspace; 1815856e12eSJohn Dyson 1821616db3cSJohn Dyson vp = imgp->vp; 1832f33b2c0SAlan Cox map = &vmspace->vm_map; 1842f33b2c0SAlan Cox vm_map_lock(map); 1851616db3cSJohn Dyson object = vp->v_object; 1861616db3cSJohn Dyson vm_object_reference(object); 1871616db3cSJohn Dyson 1881616db3cSJohn Dyson text_end = virtual_offset + a_out->a_text; 1890a91231dSAlan Cox error = vm_map_insert(map, object, 1901616db3cSJohn Dyson file_offset, 1911616db3cSJohn Dyson virtual_offset, text_end, 1921616db3cSJohn Dyson VM_PROT_READ | VM_PROT_EXECUTE, VM_PROT_ALL, 193e972780aSAlan Cox MAP_COPY_ON_WRITE | MAP_PREFAULT); 1942f33b2c0SAlan Cox if (error) { 1952f33b2c0SAlan Cox vm_map_unlock(map); 196cfefd687SGarrett Wollman return (error); 1972f33b2c0SAlan Cox } 1981616db3cSJohn Dyson data_end = text_end + a_out->a_data; 1991616db3cSJohn Dyson if (a_out->a_data) { 2001616db3cSJohn Dyson vm_object_reference(object); 2010a91231dSAlan Cox error = vm_map_insert(map, object, 2021616db3cSJohn Dyson file_offset + a_out->a_text, 2031616db3cSJohn Dyson text_end, data_end, 2041616db3cSJohn Dyson VM_PROT_ALL, VM_PROT_ALL, 205e972780aSAlan Cox MAP_COPY_ON_WRITE | MAP_PREFAULT); 2062f33b2c0SAlan Cox if (error) { 2072f33b2c0SAlan Cox vm_map_unlock(map); 2081616db3cSJohn Dyson return (error); 2091616db3cSJohn Dyson } 2102f33b2c0SAlan Cox } 211cfefd687SGarrett Wollman 2121616db3cSJohn Dyson if (bss_size) { 2130a91231dSAlan Cox error = vm_map_insert(map, NULL, 0, 2141616db3cSJohn Dyson data_end, data_end + bss_size, 2151616db3cSJohn Dyson VM_PROT_ALL, VM_PROT_ALL, 0); 2162f33b2c0SAlan Cox if (error) { 2172f33b2c0SAlan Cox vm_map_unlock(map); 218cfefd687SGarrett Wollman return (error); 21968940ac1SDavid Greenman } 2202f33b2c0SAlan Cox } 2212f33b2c0SAlan Cox vm_map_unlock(map); 222cfefd687SGarrett Wollman 223cfefd687SGarrett Wollman /* Fill in process VM information */ 224cfefd687SGarrett Wollman vmspace->vm_tsize = a_out->a_text >> PAGE_SHIFT; 225cfefd687SGarrett Wollman vmspace->vm_dsize = (a_out->a_data + bss_size) >> PAGE_SHIFT; 2267cd99438SBruce Evans vmspace->vm_taddr = (caddr_t) (uintptr_t) virtual_offset; 2277cd99438SBruce Evans vmspace->vm_daddr = (caddr_t) (uintptr_t) 2287cd99438SBruce Evans (virtual_offset + a_out->a_text); 229cfefd687SGarrett Wollman 230cfefd687SGarrett Wollman /* Fill in image_params */ 231c52007c2SDavid Greenman imgp->interpreted = 0; 232c52007c2SDavid Greenman imgp->entry_addr = a_out->a_entry; 233cfefd687SGarrett Wollman 234c52007c2SDavid Greenman imgp->proc->p_sysent = &aout_sysvec; 235c0e5de7dSDavid Greenman 236c0e5de7dSDavid Greenman /* Indicate that this file should not be modified */ 237c52007c2SDavid Greenman imgp->vp->v_flag |= VTEXT; 238c0e5de7dSDavid Greenman 239cfefd687SGarrett Wollman return (0); 240cfefd687SGarrett Wollman } 24192d91f76SGarrett Wollman 24292d91f76SGarrett Wollman /* 2439fe42598SBruce Evans * Dump core, into a file named as described in the comments for 2449fe42598SBruce Evans * expand_name(), unless the process was setuid/setgid. 24522d4b0fbSJohn Polstra */ 24622d4b0fbSJohn Polstra int 247fca666a1SJulian Elischer aout_coredump(p, vp, limit) 24822d4b0fbSJohn Polstra register struct proc *p; 24922d4b0fbSJohn Polstra register struct vnode *vp; 250fca666a1SJulian Elischer off_t limit; 251fca666a1SJulian Elischer { 25222d4b0fbSJohn Polstra register struct ucred *cred = p->p_cred->pc_ucred; 25322d4b0fbSJohn Polstra register struct vmspace *vm = p->p_vmspace; 254b9e91a85SBruce Evans int error; 25522d4b0fbSJohn Polstra 256b9e91a85SBruce Evans if (ctob(UPAGES + vm->vm_dsize + vm->vm_ssize) >= limit) 25722d4b0fbSJohn Polstra return (EFAULT); 25822d4b0fbSJohn Polstra bcopy(p, &p->p_addr->u_kproc.kp_proc, sizeof(struct proc)); 25922d4b0fbSJohn Polstra fill_eproc(p, &p->p_addr->u_kproc.kp_eproc); 26022d4b0fbSJohn Polstra error = cpu_coredump(p, vp, cred); 26122d4b0fbSJohn Polstra if (error == 0) 26222d4b0fbSJohn Polstra error = vn_rdwr(UIO_WRITE, vp, vm->vm_daddr, 26322d4b0fbSJohn Polstra (int)ctob(vm->vm_dsize), (off_t)ctob(UPAGES), UIO_USERSPACE, 26422d4b0fbSJohn Polstra IO_NODELOCKED|IO_UNIT, cred, (int *) NULL, p); 26522d4b0fbSJohn Polstra if (error == 0) 26622d4b0fbSJohn Polstra error = vn_rdwr(UIO_WRITE, vp, 26722d4b0fbSJohn Polstra (caddr_t) trunc_page(USRSTACK - ctob(vm->vm_ssize)), 26822d4b0fbSJohn Polstra round_page(ctob(vm->vm_ssize)), 26922d4b0fbSJohn Polstra (off_t)ctob(UPAGES) + ctob(vm->vm_dsize), UIO_USERSPACE, 27022d4b0fbSJohn Polstra IO_NODELOCKED|IO_UNIT, cred, (int *) NULL, p); 271b9e91a85SBruce Evans return (error); 27222d4b0fbSJohn Polstra } 27322d4b0fbSJohn Polstra 27422d4b0fbSJohn Polstra /* 27592d91f76SGarrett Wollman * Tell kern_execve.c about it, with a little help from the linker. 27692d91f76SGarrett Wollman */ 277820ca326SMatthew Dillon static struct execsw aout_execsw = { exec_aout_imgact, "a.out" }; 278aa855a59SPeter Wemm EXEC_SET(aout, aout_execsw); 279