imgact_aout.c revision 140992
154359Sroberto/*- 254359Sroberto * Copyright (c) 1993, David Greenman 354359Sroberto * All rights reserved. 454359Sroberto * 554359Sroberto * Redistribution and use in source and binary forms, with or without 682498Sroberto * modification, are permitted provided that the following conditions 754359Sroberto * are met: 854359Sroberto * 1. Redistributions of source code must retain the above copyright 954359Sroberto * notice, this list of conditions and the following disclaimer. 1054359Sroberto * 2. Redistributions in binary form must reproduce the above copyright 1154359Sroberto * notice, this list of conditions and the following disclaimer in the 1254359Sroberto * documentation and/or other materials provided with the distribution. 1354359Sroberto * 1454359Sroberto * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1554359Sroberto * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1654359Sroberto * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1754359Sroberto * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1854359Sroberto * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1954359Sroberto * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2054359Sroberto * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2154359Sroberto * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2254359Sroberto * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2354359Sroberto * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2454359Sroberto * SUCH DAMAGE. 2554359Sroberto */ 2654359Sroberto 2754359Sroberto#include <sys/cdefs.h> 2854359Sroberto__FBSDID("$FreeBSD: head/sys/kern/imgact_aout.c 140992 2005-01-29 23:12:00Z sobomax $"); 2954359Sroberto 3054359Sroberto#include <sys/param.h> 3154359Sroberto#include <sys/exec.h> 3254359Sroberto#include <sys/imgact.h> 3354359Sroberto#include <sys/imgact_aout.h> 3454359Sroberto#include <sys/kernel.h> 3554359Sroberto#include <sys/lock.h> 3654359Sroberto#include <sys/malloc.h> 3754359Sroberto#include <sys/mutex.h> 3854359Sroberto#include <sys/proc.h> 3954359Sroberto#include <sys/resourcevar.h> 4054359Sroberto#include <sys/signalvar.h> 4154359Sroberto#include <sys/syscall.h> 4254359Sroberto#include <sys/sysent.h> 4354359Sroberto#include <sys/systm.h> 4454359Sroberto#include <sys/vnode.h> 4554359Sroberto 4654359Sroberto#include <machine/frame.h> 4754359Sroberto#include <machine/md_var.h> 4854359Sroberto 4954359Sroberto#include <vm/vm.h> 5054359Sroberto#include <vm/pmap.h> 5154359Sroberto#include <vm/vm_map.h> 5254359Sroberto#include <vm/vm_object.h> 5354359Sroberto#include <vm/vm_param.h> 5454359Sroberto 5554359Srobertostatic int exec_aout_imgact(struct image_params *imgp); 5654359Srobertostatic int aout_fixup(register_t **stack_base, struct image_params *imgp); 5754359Sroberto 5854359Srobertostruct sysentvec aout_sysvec = { 5954359Sroberto SYS_MAXSYSCALL, 6054359Sroberto sysent, 6154359Sroberto 0, 6254359Sroberto 0, 6354359Sroberto NULL, 6454359Sroberto 0, 6554359Sroberto NULL, 6654359Sroberto NULL, 6754359Sroberto aout_fixup, 6854359Sroberto sendsig, 6954359Sroberto sigcode, 7054359Sroberto &szsigcode, 7154359Sroberto NULL, 7254359Sroberto "FreeBSD a.out", 7354359Sroberto NULL, 7454359Sroberto NULL, 7554359Sroberto MINSIGSTKSZ, 7654359Sroberto PAGE_SIZE, 7754359Sroberto VM_MIN_ADDRESS, 7854359Sroberto VM_MAXUSER_ADDRESS, 7954359Sroberto USRSTACK, 8054359Sroberto PS_STRINGS, 8154359Sroberto VM_PROT_ALL, 8254359Sroberto exec_copyout_strings, 8354359Sroberto exec_setregs, 8454359Sroberto NULL 8554359Sroberto}; 8654359Sroberto 8754359Srobertostatic int 8854359Srobertoaout_fixup(stack_base, imgp) 8954359Sroberto register_t **stack_base; 9054359Sroberto struct image_params *imgp; 9154359Sroberto{ 9254359Sroberto 9354359Sroberto return (suword(--(*stack_base), imgp->args->argc)); 9454359Sroberto} 9554359Sroberto 9654359Srobertostatic int 9754359Srobertoexec_aout_imgact(imgp) 9854359Sroberto struct image_params *imgp; 9954359Sroberto{ 10054359Sroberto const struct exec *a_out = (const struct exec *) imgp->image_header; 10154359Sroberto struct vmspace *vmspace; 10254359Sroberto struct vnode *vp; 10354359Sroberto vm_map_t map; 10454359Sroberto vm_object_t object; 10554359Sroberto vm_offset_t text_end, data_end; 10654359Sroberto unsigned long virtual_offset; 10754359Sroberto unsigned long file_offset; 10854359Sroberto unsigned long bss_size; 10954359Sroberto int error; 11054359Sroberto 11154359Sroberto GIANT_REQUIRED; 11254359Sroberto 11354359Sroberto /* 11454359Sroberto * Linux and *BSD binaries look very much alike, 11554359Sroberto * only the machine id is different: 11654359Sroberto * 0x64 for Linux, 0x86 for *BSD, 0x00 for BSDI. 11754359Sroberto * NetBSD is in network byte order.. ugh. 11854359Sroberto */ 11954359Sroberto if (((a_out->a_magic >> 16) & 0xff) != 0x86 && 12054359Sroberto ((a_out->a_magic >> 16) & 0xff) != 0 && 12154359Sroberto ((((int)ntohl(a_out->a_magic)) >> 16) & 0xff) != 0x86) 12254359Sroberto return -1; 12354359Sroberto 12454359Sroberto /* 12554359Sroberto * Set file/virtual offset based on a.out variant. 12654359Sroberto * We do two cases: host byte order and network byte order 12754359Sroberto * (for NetBSD compatibility) 12854359Sroberto */ 12954359Sroberto switch ((int)(a_out->a_magic & 0xffff)) { 13054359Sroberto case ZMAGIC: 13154359Sroberto virtual_offset = 0; 13254359Sroberto if (a_out->a_text) { 13354359Sroberto file_offset = PAGE_SIZE; 13454359Sroberto } else { 13554359Sroberto /* Bill's "screwball mode" */ 13654359Sroberto file_offset = 0; 13754359Sroberto } 13854359Sroberto break; 13954359Sroberto case QMAGIC: 14054359Sroberto virtual_offset = PAGE_SIZE; 14154359Sroberto file_offset = 0; 14254359Sroberto /* Pass PS_STRINGS for BSD/OS binaries only. */ 14354359Sroberto if (N_GETMID(*a_out) == MID_ZERO) 14454359Sroberto imgp->ps_strings = aout_sysvec.sv_psstrings; 14554359Sroberto break; 14654359Sroberto default: 14754359Sroberto /* NetBSD compatibility */ 14854359Sroberto switch ((int)(ntohl(a_out->a_magic) & 0xffff)) { 14954359Sroberto case ZMAGIC: 15054359Sroberto case QMAGIC: 15154359Sroberto virtual_offset = PAGE_SIZE; 15254359Sroberto file_offset = 0; 15354359Sroberto break; 15454359Sroberto default: 15554359Sroberto return (-1); 15654359Sroberto } 15754359Sroberto } 15854359Sroberto 15954359Sroberto bss_size = roundup(a_out->a_bss, PAGE_SIZE); 16054359Sroberto 16154359Sroberto /* 16254359Sroberto * Check various fields in header for validity/bounds. 16354359Sroberto */ 16454359Sroberto if (/* entry point must lay with text region */ 16554359Sroberto a_out->a_entry < virtual_offset || 16654359Sroberto a_out->a_entry >= virtual_offset + a_out->a_text || 16754359Sroberto 16854359Sroberto /* text and data size must each be page rounded */ 16954359Sroberto a_out->a_text & PAGE_MASK || a_out->a_data & PAGE_MASK) 17054359Sroberto return (-1); 17154359Sroberto 17254359Sroberto /* text + data can't exceed file size */ 17354359Sroberto if (a_out->a_data + a_out->a_text > imgp->attr->va_size) 17454359Sroberto return (EFAULT); 17554359Sroberto 17654359Sroberto /* 17754359Sroberto * text/data/bss must not exceed limits 17854359Sroberto */ 17954359Sroberto PROC_LOCK(imgp->proc); 18054359Sroberto if (/* text can't exceed maximum text size */ 18154359Sroberto a_out->a_text > maxtsiz || 18254359Sroberto 18354359Sroberto /* data + bss can't exceed rlimit */ 18454359Sroberto a_out->a_data + bss_size > lim_cur(imgp->proc, RLIMIT_DATA)) { 18554359Sroberto PROC_UNLOCK(imgp->proc); 18654359Sroberto return (ENOMEM); 18754359Sroberto } 18854359Sroberto PROC_UNLOCK(imgp->proc); 18954359Sroberto 19054359Sroberto /* 19154359Sroberto * Destroy old process VM and create a new one (with a new stack) 19254359Sroberto */ 19354359Sroberto exec_new_vmspace(imgp, &aout_sysvec); 19454359Sroberto 19554359Sroberto /* 19654359Sroberto * The vm space can be changed by exec_new_vmspace 19754359Sroberto */ 19854359Sroberto vmspace = imgp->proc->p_vmspace; 19954359Sroberto 20054359Sroberto vp = imgp->vp; 20154359Sroberto object = imgp->object; 20254359Sroberto map = &vmspace->vm_map; 20354359Sroberto vm_map_lock(map); 20454359Sroberto vm_object_reference(object); 20554359Sroberto 20654359Sroberto text_end = virtual_offset + a_out->a_text; 20754359Sroberto error = vm_map_insert(map, object, 20854359Sroberto file_offset, 20954359Sroberto virtual_offset, text_end, 21054359Sroberto VM_PROT_READ | VM_PROT_EXECUTE, VM_PROT_ALL, 21154359Sroberto MAP_COPY_ON_WRITE | MAP_PREFAULT); 21254359Sroberto if (error) { 21354359Sroberto vm_map_unlock(map); 21454359Sroberto return (error); 21554359Sroberto } 21654359Sroberto data_end = text_end + a_out->a_data; 21754359Sroberto if (a_out->a_data) { 21854359Sroberto vm_object_reference(object); 21954359Sroberto error = vm_map_insert(map, object, 22054359Sroberto file_offset + a_out->a_text, 22154359Sroberto text_end, data_end, 22254359Sroberto VM_PROT_ALL, VM_PROT_ALL, 22354359Sroberto MAP_COPY_ON_WRITE | MAP_PREFAULT); 22454359Sroberto if (error) { 22554359Sroberto vm_map_unlock(map); 226 return (error); 227 } 228 } 229 230 if (bss_size) { 231 error = vm_map_insert(map, NULL, 0, 232 data_end, data_end + bss_size, 233 VM_PROT_ALL, VM_PROT_ALL, 0); 234 if (error) { 235 vm_map_unlock(map); 236 return (error); 237 } 238 } 239 vm_map_unlock(map); 240 241 /* Fill in process VM information */ 242 vmspace->vm_tsize = a_out->a_text >> PAGE_SHIFT; 243 vmspace->vm_dsize = (a_out->a_data + bss_size) >> PAGE_SHIFT; 244 vmspace->vm_taddr = (caddr_t) (uintptr_t) virtual_offset; 245 vmspace->vm_daddr = (caddr_t) (uintptr_t) 246 (virtual_offset + a_out->a_text); 247 248 /* Fill in image_params */ 249 imgp->interpreted = 0; 250 imgp->entry_addr = a_out->a_entry; 251 252 imgp->proc->p_sysent = &aout_sysvec; 253 254 return (0); 255} 256 257/* 258 * Tell kern_execve.c about it, with a little help from the linker. 259 */ 260static struct execsw aout_execsw = { exec_aout_imgact, "a.out" }; 261EXEC_SET(aout, aout_execsw); 262