imgact_svr4.c revision 284215
121288Sdavidn/*- 221288Sdavidn * Copyright (c) 1998 Mark Newton 321288Sdavidn * Copyright (c) 1994-1996 S��ren Schmidt 421288Sdavidn * All rights reserved. 521288Sdavidn * 621288Sdavidn * Based heavily on /sys/kern/imgact_aout.c which is: 721288Sdavidn * Copyright (c) 1993, David Greenman 821288Sdavidn * 921288Sdavidn * Redistribution and use in source and binary forms, with or without 1021288Sdavidn * modification, are permitted provided that the following conditions 1121288Sdavidn * are met: 1221288Sdavidn * 1. Redistributions of source code must retain the above copyright 1321288Sdavidn * notice, this list of conditions and the following disclaimer 1421288Sdavidn * in this position and unchanged. 1521288Sdavidn * 2. Redistributions in binary form must reproduce the above copyright 1621288Sdavidn * notice, this list of conditions and the following disclaimer in the 1721288Sdavidn * documentation and/or other materials provided with the distribution. 1821288Sdavidn * 3. The name of the author may not be used to endorse or promote products 1921288Sdavidn * derived from this software without specific prior written permission 2021288Sdavidn * 2121288Sdavidn * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 2221288Sdavidn * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 2321288Sdavidn * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2421288Sdavidn * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 2584225Sdillon * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2684225Sdillon * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2784225Sdillon * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2821288Sdavidn * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2921288Sdavidn * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 3021288Sdavidn * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3121288Sdavidn */ 3221288Sdavidn 3321288Sdavidn#include <sys/cdefs.h> 3422084Sdavidn__FBSDID("$FreeBSD: head/sys/compat/svr4/imgact_svr4.c 284215 2015-06-10 10:48:12Z mjg $"); 3521288Sdavidn 3621288Sdavidn#include <sys/param.h> 3721288Sdavidn#include <sys/systm.h> 3821288Sdavidn#include <sys/exec.h> 3921288Sdavidn#include <sys/imgact.h> 4021288Sdavidn#include <sys/imgact_aout.h> 4121288Sdavidn#include <sys/kernel.h> 4236351Ssteve#include <sys/lock.h> 4321288Sdavidn#include <sys/mman.h> 4421288Sdavidn#include <sys/mutex.h> 4521288Sdavidn#include <sys/proc.h> 4625670Sdavidn#include <sys/racct.h> 4725670Sdavidn#include <sys/resourcevar.h> 4825670Sdavidn#include <sys/vnode.h> 4921288Sdavidn 5025670Sdavidn#include <vm/vm.h> 5125670Sdavidn#include <vm/vm_kern.h> 5225670Sdavidn#include <vm/vm_param.h> 5325670Sdavidn#include <vm/pmap.h> 5425670Sdavidn#include <vm/vm_map.h> 5525670Sdavidn#include <vm/vm_extern.h> 5625670Sdavidn 5725670Sdavidn#include <compat/svr4/svr4.h> 5825670Sdavidn 5963149Ssheldonhstatic int exec_svr4_imgact(struct image_params *iparams); 6098851Sdillon 6125670Sdavidnstatic int 6221288Sdavidnexec_svr4_imgact(imgp) 6321288Sdavidn struct image_params *imgp; 6421288Sdavidn{ 6521288Sdavidn const struct exec *a_out = (const struct exec *) imgp->image_header; 6621288Sdavidn struct vmspace *vmspace; 6721288Sdavidn vm_offset_t vmaddr; 6825670Sdavidn unsigned long virtual_offset, file_offset; 6921288Sdavidn unsigned long bss_size; 7025670Sdavidn ssize_t aresid; 7125670Sdavidn int error; 7221402Sdavidn 7325670Sdavidn if (((a_out->a_magic >> 16) & 0xff) != 0x64) 7425670Sdavidn return -1; 7521288Sdavidn 7625670Sdavidn /* 7725670Sdavidn * Set file/virtual offset based on a.out variant. 7825670Sdavidn */ 7925670Sdavidn switch ((int)(a_out->a_magic & 0xffff)) { 8025670Sdavidn case 0413: 8125670Sdavidn virtual_offset = 0; 8225670Sdavidn file_offset = 1024; 8325670Sdavidn break; 8425670Sdavidn case 0314: 8525670Sdavidn virtual_offset = 4096; 8625670Sdavidn file_offset = 0; 8721288Sdavidn break; 8825670Sdavidn default: 8925670Sdavidn return (-1); 9025670Sdavidn } 9125670Sdavidn bss_size = round_page(a_out->a_bss); 9225670Sdavidn#ifdef DEBUG 9325670Sdavidn printf("imgact: text: %08lx, data: %08lx, bss: %08lx\n", (u_long)a_out->a_text, (u_long)a_out->a_data, bss_size); 9425670Sdavidn#endif 9521288Sdavidn 9625670Sdavidn /* 9725670Sdavidn * Check various fields in header for validity/bounds. 9821288Sdavidn */ 9925670Sdavidn if (a_out->a_entry < virtual_offset || 10025670Sdavidn a_out->a_entry >= virtual_offset + a_out->a_text || 10125670Sdavidn a_out->a_text & PAGE_MASK || a_out->a_data & PAGE_MASK) 10225670Sdavidn return (-1); 10321288Sdavidn 10425670Sdavidn /* text + data can't exceed file size */ 10525670Sdavidn if (a_out->a_data + a_out->a_text > imgp->attr->va_size) 10625670Sdavidn return (EFAULT); 10725670Sdavidn /* 10821288Sdavidn * text/data/bss must not exceed limits 10921288Sdavidn */ 11025670Sdavidn PROC_LOCK(imgp->proc); 11125670Sdavidn if (a_out->a_text > maxtsiz || 11221288Sdavidn a_out->a_data + bss_size > lim_cur_proc(imgp->proc, RLIMIT_DATA) || 11325670Sdavidn racct_set(imgp->proc, RACCT_DATA, a_out->a_data + bss_size) != 0) { 11425670Sdavidn PROC_UNLOCK(imgp->proc); 11525670Sdavidn return (ENOMEM); 11698977Sache } 11721288Sdavidn PROC_UNLOCK(imgp->proc); 11898977Sache 11998977Sache VOP_UNLOCK(imgp->vp, 0); 12098977Sache 12198977Sache /* 12221288Sdavidn * Destroy old process VM and create a new one (with a new stack) 12398977Sache */ 12498977Sache error = exec_new_vmspace(imgp, &svr4_sysvec); 12598977Sache if (error) 12698977Sache goto fail; 12798977Sache vmspace = imgp->proc->p_vmspace; 12821288Sdavidn 12921288Sdavidn /* 13021288Sdavidn * Check if file_offset page aligned,. 13194202Sru * Currently we cannot handle misalinged file offsets, 13221288Sdavidn * and so we read in the entire image (what a waste). 13325670Sdavidn */ 13421288Sdavidn if (file_offset & PAGE_MASK) { 13525670Sdavidn#ifdef DEBUG 13625670Sdavidn printf("imgact: Non page aligned binary %lu\n", file_offset); 13725670Sdavidn#endif 13825670Sdavidn /* 13921288Sdavidn * Map text+data+bss read/write/execute 14025670Sdavidn */ 14125670Sdavidn vmaddr = virtual_offset; 14294202Sru error = vm_map_find(&vmspace->vm_map, NULL, 0, &vmaddr, 14325670Sdavidn a_out->a_text + a_out->a_data + bss_size, 0, VMFS_NO_SPACE, 14425670Sdavidn VM_PROT_ALL, VM_PROT_ALL, 0); 14594202Sru if (error) 14625670Sdavidn goto fail; 14725670Sdavidn 14821288Sdavidn error = vn_rdwr(UIO_READ, imgp->vp, (void *)vmaddr, file_offset, 14925670Sdavidn a_out->a_text + a_out->a_data, UIO_USERSPACE, 0, 15025670Sdavidn curthread->td_ucred, NOCRED, &aresid, curthread); 15125670Sdavidn if (error != 0) 15221288Sdavidn goto fail; 15325670Sdavidn if (aresid != 0) { 15425670Sdavidn error = ENOEXEC; 15521288Sdavidn goto fail; 15625670Sdavidn } 15725670Sdavidn 15825670Sdavidn /* 15925670Sdavidn * remove write enable on the 'text' part 16025670Sdavidn */ 16125670Sdavidn error = vm_map_protect(&vmspace->vm_map, 16225670Sdavidn vmaddr, 16321288Sdavidn vmaddr + a_out->a_text, 16447118Sache VM_PROT_EXECUTE|VM_PROT_READ, 16525670Sdavidn TRUE); 16625670Sdavidn if (error) 16725670Sdavidn goto fail; 16825670Sdavidn } 16925670Sdavidn else { 17025670Sdavidn#ifdef DEBUG 17125670Sdavidn printf("imgact: Page aligned binary %lu\n", file_offset); 17225670Sdavidn#endif 17325670Sdavidn /* 17425670Sdavidn * Map text+data read/execute 17525670Sdavidn */ 17625670Sdavidn vmaddr = virtual_offset; 17725670Sdavidn error = vm_mmap(&vmspace->vm_map, &vmaddr, 17825670Sdavidn a_out->a_text + a_out->a_data, 17925670Sdavidn VM_PROT_READ | VM_PROT_EXECUTE, 18025670Sdavidn VM_PROT_ALL, 18121288Sdavidn MAP_PRIVATE | MAP_FIXED, 18221288Sdavidn OBJT_VNODE, imgp->vp, file_offset); 18325670Sdavidn if (error) 18425670Sdavidn goto fail; 18521288Sdavidn 18621288Sdavidn#ifdef DEBUG 18721288Sdavidn printf("imgact: startaddr=%08lx, length=%08lx\n", (u_long)vmaddr, 18821288Sdavidn (u_long)a_out->a_text + a_out->a_data); 18921288Sdavidn#endif 19021288Sdavidn /* 19125670Sdavidn * allow read/write of data 19225670Sdavidn */ 19325670Sdavidn error = vm_map_protect(&vmspace->vm_map, 19425670Sdavidn vmaddr + a_out->a_text, 19521288Sdavidn vmaddr + a_out->a_text + a_out->a_data, 19625670Sdavidn VM_PROT_ALL, 19725670Sdavidn FALSE); 19821288Sdavidn if (error) 19925670Sdavidn goto fail; 20094202Sru 20194202Sru /* 20221288Sdavidn * Allocate anon demand-zeroed area for uninitialized data 20325670Sdavidn */ 20421288Sdavidn if (bss_size != 0) { 20525670Sdavidn vmaddr = virtual_offset + a_out->a_text + a_out->a_data; 20698977Sache error = vm_map_find(&vmspace->vm_map, NULL, 0, &vmaddr, 20725670Sdavidn bss_size, 0, VMFS_NO_SPACE, VM_PROT_ALL, VM_PROT_ALL, 0); 20825670Sdavidn if (error) 20925670Sdavidn goto fail; 21025670Sdavidn#ifdef DEBUG 21125670Sdavidn printf("imgact: bssaddr=%08lx, length=%08lx\n", 21221288Sdavidn (u_long)vmaddr, bss_size); 21321288Sdavidn#endif 21425670Sdavidn 21525670Sdavidn } 21625670Sdavidn } 21725670Sdavidn /* Fill in process VM information */ 21825670Sdavidn vmspace->vm_tsize = round_page(a_out->a_text) >> PAGE_SHIFT; 21925670Sdavidn vmspace->vm_dsize = round_page(a_out->a_data + bss_size) >> PAGE_SHIFT; 22021402Sdavidn vmspace->vm_taddr = (caddr_t)virtual_offset; 22125670Sdavidn vmspace->vm_daddr = (caddr_t)virtual_offset + a_out->a_text; 22225670Sdavidn 22325670Sdavidn /* Fill in image_params */ 22421402Sdavidn imgp->interpreted = 0; 22525670Sdavidn imgp->entry_addr = a_out->a_entry; 22625670Sdavidn 22725670Sdavidn imgp->proc->p_sysent = &svr4_sysvec; 22825670Sdavidnfail: 22925670Sdavidn vn_lock(imgp->vp, LK_EXCLUSIVE | LK_RETRY); 23025670Sdavidn return (error); 23125670Sdavidn} 23225670Sdavidn 23325670Sdavidn/* 23425670Sdavidn * Tell kern_execve.c about it, with a little help from the linker. 23525670Sdavidn */ 23621288Sdavidnstruct execsw svr4_execsw = { exec_svr4_imgact, "svr4 ELF" }; 23721288SdavidnEXEC_SET(execsw_set, svr4_execsw); 23821288Sdavidn 23921288Sdavidn