143412Snewton/*- 243412Snewton * Copyright (c) 1998 Mark Newton 3230132Suqs * Copyright (c) 1994-1996 S��ren Schmidt 443412Snewton * All rights reserved. 543412Snewton * 643412Snewton * Based heavily on /sys/kern/imgact_aout.c which is: 743412Snewton * Copyright (c) 1993, David Greenman 843412Snewton * 943412Snewton * Redistribution and use in source and binary forms, with or without 1043412Snewton * modification, are permitted provided that the following conditions 1143412Snewton * are met: 1243412Snewton * 1. Redistributions of source code must retain the above copyright 1343412Snewton * notice, this list of conditions and the following disclaimer 1443412Snewton * in this position and unchanged. 1543412Snewton * 2. Redistributions in binary form must reproduce the above copyright 1643412Snewton * notice, this list of conditions and the following disclaimer in the 1743412Snewton * documentation and/or other materials provided with the distribution. 1843412Snewton * 3. The name of the author may not be used to endorse or promote products 1997748Sschweikh * derived from this software without specific prior written permission 2043412Snewton * 2143412Snewton * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 2243412Snewton * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 2343412Snewton * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2443412Snewton * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 2543412Snewton * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2643412Snewton * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2743412Snewton * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2843412Snewton * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2943412Snewton * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 3043412Snewton * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3143412Snewton */ 3243412Snewton 33116174Sobrien#include <sys/cdefs.h> 34116174Sobrien__FBSDID("$FreeBSD$"); 35116174Sobrien 3643412Snewton#include <sys/param.h> 3743412Snewton#include <sys/systm.h> 3843412Snewton#include <sys/exec.h> 3943412Snewton#include <sys/imgact.h> 4043412Snewton#include <sys/imgact_aout.h> 4143412Snewton#include <sys/kernel.h> 4243412Snewton#include <sys/lock.h> 4376166Smarkm#include <sys/mman.h> 4476166Smarkm#include <sys/mutex.h> 4543412Snewton#include <sys/proc.h> 46220373Strasz#include <sys/racct.h> 4776166Smarkm#include <sys/resourcevar.h> 4843412Snewton#include <sys/vnode.h> 4943412Snewton 5043412Snewton#include <vm/vm.h> 5143412Snewton#include <vm/vm_kern.h> 5243412Snewton#include <vm/vm_param.h> 5343412Snewton#include <vm/pmap.h> 5443412Snewton#include <vm/vm_map.h> 5543412Snewton#include <vm/vm_extern.h> 5643412Snewton 5765302Sobrien#include <compat/svr4/svr4.h> 5843412Snewton 5992761Salfredstatic int exec_svr4_imgact(struct image_params *iparams); 6043412Snewton 6143412Snewtonstatic int 6243412Snewtonexec_svr4_imgact(imgp) 6343412Snewton struct image_params *imgp; 6443412Snewton{ 6543412Snewton const struct exec *a_out = (const struct exec *) imgp->image_header; 6643412Snewton struct vmspace *vmspace; 6743412Snewton vm_offset_t vmaddr; 6843412Snewton unsigned long virtual_offset, file_offset; 6943412Snewton unsigned long bss_size; 70231885Skib ssize_t aresid; 7143412Snewton int error; 7243412Snewton 7343412Snewton if (((a_out->a_magic >> 16) & 0xff) != 0x64) 7443412Snewton return -1; 7543412Snewton 7643412Snewton /* 7743412Snewton * Set file/virtual offset based on a.out variant. 7843412Snewton */ 7943412Snewton switch ((int)(a_out->a_magic & 0xffff)) { 8043412Snewton case 0413: 8143412Snewton virtual_offset = 0; 8243412Snewton file_offset = 1024; 8343412Snewton break; 8443412Snewton case 0314: 8543412Snewton virtual_offset = 4096; 8643412Snewton file_offset = 0; 8743412Snewton break; 8843412Snewton default: 8943412Snewton return (-1); 9043412Snewton } 9143412Snewton bss_size = round_page(a_out->a_bss); 9243412Snewton#ifdef DEBUG 93131013Sobrien printf("imgact: text: %08lx, data: %08lx, bss: %08lx\n", (u_long)a_out->a_text, (u_long)a_out->a_data, bss_size); 9443412Snewton#endif 9543412Snewton 9643412Snewton /* 9743412Snewton * Check various fields in header for validity/bounds. 9843412Snewton */ 9943412Snewton if (a_out->a_entry < virtual_offset || 10043412Snewton a_out->a_entry >= virtual_offset + a_out->a_text || 10143412Snewton a_out->a_text & PAGE_MASK || a_out->a_data & PAGE_MASK) 10243412Snewton return (-1); 10343412Snewton 10443412Snewton /* text + data can't exceed file size */ 10543412Snewton if (a_out->a_data + a_out->a_text > imgp->attr->va_size) 10643412Snewton return (EFAULT); 10743412Snewton /* 10843412Snewton * text/data/bss must not exceed limits 10943412Snewton */ 110125454Sjhb PROC_LOCK(imgp->proc); 11184783Sps if (a_out->a_text > maxtsiz || 112284215Smjg a_out->a_data + bss_size > lim_cur_proc(imgp->proc, RLIMIT_DATA) || 113220515Strasz racct_set(imgp->proc, RACCT_DATA, a_out->a_data + bss_size) != 0) { 114125454Sjhb PROC_UNLOCK(imgp->proc); 11543412Snewton return (ENOMEM); 116125454Sjhb } 117125454Sjhb PROC_UNLOCK(imgp->proc); 11843412Snewton 119175294Sattilio VOP_UNLOCK(imgp->vp, 0); 120101771Sjeff 12143412Snewton /* 12243412Snewton * Destroy old process VM and create a new one (with a new stack) 12343412Snewton */ 124173361Skib error = exec_new_vmspace(imgp, &svr4_sysvec); 125173361Skib if (error) 126173361Skib goto fail; 12743412Snewton vmspace = imgp->proc->p_vmspace; 12843412Snewton 12943412Snewton /* 13043412Snewton * Check if file_offset page aligned,. 13143412Snewton * Currently we cannot handle misalinged file offsets, 13243412Snewton * and so we read in the entire image (what a waste). 13343412Snewton */ 13443412Snewton if (file_offset & PAGE_MASK) { 13543412Snewton#ifdef DEBUG 13680114Sassar printf("imgact: Non page aligned binary %lu\n", file_offset); 13743412Snewton#endif 13843412Snewton /* 13943412Snewton * Map text+data+bss read/write/execute 14043412Snewton */ 14143412Snewton vmaddr = virtual_offset; 14243412Snewton error = vm_map_find(&vmspace->vm_map, NULL, 0, &vmaddr, 143255426Sjhb a_out->a_text + a_out->a_data + bss_size, 0, VMFS_NO_SPACE, 144255426Sjhb VM_PROT_ALL, VM_PROT_ALL, 0); 14543412Snewton if (error) 146101771Sjeff goto fail; 14743412Snewton 148231885Skib error = vn_rdwr(UIO_READ, imgp->vp, (void *)vmaddr, file_offset, 149231885Skib a_out->a_text + a_out->a_data, UIO_USERSPACE, 0, 150231885Skib curthread->td_ucred, NOCRED, &aresid, curthread); 151231885Skib if (error != 0) 152231885Skib goto fail; 153231885Skib if (aresid != 0) { 154231885Skib error = ENOEXEC; 155231885Skib goto fail; 156231885Skib } 15743412Snewton 15843412Snewton /* 15943412Snewton * remove write enable on the 'text' part 16043412Snewton */ 16143412Snewton error = vm_map_protect(&vmspace->vm_map, 16243412Snewton vmaddr, 16343412Snewton vmaddr + a_out->a_text, 16443412Snewton VM_PROT_EXECUTE|VM_PROT_READ, 16543412Snewton TRUE); 16643412Snewton if (error) 167101771Sjeff goto fail; 16843412Snewton } 16943412Snewton else { 17043412Snewton#ifdef DEBUG 17180114Sassar printf("imgact: Page aligned binary %lu\n", file_offset); 17243412Snewton#endif 17343412Snewton /* 17443412Snewton * Map text+data read/execute 17543412Snewton */ 17643412Snewton vmaddr = virtual_offset; 17743412Snewton error = vm_mmap(&vmspace->vm_map, &vmaddr, 17843412Snewton a_out->a_text + a_out->a_data, 17943412Snewton VM_PROT_READ | VM_PROT_EXECUTE, 18043412Snewton VM_PROT_ALL, 18143412Snewton MAP_PRIVATE | MAP_FIXED, 182144501Sjhb OBJT_VNODE, imgp->vp, file_offset); 18343412Snewton if (error) 184101771Sjeff goto fail; 18543412Snewton 18643412Snewton#ifdef DEBUG 18780114Sassar printf("imgact: startaddr=%08lx, length=%08lx\n", (u_long)vmaddr, 188131013Sobrien (u_long)a_out->a_text + a_out->a_data); 18943412Snewton#endif 19043412Snewton /* 19143412Snewton * allow read/write of data 19243412Snewton */ 19343412Snewton error = vm_map_protect(&vmspace->vm_map, 19443412Snewton vmaddr + a_out->a_text, 19543412Snewton vmaddr + a_out->a_text + a_out->a_data, 19643412Snewton VM_PROT_ALL, 19743412Snewton FALSE); 19843412Snewton if (error) 199101771Sjeff goto fail; 20043412Snewton 20143412Snewton /* 20243412Snewton * Allocate anon demand-zeroed area for uninitialized data 20343412Snewton */ 20443412Snewton if (bss_size != 0) { 20543412Snewton vmaddr = virtual_offset + a_out->a_text + a_out->a_data; 20643412Snewton error = vm_map_find(&vmspace->vm_map, NULL, 0, &vmaddr, 207255426Sjhb bss_size, 0, VMFS_NO_SPACE, VM_PROT_ALL, VM_PROT_ALL, 0); 20843412Snewton if (error) 209101771Sjeff goto fail; 21043412Snewton#ifdef DEBUG 21180114Sassar printf("imgact: bssaddr=%08lx, length=%08lx\n", 21280114Sassar (u_long)vmaddr, bss_size); 21343412Snewton#endif 21443412Snewton 21543412Snewton } 21643412Snewton } 21743412Snewton /* Fill in process VM information */ 21843412Snewton vmspace->vm_tsize = round_page(a_out->a_text) >> PAGE_SHIFT; 21943412Snewton vmspace->vm_dsize = round_page(a_out->a_data + bss_size) >> PAGE_SHIFT; 22043412Snewton vmspace->vm_taddr = (caddr_t)virtual_offset; 22143412Snewton vmspace->vm_daddr = (caddr_t)virtual_offset + a_out->a_text; 22243412Snewton 22343412Snewton /* Fill in image_params */ 22443412Snewton imgp->interpreted = 0; 22543412Snewton imgp->entry_addr = a_out->a_entry; 22643412Snewton 22743412Snewton imgp->proc->p_sysent = &svr4_sysvec; 228101771Sjefffail: 229175202Sattilio vn_lock(imgp->vp, LK_EXCLUSIVE | LK_RETRY); 230101771Sjeff return (error); 23143412Snewton} 23243412Snewton 23343412Snewton/* 23443412Snewton * Tell kern_execve.c about it, with a little help from the linker. 23543412Snewton */ 23646889Speterstruct execsw svr4_execsw = { exec_svr4_imgact, "svr4 ELF" }; 23745738SpeterEXEC_SET(execsw_set, svr4_execsw); 23843412Snewton 239