imgact_aout.c revision 175202
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: head/sys/kern/imgact_aout.c 175202 2008-01-10 01:10:58Z attilio $"); 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 46103181Sbde#include <machine/frame.h> 4739154Sjdp#include <machine/md_var.h> 48885Swollman 491549Srgrimes#include <vm/vm.h> 5012662Sdg#include <vm/pmap.h> 5112662Sdg#include <vm/vm_map.h> 5232446Sdyson#include <vm/vm_object.h> 53103181Sbde#include <vm/vm_param.h> 54885Swollman 5592723Salfredstatic int exec_aout_imgact(struct image_params *imgp); 56102808Sjakestatic int aout_fixup(register_t **stack_base, struct image_params *imgp); 5712568Sbde 5839154Sjdpstruct sysentvec aout_sysvec = { 5939154Sjdp SYS_MAXSYSCALL, 6039154Sjdp sysent, 6139154Sjdp 0, 6239154Sjdp 0, 63102808Sjake NULL, 6439154Sjdp 0, 65102808Sjake NULL, 66102808Sjake NULL, 67102808Sjake aout_fixup, 6839154Sjdp sendsig, 6939154Sjdp sigcode, 7039154Sjdp &szsigcode, 71102808Sjake NULL, 7239154Sjdp "FreeBSD a.out", 7368520Smarcel NULL, 74138128Sdas NULL, 75102808Sjake MINSIGSTKSZ, 76102808Sjake PAGE_SIZE, 77102808Sjake VM_MIN_ADDRESS, 78102808Sjake VM_MAXUSER_ADDRESS, 79102808Sjake USRSTACK, 80102808Sjake PS_STRINGS, 81102808Sjake VM_PROT_ALL, 82102808Sjake exec_copyout_strings, 83120422Speter exec_setregs, 84120422Speter NULL 8539154Sjdp}; 8639154Sjdp 8750901Sbdestatic int 88102808Sjakeaout_fixup(stack_base, imgp) 89102808Sjake register_t **stack_base; 90102808Sjake struct image_params *imgp; 91102808Sjake{ 92102808Sjake 93140992Ssobomax return (suword(--(*stack_base), imgp->args->argc)); 94102808Sjake} 95102808Sjake 96102808Sjakestatic int 9712130Sdgexec_aout_imgact(imgp) 9812130Sdg struct image_params *imgp; 99885Swollman{ 10017974Sbde const struct exec *a_out = (const struct exec *) imgp->image_header; 10124848Sdyson struct vmspace *vmspace; 10244469Salc vm_map_t map; 10332446Sdyson vm_object_t object; 10432446Sdyson vm_offset_t text_end, data_end; 10514703Sbde unsigned long virtual_offset; 10612767Sdyson unsigned long file_offset; 107885Swollman unsigned long bss_size; 1083098Sphk int error; 109885Swollman 110885Swollman /* 1116380Ssos * Linux and *BSD binaries look very much alike, 1128876Srgrimes * only the machine id is different: 1139202Srgrimes * 0x64 for Linux, 0x86 for *BSD, 0x00 for BSDI. 11414363Speter * NetBSD is in network byte order.. ugh. 1156380Ssos */ 1169202Srgrimes if (((a_out->a_magic >> 16) & 0xff) != 0x86 && 11714363Speter ((a_out->a_magic >> 16) & 0xff) != 0 && 11814363Speter ((((int)ntohl(a_out->a_magic)) >> 16) & 0xff) != 0x86) 1199202Srgrimes return -1; 1206380Ssos 1216380Ssos /* 122885Swollman * Set file/virtual offset based on a.out variant. 123885Swollman * We do two cases: host byte order and network byte order 124885Swollman * (for NetBSD compatibility) 125885Swollman */ 126885Swollman switch ((int)(a_out->a_magic & 0xffff)) { 127885Swollman case ZMAGIC: 128885Swollman virtual_offset = 0; 129885Swollman if (a_out->a_text) { 13015538Sphk file_offset = PAGE_SIZE; 131885Swollman } else { 132885Swollman /* Bill's "screwball mode" */ 133885Swollman file_offset = 0; 134885Swollman } 135885Swollman break; 136885Swollman case QMAGIC: 13715538Sphk virtual_offset = PAGE_SIZE; 138885Swollman file_offset = 0; 13945270Sjdp /* Pass PS_STRINGS for BSD/OS binaries only. */ 14045270Sjdp if (N_GETMID(*a_out) == MID_ZERO) 141103767Sjake imgp->ps_strings = aout_sysvec.sv_psstrings; 142885Swollman break; 143885Swollman default: 144885Swollman /* NetBSD compatibility */ 145885Swollman switch ((int)(ntohl(a_out->a_magic) & 0xffff)) { 146885Swollman case ZMAGIC: 147885Swollman case QMAGIC: 14815538Sphk virtual_offset = PAGE_SIZE; 149885Swollman file_offset = 0; 150885Swollman break; 151885Swollman default: 152885Swollman return (-1); 153885Swollman } 154885Swollman } 155885Swollman 15615538Sphk bss_size = roundup(a_out->a_bss, PAGE_SIZE); 157885Swollman 158885Swollman /* 159885Swollman * Check various fields in header for validity/bounds. 160885Swollman */ 161885Swollman if (/* entry point must lay with text region */ 162885Swollman a_out->a_entry < virtual_offset || 163885Swollman a_out->a_entry >= virtual_offset + a_out->a_text || 164885Swollman 165885Swollman /* text and data size must each be page rounded */ 16615538Sphk a_out->a_text & PAGE_MASK || a_out->a_data & PAGE_MASK) 167885Swollman return (-1); 168885Swollman 169885Swollman /* text + data can't exceed file size */ 17012130Sdg if (a_out->a_data + a_out->a_text > imgp->attr->va_size) 171885Swollman return (EFAULT); 172885Swollman 173885Swollman /* 174885Swollman * text/data/bss must not exceed limits 175885Swollman */ 176125454Sjhb PROC_LOCK(imgp->proc); 177885Swollman if (/* text can't exceed maximum text size */ 17884783Sps a_out->a_text > maxtsiz || 179885Swollman 180885Swollman /* data + bss can't exceed rlimit */ 181125454Sjhb a_out->a_data + bss_size > lim_cur(imgp->proc, RLIMIT_DATA)) { 182125454Sjhb PROC_UNLOCK(imgp->proc); 183885Swollman return (ENOMEM); 184125454Sjhb } 185125454Sjhb PROC_UNLOCK(imgp->proc); 186885Swollman 187885Swollman /* 188153698Salc * Avoid a possible deadlock if the current address space is destroyed 189153698Salc * and that address space maps the locked vnode. In the common case, 190153698Salc * the locked vnode's v_usecount is decremented but remains greater 191153698Salc * than zero. Consequently, the vnode lock is not needed by vrele(). 192153698Salc * However, in cases where the vnode lock is external, such as nullfs, 193153698Salc * v_usecount may become zero. 194153698Salc */ 195175202Sattilio VOP_UNLOCK(imgp->vp, 0, curthread); 196153698Salc 197153698Salc /* 198885Swollman * Destroy old process VM and create a new one (with a new stack) 199885Swollman */ 200173361Skib error = exec_new_vmspace(imgp, &aout_sysvec); 201885Swollman 202175202Sattilio vn_lock(imgp->vp, LK_EXCLUSIVE | LK_RETRY); 203173361Skib if (error) 204173361Skib return (error); 205153698Salc 206885Swollman /* 20724848Sdyson * The vm space can be changed by exec_new_vmspace 20824848Sdyson */ 20924848Sdyson vmspace = imgp->proc->p_vmspace; 21024848Sdyson 21199487Sjeff object = imgp->object; 21244469Salc map = &vmspace->vm_map; 21344469Salc vm_map_lock(map); 21432446Sdyson vm_object_reference(object); 21532446Sdyson 21632446Sdyson text_end = virtual_offset + a_out->a_text; 21744626Salc error = vm_map_insert(map, object, 21832446Sdyson file_offset, 21932446Sdyson virtual_offset, text_end, 22032446Sdyson VM_PROT_READ | VM_PROT_EXECUTE, VM_PROT_ALL, 22147258Salc MAP_COPY_ON_WRITE | MAP_PREFAULT); 22244469Salc if (error) { 22344469Salc vm_map_unlock(map); 224156766Salc vm_object_deallocate(object); 225885Swollman return (error); 22644469Salc } 22732446Sdyson data_end = text_end + a_out->a_data; 22832446Sdyson if (a_out->a_data) { 22932446Sdyson vm_object_reference(object); 23044626Salc error = vm_map_insert(map, object, 23132446Sdyson file_offset + a_out->a_text, 23232446Sdyson text_end, data_end, 23332446Sdyson VM_PROT_ALL, VM_PROT_ALL, 23447258Salc MAP_COPY_ON_WRITE | MAP_PREFAULT); 23544469Salc if (error) { 23644469Salc vm_map_unlock(map); 237156766Salc vm_object_deallocate(object); 23832446Sdyson return (error); 23944469Salc } 24032446Sdyson } 241885Swollman 24232446Sdyson if (bss_size) { 24344626Salc error = vm_map_insert(map, NULL, 0, 24432446Sdyson data_end, data_end + bss_size, 24532446Sdyson VM_PROT_ALL, VM_PROT_ALL, 0); 24644469Salc if (error) { 24744469Salc vm_map_unlock(map); 2486579Sdg return (error); 24944469Salc } 2506579Sdg } 25144469Salc vm_map_unlock(map); 25244469Salc 253885Swollman /* Fill in process VM information */ 254885Swollman vmspace->vm_tsize = a_out->a_text >> PAGE_SHIFT; 255885Swollman vmspace->vm_dsize = (a_out->a_data + bss_size) >> PAGE_SHIFT; 25637656Sbde vmspace->vm_taddr = (caddr_t) (uintptr_t) virtual_offset; 25737656Sbde vmspace->vm_daddr = (caddr_t) (uintptr_t) 25837656Sbde (virtual_offset + a_out->a_text); 259885Swollman 260885Swollman /* Fill in image_params */ 26112130Sdg imgp->interpreted = 0; 26212130Sdg imgp->entry_addr = a_out->a_entry; 2638876Srgrimes 26412130Sdg imgp->proc->p_sysent = &aout_sysvec; 26510221Sdg 266885Swollman return (0); 267885Swollman} 268886Swollman 269886Swollman/* 270886Swollman * Tell kern_execve.c about it, with a little help from the linker. 271886Swollman */ 27243402Sdillonstatic struct execsw aout_execsw = { exec_aout_imgact, "a.out" }; 27340435SpeterEXEC_SET(aout, aout_execsw); 274