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 * 262f33b2c0SAlan Cox * $Id: imgact_aout.c,v 1.46 1999/02/19 14:25:34 luoqi Exp $ 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 78a3bdf7a3SBruce 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; 122cfefd687SGarrett Wollman break; 123cfefd687SGarrett Wollman default: 124cfefd687SGarrett Wollman /* NetBSD compatibility */ 125cfefd687SGarrett Wollman switch ((int)(ntohl(a_out->a_magic) & 0xffff)) { 126cfefd687SGarrett Wollman case ZMAGIC: 127cfefd687SGarrett Wollman case QMAGIC: 128f8845af0SPoul-Henning Kamp virtual_offset = PAGE_SIZE; 129cfefd687SGarrett Wollman file_offset = 0; 130cfefd687SGarrett Wollman break; 131cfefd687SGarrett Wollman default: 132cfefd687SGarrett Wollman return (-1); 133cfefd687SGarrett Wollman } 134cfefd687SGarrett Wollman } 135cfefd687SGarrett Wollman 136f8845af0SPoul-Henning Kamp bss_size = roundup(a_out->a_bss, PAGE_SIZE); 137cfefd687SGarrett Wollman 138cfefd687SGarrett Wollman /* 139cfefd687SGarrett Wollman * Check various fields in header for validity/bounds. 140cfefd687SGarrett Wollman */ 141cfefd687SGarrett Wollman if (/* entry point must lay with text region */ 142cfefd687SGarrett Wollman a_out->a_entry < virtual_offset || 143cfefd687SGarrett Wollman a_out->a_entry >= virtual_offset + a_out->a_text || 144cfefd687SGarrett Wollman 145cfefd687SGarrett Wollman /* text and data size must each be page rounded */ 146f8845af0SPoul-Henning Kamp a_out->a_text & PAGE_MASK || a_out->a_data & PAGE_MASK) 147cfefd687SGarrett Wollman return (-1); 148cfefd687SGarrett Wollman 149cfefd687SGarrett Wollman /* text + data can't exceed file size */ 150c52007c2SDavid Greenman if (a_out->a_data + a_out->a_text > imgp->attr->va_size) 151cfefd687SGarrett Wollman return (EFAULT); 152cfefd687SGarrett Wollman 153cfefd687SGarrett Wollman /* 154cfefd687SGarrett Wollman * text/data/bss must not exceed limits 155cfefd687SGarrett Wollman */ 156cfefd687SGarrett Wollman if (/* text can't exceed maximum text size */ 157cfefd687SGarrett Wollman a_out->a_text > MAXTSIZ || 158cfefd687SGarrett Wollman 159cfefd687SGarrett Wollman /* data + bss can't exceed rlimit */ 160cfefd687SGarrett Wollman a_out->a_data + bss_size > 161c52007c2SDavid Greenman imgp->proc->p_rlimit[RLIMIT_DATA].rlim_cur) 162cfefd687SGarrett Wollman return (ENOMEM); 163cfefd687SGarrett Wollman 164cfefd687SGarrett Wollman /* copy in arguments and/or environment from old process */ 165c52007c2SDavid Greenman error = exec_extract_strings(imgp); 166cfefd687SGarrett Wollman if (error) 167cfefd687SGarrett Wollman return (error); 168cfefd687SGarrett Wollman 169cfefd687SGarrett Wollman /* 170cfefd687SGarrett Wollman * Destroy old process VM and create a new one (with a new stack) 171cfefd687SGarrett Wollman */ 172c52007c2SDavid Greenman exec_new_vmspace(imgp); 173cfefd687SGarrett Wollman 174cfefd687SGarrett Wollman /* 1755856e12eSJohn Dyson * The vm space can be changed by exec_new_vmspace 1765856e12eSJohn Dyson */ 1775856e12eSJohn Dyson vmspace = imgp->proc->p_vmspace; 1785856e12eSJohn Dyson 1791616db3cSJohn Dyson vp = imgp->vp; 1802f33b2c0SAlan Cox map = &vmspace->vm_map; 1812f33b2c0SAlan Cox vm_map_lock(map); 1821616db3cSJohn Dyson object = vp->v_object; 1831616db3cSJohn Dyson vm_object_reference(object); 1841616db3cSJohn Dyson 1851616db3cSJohn Dyson text_end = virtual_offset + a_out->a_text; 1861616db3cSJohn Dyson error = vm_map_insert(&vmspace->vm_map, object, 1871616db3cSJohn Dyson file_offset, 1881616db3cSJohn Dyson virtual_offset, text_end, 1891616db3cSJohn Dyson VM_PROT_READ | VM_PROT_EXECUTE, VM_PROT_ALL, 1901616db3cSJohn Dyson MAP_COPY_NEEDED | MAP_COPY_ON_WRITE); 1912f33b2c0SAlan Cox if (error) { 1922f33b2c0SAlan Cox vm_map_unlock(map); 193cfefd687SGarrett Wollman return (error); 1942f33b2c0SAlan Cox } 1951616db3cSJohn Dyson data_end = text_end + a_out->a_data; 1961616db3cSJohn Dyson if (a_out->a_data) { 1971616db3cSJohn Dyson vm_object_reference(object); 1981616db3cSJohn Dyson error = vm_map_insert(&vmspace->vm_map, object, 1991616db3cSJohn Dyson file_offset + a_out->a_text, 2001616db3cSJohn Dyson text_end, data_end, 2011616db3cSJohn Dyson VM_PROT_ALL, VM_PROT_ALL, 2021616db3cSJohn Dyson MAP_COPY_NEEDED | MAP_COPY_ON_WRITE); 2032f33b2c0SAlan Cox if (error) { 2042f33b2c0SAlan Cox vm_map_unlock(map); 2051616db3cSJohn Dyson return (error); 2061616db3cSJohn Dyson } 2072f33b2c0SAlan Cox } 208cfefd687SGarrett Wollman 209b1028ad1SLuoqi Chen pmap_object_init_pt(vmspace_pmap(vmspace), virtual_offset, 2101616db3cSJohn Dyson object, (vm_pindex_t) OFF_TO_IDX(file_offset), 2111616db3cSJohn Dyson a_out->a_text + a_out->a_data, 0); 2121616db3cSJohn Dyson 2131616db3cSJohn Dyson if (bss_size) { 2141616db3cSJohn Dyson error = vm_map_insert(&vmspace->vm_map, NULL, 0, 2151616db3cSJohn Dyson data_end, data_end + bss_size, 2161616db3cSJohn Dyson VM_PROT_ALL, VM_PROT_ALL, 0); 2172f33b2c0SAlan Cox if (error) { 2182f33b2c0SAlan Cox vm_map_unlock(map); 219cfefd687SGarrett Wollman return (error); 22068940ac1SDavid Greenman } 2212f33b2c0SAlan Cox } 2222f33b2c0SAlan Cox vm_map_unlock(map); 223cfefd687SGarrett Wollman 224cfefd687SGarrett Wollman /* Fill in process VM information */ 225cfefd687SGarrett Wollman vmspace->vm_tsize = a_out->a_text >> PAGE_SHIFT; 226cfefd687SGarrett Wollman vmspace->vm_dsize = (a_out->a_data + bss_size) >> PAGE_SHIFT; 2277cd99438SBruce Evans vmspace->vm_taddr = (caddr_t) (uintptr_t) virtual_offset; 2287cd99438SBruce Evans vmspace->vm_daddr = (caddr_t) (uintptr_t) 2297cd99438SBruce Evans (virtual_offset + a_out->a_text); 230cfefd687SGarrett Wollman 231cfefd687SGarrett Wollman /* Fill in image_params */ 232c52007c2SDavid Greenman imgp->interpreted = 0; 233c52007c2SDavid Greenman imgp->entry_addr = a_out->a_entry; 234cfefd687SGarrett Wollman 235c52007c2SDavid Greenman imgp->proc->p_sysent = &aout_sysvec; 236c0e5de7dSDavid Greenman 237c0e5de7dSDavid Greenman /* Indicate that this file should not be modified */ 238c52007c2SDavid Greenman imgp->vp->v_flag |= VTEXT; 239c0e5de7dSDavid Greenman 240cfefd687SGarrett Wollman return (0); 241cfefd687SGarrett Wollman } 24292d91f76SGarrett Wollman 24392d91f76SGarrett Wollman /* 2449fe42598SBruce Evans * Dump core, into a file named as described in the comments for 2459fe42598SBruce Evans * expand_name(), unless the process was setuid/setgid. 24622d4b0fbSJohn Polstra */ 24722d4b0fbSJohn Polstra int 24822d4b0fbSJohn Polstra aout_coredump(p) 24922d4b0fbSJohn Polstra register struct proc *p; 25022d4b0fbSJohn Polstra { 25122d4b0fbSJohn Polstra register struct vnode *vp; 25222d4b0fbSJohn Polstra register struct ucred *cred = p->p_cred->pc_ucred; 25322d4b0fbSJohn Polstra register struct vmspace *vm = p->p_vmspace; 25422d4b0fbSJohn Polstra struct nameidata nd; 25522d4b0fbSJohn Polstra struct vattr vattr; 25622d4b0fbSJohn Polstra int error, error1; 25722d4b0fbSJohn Polstra char *name; /* name of corefile */ 25822d4b0fbSJohn Polstra 25922d4b0fbSJohn Polstra STOPEVENT(p, S_CORE, 0); 26022d4b0fbSJohn Polstra if (sugid_coredump == 0 && p->p_flag & P_SUGID) 26122d4b0fbSJohn Polstra return (EFAULT); 26222d4b0fbSJohn Polstra if (ctob(UPAGES + vm->vm_dsize + vm->vm_ssize) >= 26322d4b0fbSJohn Polstra p->p_rlimit[RLIMIT_CORE].rlim_cur) 26422d4b0fbSJohn Polstra return (EFAULT); 26522d4b0fbSJohn Polstra name = expand_name(p->p_comm, p->p_ucred->cr_uid, p->p_pid); 26622d4b0fbSJohn Polstra if (name == NULL) 26722d4b0fbSJohn Polstra return (EFAULT); /* XXX -- not the best error */ 26822d4b0fbSJohn Polstra NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, name, p); 26922d4b0fbSJohn Polstra error = vn_open(&nd, O_CREAT | FWRITE, S_IRUSR | S_IWUSR); 27022d4b0fbSJohn Polstra free(name, M_TEMP); 27122d4b0fbSJohn Polstra if (error) 27222d4b0fbSJohn Polstra return (error); 27322d4b0fbSJohn Polstra vp = nd.ni_vp; 27422d4b0fbSJohn Polstra 27522d4b0fbSJohn Polstra /* Don't dump to non-regular files or files with links. */ 27622d4b0fbSJohn Polstra if (vp->v_type != VREG || 27722d4b0fbSJohn Polstra VOP_GETATTR(vp, &vattr, cred, p) || vattr.va_nlink != 1) { 27822d4b0fbSJohn Polstra error = EFAULT; 27922d4b0fbSJohn Polstra goto out; 28022d4b0fbSJohn Polstra } 28122d4b0fbSJohn Polstra VATTR_NULL(&vattr); 28222d4b0fbSJohn Polstra vattr.va_size = 0; 28322d4b0fbSJohn Polstra VOP_LEASE(vp, p, cred, LEASE_WRITE); 28422d4b0fbSJohn Polstra VOP_SETATTR(vp, &vattr, cred, p); 28522d4b0fbSJohn Polstra p->p_acflag |= ACORE; 28622d4b0fbSJohn Polstra bcopy(p, &p->p_addr->u_kproc.kp_proc, sizeof(struct proc)); 28722d4b0fbSJohn Polstra fill_eproc(p, &p->p_addr->u_kproc.kp_eproc); 28822d4b0fbSJohn Polstra error = cpu_coredump(p, vp, cred); 28922d4b0fbSJohn Polstra if (error == 0) 29022d4b0fbSJohn Polstra error = vn_rdwr(UIO_WRITE, vp, vm->vm_daddr, 29122d4b0fbSJohn Polstra (int)ctob(vm->vm_dsize), (off_t)ctob(UPAGES), UIO_USERSPACE, 29222d4b0fbSJohn Polstra IO_NODELOCKED|IO_UNIT, cred, (int *) NULL, p); 29322d4b0fbSJohn Polstra if (error == 0) 29422d4b0fbSJohn Polstra error = vn_rdwr(UIO_WRITE, vp, 29522d4b0fbSJohn Polstra (caddr_t) trunc_page(USRSTACK - ctob(vm->vm_ssize)), 29622d4b0fbSJohn Polstra round_page(ctob(vm->vm_ssize)), 29722d4b0fbSJohn Polstra (off_t)ctob(UPAGES) + ctob(vm->vm_dsize), UIO_USERSPACE, 29822d4b0fbSJohn Polstra IO_NODELOCKED|IO_UNIT, cred, (int *) NULL, p); 29922d4b0fbSJohn Polstra out: 30022d4b0fbSJohn Polstra VOP_UNLOCK(vp, 0, p); 30122d4b0fbSJohn Polstra error1 = vn_close(vp, FWRITE, cred, p); 30222d4b0fbSJohn Polstra if (error == 0) 30322d4b0fbSJohn Polstra error = error1; 30422d4b0fbSJohn Polstra return (error); 30522d4b0fbSJohn Polstra } 30622d4b0fbSJohn Polstra 30722d4b0fbSJohn Polstra /* 30892d91f76SGarrett Wollman * Tell kern_execve.c about it, with a little help from the linker. 30992d91f76SGarrett Wollman * Since `const' objects end up in the text segment, TEXT_SET is the 31092d91f76SGarrett Wollman * correct directive to use. 31192d91f76SGarrett Wollman */ 312820ca326SMatthew Dillon static struct execsw aout_execsw = { exec_aout_imgact, "a.out" }; 313aa855a59SPeter Wemm EXEC_SET(aout, aout_execsw); 314