imgact_aout.c revision 120422
1885Swollman/* 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: head/sys/kern/imgact_aout.c 120422 2003-09-25 01:10:26Z peter $"); 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> 3576166Smarkm#include <sys/lock.h> 36103181Sbde#include <sys/malloc.h> 3776166Smarkm#include <sys/mutex.h> 3815494Sbde#include <sys/proc.h> 3976166Smarkm#include <sys/resourcevar.h> 4039154Sjdp#include <sys/signalvar.h> 41103181Sbde#include <sys/syscall.h> 422257Ssos#include <sys/sysent.h> 43103181Sbde#include <sys/systm.h> 4415494Sbde#include <sys/vnode.h> 4576166Smarkm#include <sys/user.h> 4676166Smarkm 47103181Sbde#include <machine/frame.h> 4839154Sjdp#include <machine/md_var.h> 49885Swollman 501549Srgrimes#include <vm/vm.h> 5112662Sdg#include <vm/pmap.h> 5212662Sdg#include <vm/vm_map.h> 5332446Sdyson#include <vm/vm_object.h> 54103181Sbde#include <vm/vm_param.h> 55885Swollman 5692723Salfredstatic int exec_aout_imgact(struct image_params *imgp); 57102808Sjakestatic int aout_fixup(register_t **stack_base, struct image_params *imgp); 5812568Sbde 5939154Sjdpstruct sysentvec aout_sysvec = { 6039154Sjdp SYS_MAXSYSCALL, 6139154Sjdp sysent, 6239154Sjdp 0, 6339154Sjdp 0, 64102808Sjake NULL, 6539154Sjdp 0, 66102808Sjake NULL, 67102808Sjake NULL, 68102808Sjake aout_fixup, 6939154Sjdp sendsig, 7039154Sjdp sigcode, 7139154Sjdp &szsigcode, 72102808Sjake NULL, 7339154Sjdp "FreeBSD a.out", 7468520Smarcel aout_coredump, 7568520Smarcel NULL, 76102808Sjake MINSIGSTKSZ, 77102808Sjake PAGE_SIZE, 78102808Sjake VM_MIN_ADDRESS, 79102808Sjake VM_MAXUSER_ADDRESS, 80102808Sjake USRSTACK, 81102808Sjake PS_STRINGS, 82102808Sjake VM_PROT_ALL, 83102808Sjake exec_copyout_strings, 84120422Speter exec_setregs, 85120422Speter NULL 8639154Sjdp}; 8739154Sjdp 8850901Sbdestatic int 89102808Sjakeaout_fixup(stack_base, imgp) 90102808Sjake register_t **stack_base; 91102808Sjake struct image_params *imgp; 92102808Sjake{ 93102808Sjake 94102808Sjake return (suword(--(*stack_base), imgp->argc)); 95102808Sjake} 96102808Sjake 97102808Sjakestatic int 9812130Sdgexec_aout_imgact(imgp) 9912130Sdg struct image_params *imgp; 100885Swollman{ 10117974Sbde const struct exec *a_out = (const struct exec *) imgp->image_header; 10224848Sdyson struct vmspace *vmspace; 10332446Sdyson struct vnode *vp; 10444469Salc vm_map_t map; 10532446Sdyson vm_object_t object; 10632446Sdyson vm_offset_t text_end, data_end; 10714703Sbde unsigned long virtual_offset; 10812767Sdyson unsigned long file_offset; 109885Swollman unsigned long bss_size; 1103098Sphk int error; 111885Swollman 11279224Sdillon GIANT_REQUIRED; 11379224Sdillon 114885Swollman /* 1156380Ssos * Linux and *BSD binaries look very much alike, 1168876Srgrimes * only the machine id is different: 1179202Srgrimes * 0x64 for Linux, 0x86 for *BSD, 0x00 for BSDI. 11814363Speter * NetBSD is in network byte order.. ugh. 1196380Ssos */ 1209202Srgrimes if (((a_out->a_magic >> 16) & 0xff) != 0x86 && 12114363Speter ((a_out->a_magic >> 16) & 0xff) != 0 && 12214363Speter ((((int)ntohl(a_out->a_magic)) >> 16) & 0xff) != 0x86) 1239202Srgrimes return -1; 1246380Ssos 1256380Ssos /* 126885Swollman * Set file/virtual offset based on a.out variant. 127885Swollman * We do two cases: host byte order and network byte order 128885Swollman * (for NetBSD compatibility) 129885Swollman */ 130885Swollman switch ((int)(a_out->a_magic & 0xffff)) { 131885Swollman case ZMAGIC: 132885Swollman virtual_offset = 0; 133885Swollman if (a_out->a_text) { 13415538Sphk file_offset = PAGE_SIZE; 135885Swollman } else { 136885Swollman /* Bill's "screwball mode" */ 137885Swollman file_offset = 0; 138885Swollman } 139885Swollman break; 140885Swollman case QMAGIC: 14115538Sphk virtual_offset = PAGE_SIZE; 142885Swollman file_offset = 0; 14345270Sjdp /* Pass PS_STRINGS for BSD/OS binaries only. */ 14445270Sjdp if (N_GETMID(*a_out) == MID_ZERO) 145103767Sjake imgp->ps_strings = aout_sysvec.sv_psstrings; 146885Swollman break; 147885Swollman default: 148885Swollman /* NetBSD compatibility */ 149885Swollman switch ((int)(ntohl(a_out->a_magic) & 0xffff)) { 150885Swollman case ZMAGIC: 151885Swollman case QMAGIC: 15215538Sphk virtual_offset = PAGE_SIZE; 153885Swollman file_offset = 0; 154885Swollman break; 155885Swollman default: 156885Swollman return (-1); 157885Swollman } 158885Swollman } 159885Swollman 16015538Sphk bss_size = roundup(a_out->a_bss, PAGE_SIZE); 161885Swollman 162885Swollman /* 163885Swollman * Check various fields in header for validity/bounds. 164885Swollman */ 165885Swollman if (/* entry point must lay with text region */ 166885Swollman a_out->a_entry < virtual_offset || 167885Swollman a_out->a_entry >= virtual_offset + a_out->a_text || 168885Swollman 169885Swollman /* text and data size must each be page rounded */ 17015538Sphk a_out->a_text & PAGE_MASK || a_out->a_data & PAGE_MASK) 171885Swollman return (-1); 172885Swollman 173885Swollman /* text + data can't exceed file size */ 17412130Sdg if (a_out->a_data + a_out->a_text > imgp->attr->va_size) 175885Swollman return (EFAULT); 176885Swollman 177885Swollman /* 178885Swollman * text/data/bss must not exceed limits 179885Swollman */ 18071497Sjhb mtx_assert(&Giant, MA_OWNED); 181885Swollman if (/* text can't exceed maximum text size */ 18284783Sps a_out->a_text > maxtsiz || 183885Swollman 184885Swollman /* data + bss can't exceed rlimit */ 185885Swollman a_out->a_data + bss_size > 18612130Sdg imgp->proc->p_rlimit[RLIMIT_DATA].rlim_cur) 187885Swollman return (ENOMEM); 188885Swollman 189885Swollman /* copy in arguments and/or environment from old process */ 19012130Sdg error = exec_extract_strings(imgp); 191885Swollman if (error) 192885Swollman return (error); 193885Swollman 194885Swollman /* 195885Swollman * Destroy old process VM and create a new one (with a new stack) 196885Swollman */ 197103767Sjake exec_new_vmspace(imgp, &aout_sysvec); 198885Swollman 199885Swollman /* 20024848Sdyson * The vm space can be changed by exec_new_vmspace 20124848Sdyson */ 20224848Sdyson vmspace = imgp->proc->p_vmspace; 20324848Sdyson 20432446Sdyson vp = imgp->vp; 20599487Sjeff object = imgp->object; 20644469Salc map = &vmspace->vm_map; 20744469Salc vm_map_lock(map); 20832446Sdyson vm_object_reference(object); 20932446Sdyson 21032446Sdyson text_end = virtual_offset + a_out->a_text; 21144626Salc error = vm_map_insert(map, object, 21232446Sdyson file_offset, 21332446Sdyson virtual_offset, text_end, 21432446Sdyson VM_PROT_READ | VM_PROT_EXECUTE, VM_PROT_ALL, 21547258Salc MAP_COPY_ON_WRITE | MAP_PREFAULT); 21644469Salc if (error) { 21744469Salc vm_map_unlock(map); 218885Swollman return (error); 21944469Salc } 22032446Sdyson data_end = text_end + a_out->a_data; 22132446Sdyson if (a_out->a_data) { 22232446Sdyson vm_object_reference(object); 22344626Salc error = vm_map_insert(map, object, 22432446Sdyson file_offset + a_out->a_text, 22532446Sdyson text_end, data_end, 22632446Sdyson VM_PROT_ALL, VM_PROT_ALL, 22747258Salc MAP_COPY_ON_WRITE | MAP_PREFAULT); 22844469Salc if (error) { 22944469Salc vm_map_unlock(map); 23032446Sdyson return (error); 23144469Salc } 23232446Sdyson } 233885Swollman 23432446Sdyson if (bss_size) { 23544626Salc error = vm_map_insert(map, NULL, 0, 23632446Sdyson data_end, data_end + bss_size, 23732446Sdyson VM_PROT_ALL, VM_PROT_ALL, 0); 23844469Salc if (error) { 23944469Salc vm_map_unlock(map); 2406579Sdg return (error); 24144469Salc } 2426579Sdg } 24344469Salc vm_map_unlock(map); 24444469Salc 245885Swollman /* Fill in process VM information */ 246885Swollman vmspace->vm_tsize = a_out->a_text >> PAGE_SHIFT; 247885Swollman vmspace->vm_dsize = (a_out->a_data + bss_size) >> PAGE_SHIFT; 24837656Sbde vmspace->vm_taddr = (caddr_t) (uintptr_t) virtual_offset; 24937656Sbde vmspace->vm_daddr = (caddr_t) (uintptr_t) 25037656Sbde (virtual_offset + a_out->a_text); 251885Swollman 252885Swollman /* Fill in image_params */ 25312130Sdg imgp->interpreted = 0; 25412130Sdg imgp->entry_addr = a_out->a_entry; 2558876Srgrimes 25612130Sdg imgp->proc->p_sysent = &aout_sysvec; 25710221Sdg 258885Swollman return (0); 259885Swollman} 260886Swollman 261886Swollman/* 26242237Sbde * Dump core, into a file named as described in the comments for 26342237Sbde * expand_name(), unless the process was setuid/setgid. 26439154Sjdp */ 26539154Sjdpint 26683366Sjulianaout_coredump(td, vp, limit) 26783366Sjulian register struct thread *td; 26850717Sjulian register struct vnode *vp; 26950717Sjulian off_t limit; 27039154Sjdp{ 27183366Sjulian struct proc *p = td->td_proc; 27291406Sjhb register struct ucred *cred = td->td_ucred; 27339154Sjdp register struct vmspace *vm = p->p_vmspace; 274103086Speter char *tempuser; 27550901Sbde int error; 27639154Sjdp 277103084Speter if (ctob((uarea_pages + kstack_pages) 27883366Sjulian + vm->vm_dsize + vm->vm_ssize) >= limit) 27939154Sjdp return (EFAULT); 280103084Speter tempuser = malloc(ctob(uarea_pages + kstack_pages), M_TEMP, 281111119Simp M_WAITOK | M_ZERO); 282103047Speter if (tempuser == NULL) 283103047Speter return (ENOMEM); 284103086Speter PROC_LOCK(p); 285103086Speter fill_kinfo_proc(p, &p->p_uarea->u_kproc); 286103086Speter PROC_UNLOCK(p); 287103047Speter bcopy(p->p_uarea, tempuser, sizeof(struct user)); 288103047Speter bcopy(td->td_frame, 289103084Speter tempuser + ctob(uarea_pages) + 290103086Speter ((caddr_t)td->td_frame - (caddr_t)td->td_kstack), 291103047Speter sizeof(struct trapframe)); 292103086Speter error = vn_rdwr(UIO_WRITE, vp, (caddr_t)tempuser, 293103084Speter ctob(uarea_pages + kstack_pages), 294103047Speter (off_t)0, UIO_SYSSPACE, IO_UNIT, cred, NOCRED, 295103047Speter (int *)NULL, td); 296103047Speter free(tempuser, M_TEMP); 29739154Sjdp if (error == 0) 29883366Sjulian error = vn_rdwr(UIO_WRITE, vp, vm->vm_daddr, 29983366Sjulian (int)ctob(vm->vm_dsize), 300103084Speter (off_t)ctob(uarea_pages + kstack_pages), UIO_USERSPACE, 301101941Srwatson IO_UNIT | IO_DIRECT, cred, NOCRED, (int *) NULL, td); 30239154Sjdp if (error == 0) 30383222Sdillon error = vn_rdwr_inchunks(UIO_WRITE, vp, 304103767Sjake (caddr_t)trunc_page(p->p_sysent->sv_usrstack - 305103767Sjake ctob(vm->vm_ssize)), round_page(ctob(vm->vm_ssize)), 306103084Speter (off_t)ctob(uarea_pages + kstack_pages) + 30783366Sjulian ctob(vm->vm_dsize), UIO_USERSPACE, 308101941Srwatson IO_UNIT | IO_DIRECT, cred, NOCRED, (int *) NULL, td); 30950901Sbde return (error); 31039154Sjdp} 31139154Sjdp 31239154Sjdp/* 313886Swollman * Tell kern_execve.c about it, with a little help from the linker. 314886Swollman */ 31543402Sdillonstatic struct execsw aout_execsw = { exec_aout_imgact, "a.out" }; 31640435SpeterEXEC_SET(aout, aout_execsw); 317