imgact_aout.c revision 50717
150974Swpaul/* 250974Swpaul * Copyright (c) 1993, David Greenman 350974Swpaul * All rights reserved. 450974Swpaul * 550974Swpaul * Redistribution and use in source and binary forms, with or without 650974Swpaul * modification, are permitted provided that the following conditions 750974Swpaul * are met: 850974Swpaul * 1. Redistributions of source code must retain the above copyright 950974Swpaul * notice, this list of conditions and the following disclaimer. 1050974Swpaul * 2. Redistributions in binary form must reproduce the above copyright 1150974Swpaul * notice, this list of conditions and the following disclaimer in the 1250974Swpaul * documentation and/or other materials provided with the distribution. 1350974Swpaul * 1450974Swpaul * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1550974Swpaul * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1650974Swpaul * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1750974Swpaul * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1850974Swpaul * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1950974Swpaul * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2050974Swpaul * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2150974Swpaul * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2250974Swpaul * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2350974Swpaul * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2450974Swpaul * SUCH DAMAGE. 2550974Swpaul * 2650974Swpaul * $FreeBSD: head/sys/kern/imgact_aout.c 50717 1999-09-01 00:29:56Z julian $ 2750974Swpaul */ 2850974Swpaul 2950974Swpaul#include <sys/param.h> 3050974Swpaul#include <sys/acct.h> 3150974Swpaul#include <sys/resourcevar.h> 3250974Swpaul#include <sys/exec.h> 3350974Swpaul#include <sys/fcntl.h> 3450974Swpaul#include <sys/imgact.h> 3550974Swpaul#include <sys/imgact_aout.h> 3650974Swpaul#include <sys/kernel.h> 3750974Swpaul#include <sys/malloc.h> 3850974Swpaul#include <sys/namei.h> 3964963Swpaul#include <sys/pioctl.h> 4064963Swpaul#include <sys/proc.h> 4164963Swpaul#include <sys/signalvar.h> 4250974Swpaul#include <sys/stat.h> 4350974Swpaul#include <sys/sysent.h> 4450974Swpaul#include <sys/syscall.h> 4550974Swpaul#include <sys/vnode.h> 4650974Swpaul#include <sys/systm.h> 4750974Swpaul#include <machine/md_var.h> 4850974Swpaul 4950974Swpaul#include <vm/vm.h> 5050974Swpaul#include <vm/vm_param.h> 5150974Swpaul#include <vm/vm_prot.h> 5250974Swpaul#include <sys/lock.h> 5350974Swpaul#include <vm/pmap.h> 5450974Swpaul#include <vm/vm_map.h> 5550974Swpaul#include <vm/vm_object.h> 5650974Swpaul#include <sys/user.h> 5750974Swpaul 5850974Swpaulstatic int exec_aout_imgact __P((struct image_params *imgp)); 5950974Swpaul 6050974Swpaulstruct sysentvec aout_sysvec = { 6150974Swpaul SYS_MAXSYSCALL, 6250974Swpaul sysent, 6350974Swpaul 0, 6450974Swpaul 0, 6550974Swpaul 0, 6650974Swpaul 0, 6787059Sluigi 0, 6850974Swpaul 0, 6950974Swpaul 0, 7050974Swpaul sendsig, 7150974Swpaul sigcode, 7250974Swpaul &szsigcode, 7350974Swpaul 0, 7487390Sjhay "FreeBSD a.out", 7587390Sjhay aout_coredump 7650974Swpaul}; 7750974Swpaul 7850974Swpaulint 7950974Swpaulexec_aout_imgact(imgp) 8050974Swpaul struct image_params *imgp; 8150974Swpaul{ 8250974Swpaul const struct exec *a_out = (const struct exec *) imgp->image_header; 8350974Swpaul struct vmspace *vmspace; 8450974Swpaul struct vnode *vp; 8550974Swpaul vm_map_t map; 8650974Swpaul vm_object_t object; 8750974Swpaul vm_offset_t text_end, data_end; 8850974Swpaul unsigned long virtual_offset; 8950974Swpaul unsigned long file_offset; 9050974Swpaul unsigned long bss_size; 9150974Swpaul int error; 9250974Swpaul 9350974Swpaul /* 9450974Swpaul * Linux and *BSD binaries look very much alike, 9550974Swpaul * only the machine id is different: 9659758Speter * 0x64 for Linux, 0x86 for *BSD, 0x00 for BSDI. 9759758Speter * NetBSD is in network byte order.. ugh. 9851089Speter */ 9950974Swpaul if (((a_out->a_magic >> 16) & 0xff) != 0x86 && 10050974Swpaul ((a_out->a_magic >> 16) & 0xff) != 0 && 10150974Swpaul ((((int)ntohl(a_out->a_magic)) >> 16) & 0xff) != 0x86) 10250974Swpaul return -1; 10350974Swpaul 10450974Swpaul /* 10550974Swpaul * Set file/virtual offset based on a.out variant. 10650974Swpaul * We do two cases: host byte order and network byte order 10750974Swpaul * (for NetBSD compatibility) 10850974Swpaul */ 10950974Swpaul switch ((int)(a_out->a_magic & 0xffff)) { 11050974Swpaul case ZMAGIC: 11150974Swpaul virtual_offset = 0; 11262672Swpaul if (a_out->a_text) { 11350974Swpaul file_offset = PAGE_SIZE; 11450974Swpaul } else { 11550974Swpaul /* Bill's "screwball mode" */ 11692739Salfred file_offset = 0; 11792739Salfred } 11892739Salfred break; 11950974Swpaul case QMAGIC: 12092739Salfred virtual_offset = PAGE_SIZE; 12192739Salfred file_offset = 0; 12292739Salfred /* Pass PS_STRINGS for BSD/OS binaries only. */ 12392739Salfred if (N_GETMID(*a_out) == MID_ZERO) 12492739Salfred imgp->ps_strings = PS_STRINGS; 12592739Salfred break; 12692739Salfred default: 12792739Salfred /* NetBSD compatibility */ 12892739Salfred switch ((int)(ntohl(a_out->a_magic) & 0xffff)) { 12992739Salfred case ZMAGIC: 13092739Salfred case QMAGIC: 13192739Salfred virtual_offset = PAGE_SIZE; 13292739Salfred file_offset = 0; 13392739Salfred break; 13492739Salfred default: 13592739Salfred return (-1); 13692739Salfred } 13750974Swpaul } 13892739Salfred 13992739Salfred bss_size = roundup(a_out->a_bss, PAGE_SIZE); 14092739Salfred 14192739Salfred /* 14292739Salfred * Check various fields in header for validity/bounds. 14392739Salfred */ 14472197Swpaul if (/* entry point must lay with text region */ 14592739Salfred a_out->a_entry < virtual_offset || 14692739Salfred a_out->a_entry >= virtual_offset + a_out->a_text || 14792739Salfred 14892739Salfred /* text and data size must each be page rounded */ 14972197Swpaul a_out->a_text & PAGE_MASK || a_out->a_data & PAGE_MASK) 15072197Swpaul return (-1); 15192739Salfred 15292739Salfred /* text + data can't exceed file size */ 15392739Salfred if (a_out->a_data + a_out->a_text > imgp->attr->va_size) 15450974Swpaul return (EFAULT); 15592739Salfred 15692739Salfred /* 15792739Salfred * text/data/bss must not exceed limits 15892739Salfred */ 15992739Salfred if (/* text can't exceed maximum text size */ 16092739Salfred a_out->a_text > MAXTSIZ || 16150974Swpaul 16292739Salfred /* data + bss can't exceed rlimit */ 16392739Salfred a_out->a_data + bss_size > 16492739Salfred imgp->proc->p_rlimit[RLIMIT_DATA].rlim_cur) 16550974Swpaul return (ENOMEM); 16650974Swpaul 16750974Swpaul /* copy in arguments and/or environment from old process */ 16850974Swpaul error = exec_extract_strings(imgp); 16951030Swpaul if (error) 17051030Swpaul return (error); 17150974Swpaul 17250974Swpaul /* 17350974Swpaul * Destroy old process VM and create a new one (with a new stack) 17450974Swpaul */ 17550974Swpaul exec_new_vmspace(imgp); 17650974Swpaul 17750974Swpaul /* 17850974Swpaul * The vm space can be changed by exec_new_vmspace 17950974Swpaul */ 18050974Swpaul vmspace = imgp->proc->p_vmspace; 18150974Swpaul 18250974Swpaul vp = imgp->vp; 18350974Swpaul map = &vmspace->vm_map; 18450974Swpaul vm_map_lock(map); 18550974Swpaul object = vp->v_object; 18650974Swpaul vm_object_reference(object); 18750974Swpaul 18850974Swpaul text_end = virtual_offset + a_out->a_text; 18950974Swpaul error = vm_map_insert(map, object, 19050974Swpaul file_offset, 19150974Swpaul virtual_offset, text_end, 19250974Swpaul VM_PROT_READ | VM_PROT_EXECUTE, VM_PROT_ALL, 19351455Swpaul MAP_COPY_ON_WRITE | MAP_PREFAULT); 19450974Swpaul if (error) { 19550974Swpaul vm_map_unlock(map); 19650974Swpaul return (error); 19750974Swpaul } 19850974Swpaul data_end = text_end + a_out->a_data; 19950974Swpaul if (a_out->a_data) { 20051533Swpaul vm_object_reference(object); 20151473Swpaul error = vm_map_insert(map, object, 20250974Swpaul file_offset + a_out->a_text, 20350974Swpaul text_end, data_end, 20450974Swpaul VM_PROT_ALL, VM_PROT_ALL, 20550974Swpaul MAP_COPY_ON_WRITE | MAP_PREFAULT); 20650974Swpaul if (error) { 20750974Swpaul vm_map_unlock(map); 20850974Swpaul return (error); 20950974Swpaul } 21050974Swpaul } 21150974Swpaul 21250974Swpaul if (bss_size) { 21350974Swpaul error = vm_map_insert(map, NULL, 0, 21450974Swpaul data_end, data_end + bss_size, 21550974Swpaul VM_PROT_ALL, VM_PROT_ALL, 0); 21650974Swpaul if (error) { 21781713Swpaul vm_map_unlock(map); 21881713Swpaul return (error); 21981713Swpaul } 22081713Swpaul } 22181713Swpaul vm_map_unlock(map); 22281713Swpaul 22381713Swpaul /* Fill in process VM information */ 22481713Swpaul vmspace->vm_tsize = a_out->a_text >> PAGE_SHIFT; 22581713Swpaul vmspace->vm_dsize = (a_out->a_data + bss_size) >> PAGE_SHIFT; 22681713Swpaul vmspace->vm_taddr = (caddr_t) (uintptr_t) virtual_offset; 22781713Swpaul vmspace->vm_daddr = (caddr_t) (uintptr_t) 22881713Swpaul (virtual_offset + a_out->a_text); 22981713Swpaul 23081713Swpaul /* Fill in image_params */ 23181713Swpaul imgp->interpreted = 0; 23281713Swpaul imgp->entry_addr = a_out->a_entry; 23381713Swpaul 23481713Swpaul imgp->proc->p_sysent = &aout_sysvec; 23581713Swpaul 23681713Swpaul /* Indicate that this file should not be modified */ 23781713Swpaul imgp->vp->v_flag |= VTEXT; 23881713Swpaul 23981713Swpaul return (0); 24081713Swpaul} 24181713Swpaul 24281713Swpaul/* 24381713Swpaul * Dump core, into a file named as described in the comments for 24481713Swpaul * expand_name(), unless the process was setuid/setgid. 24581713Swpaul */ 24681713Swpaulint 24781713Swpaulaout_coredump(p, vp, limit) 24881713Swpaul register struct proc *p; 24981713Swpaul register struct vnode *vp; 25081713Swpaul off_t limit; 25181713Swpaul{ 25281713Swpaul register struct ucred *cred = p->p_cred->pc_ucred; 25381713Swpaul register struct vmspace *vm = p->p_vmspace; 25481713Swpaul int error = 0; 25581713Swpaul 25681713Swpaul if (ctob(UPAGES + vm->vm_dsize + vm->vm_ssize) >= 25781713Swpaul limit) 25881713Swpaul return (EFAULT); 25962672Swpaul 26062672Swpaul bcopy(p, &p->p_addr->u_kproc.kp_proc, sizeof(struct proc)); 26162672Swpaul fill_eproc(p, &p->p_addr->u_kproc.kp_eproc); 26262672Swpaul error = cpu_coredump(p, vp, cred); 26362672Swpaul if (error == 0) 26462672Swpaul error = vn_rdwr(UIO_WRITE, vp, vm->vm_daddr, 26562672Swpaul (int)ctob(vm->vm_dsize), (off_t)ctob(UPAGES), UIO_USERSPACE, 26662672Swpaul IO_NODELOCKED|IO_UNIT, cred, (int *) NULL, p); 26762672Swpaul if (error == 0) 26862672Swpaul error = vn_rdwr(UIO_WRITE, vp, 26962672Swpaul (caddr_t) trunc_page(USRSTACK - ctob(vm->vm_ssize)), 27062672Swpaul round_page(ctob(vm->vm_ssize)), 27162672Swpaul (off_t)ctob(UPAGES) + ctob(vm->vm_dsize), UIO_USERSPACE, 27262672Swpaul IO_NODELOCKED|IO_UNIT, cred, (int *) NULL, p); 27362672Swpaul return error; 27450974Swpaul} 27550974Swpaul 27650974Swpaul/* 27750974Swpaul * Tell kern_execve.c about it, with a little help from the linker. 27850974Swpaul */ 27950974Swpaulstatic struct execsw aout_execsw = { exec_aout_imgact, "a.out" }; 28050974SwpaulEXEC_SET(aout, aout_execsw); 28150974Swpaul