19313Ssos/*- 2230132Suqs * Copyright (c) 1994-1996 S��ren Schmidt 39313Ssos * All rights reserved. 49313Ssos * 59313Ssos * Based heavily on /sys/kern/imgact_aout.c which is: 69313Ssos * Copyright (c) 1993, David Greenman 79313Ssos * 89313Ssos * Redistribution and use in source and binary forms, with or without 99313Ssos * modification, are permitted provided that the following conditions 109313Ssos * are met: 119313Ssos * 1. Redistributions of source code must retain the above copyright 12111798Sdes * notice, this list of conditions and the following disclaimer 139313Ssos * in this position and unchanged. 149313Ssos * 2. Redistributions in binary form must reproduce the above copyright 159313Ssos * notice, this list of conditions and the following disclaimer in the 169313Ssos * documentation and/or other materials provided with the distribution. 179313Ssos * 3. The name of the author may not be used to endorse or promote products 1897748Sschweikh * derived from this software without specific prior written permission 199313Ssos * 209313Ssos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 219313Ssos * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 229313Ssos * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 239313Ssos * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 249313Ssos * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 259313Ssos * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 269313Ssos * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 279313Ssos * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 289313Ssos * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 299313Ssos * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 309313Ssos */ 319313Ssos 32115705Sobrien#include <sys/cdefs.h> 33115705Sobrien__FBSDID("$FreeBSD$"); 34115705Sobrien 359313Ssos#include <sys/param.h> 369313Ssos#include <sys/systm.h> 379313Ssos#include <sys/exec.h> 389313Ssos#include <sys/imgact.h> 399313Ssos#include <sys/imgact_aout.h> 409313Ssos#include <sys/kernel.h> 4131561Sbde#include <sys/lock.h> 4276166Smarkm#include <sys/mman.h> 4376166Smarkm#include <sys/mutex.h> 4415494Sbde#include <sys/proc.h> 45220373Strasz#include <sys/racct.h> 4676166Smarkm#include <sys/resourcevar.h> 4715494Sbde#include <sys/vnode.h> 489313Ssos 499313Ssos#include <vm/vm.h> 509313Ssos#include <vm/vm_kern.h> 5112689Speter#include <vm/vm_param.h> 5212689Speter#include <vm/pmap.h> 5312689Speter#include <vm/vm_map.h> 5412842Sbde#include <vm/vm_extern.h> 559313Ssos 5614331Speter#include <i386/linux/linux.h> 5712458Sbde 5892765Salfredstatic int exec_linux_imgact(struct image_params *iparams); 5912458Sbde 6033181Seivindstatic int 61105441Smarkmexec_linux_imgact(struct image_params *imgp) 629313Ssos{ 6318024Sbde const struct exec *a_out = (const struct exec *) imgp->image_header; 6424848Sdyson struct vmspace *vmspace; 6514703Sbde vm_offset_t vmaddr; 6614703Sbde unsigned long virtual_offset, file_offset; 6714703Sbde unsigned long bss_size; 68231885Skib ssize_t aresid; 699313Ssos int error; 709313Ssos 719313Ssos if (((a_out->a_magic >> 16) & 0xff) != 0x64) 729313Ssos return -1; 739313Ssos 749313Ssos /* 759313Ssos * Set file/virtual offset based on a.out variant. 769313Ssos */ 779313Ssos switch ((int)(a_out->a_magic & 0xffff)) { 789313Ssos case 0413: 799313Ssos virtual_offset = 0; 809313Ssos file_offset = 1024; 819313Ssos break; 829313Ssos case 0314: 839313Ssos virtual_offset = 4096; 849313Ssos file_offset = 0; 859313Ssos break; 869313Ssos default: 879313Ssos return (-1); 889313Ssos } 899313Ssos bss_size = round_page(a_out->a_bss); 9014331Speter#ifdef DEBUG 9137950Sbde printf("imgact: text: %08lx, data: %08lx, bss: %08lx\n", 9237950Sbde (u_long)a_out->a_text, (u_long)a_out->a_data, bss_size); 9314331Speter#endif 949313Ssos 959313Ssos /* 969313Ssos * Check various fields in header for validity/bounds. 979313Ssos */ 989313Ssos if (a_out->a_entry < virtual_offset || 999313Ssos a_out->a_entry >= virtual_offset + a_out->a_text || 10015538Sphk a_out->a_text & PAGE_MASK || a_out->a_data & PAGE_MASK) 1019313Ssos return (-1); 1029313Ssos 1039313Ssos /* text + data can't exceed file size */ 10412130Sdg if (a_out->a_data + a_out->a_text > imgp->attr->va_size) 1059313Ssos return (EFAULT); 1069313Ssos /* 1079313Ssos * text/data/bss must not exceed limits 1089313Ssos */ 109125454Sjhb PROC_LOCK(imgp->proc); 11084783Sps if (a_out->a_text > maxtsiz || 111220373Strasz a_out->a_data + bss_size > lim_cur(imgp->proc, RLIMIT_DATA) || 112220373Strasz racct_set(imgp->proc, RACCT_DATA, a_out->a_data + bss_size) != 0) { 113125454Sjhb PROC_UNLOCK(imgp->proc); 1149313Ssos return (ENOMEM); 115125454Sjhb } 116125454Sjhb PROC_UNLOCK(imgp->proc); 1179313Ssos 118175294Sattilio VOP_UNLOCK(imgp->vp, 0); 119101771Sjeff 1209313Ssos /* 1219313Ssos * Destroy old process VM and create a new one (with a new stack) 1229313Ssos */ 123173361Skib error = exec_new_vmspace(imgp, &linux_sysvec); 124173361Skib if (error) 125173361Skib goto fail; 12624848Sdyson vmspace = imgp->proc->p_vmspace; 1279313Ssos 1289313Ssos /* 1299313Ssos * Check if file_offset page aligned,. 130166944Snetchild * Currently we cannot handle misaligned file offsets, 1319313Ssos * and so we read in the entire image (what a waste). 1329313Ssos */ 13315538Sphk if (file_offset & PAGE_MASK) { 1349313Ssos#ifdef DEBUG 13537950Sbde printf("imgact: Non page aligned binary %lu\n", file_offset); 1369313Ssos#endif 1379313Ssos /* 13814114Speter * Map text+data+bss read/write/execute 1399313Ssos */ 1409313Ssos vmaddr = virtual_offset; 1419313Ssos error = vm_map_find(&vmspace->vm_map, NULL, 0, &vmaddr, 142255426Sjhb a_out->a_text + a_out->a_data + bss_size, 0, VMFS_NO_SPACE, 143255426Sjhb VM_PROT_ALL, VM_PROT_ALL, 0); 1449313Ssos if (error) 145101771Sjeff goto fail; 1469313Ssos 147231885Skib error = vn_rdwr(UIO_READ, imgp->vp, (void *)vmaddr, file_offset, 148231885Skib a_out->a_text + a_out->a_data, UIO_USERSPACE, 0, 149231885Skib curthread->td_ucred, NOCRED, &aresid, curthread); 150231885Skib if (error != 0) 151231885Skib goto fail; 152231885Skib if (aresid != 0) { 153231885Skib error = ENOEXEC; 154231885Skib goto fail; 155231885Skib } 1569313Ssos 1579313Ssos /* 15814114Speter * remove write enable on the 'text' part 1599313Ssos */ 16014471Speter error = vm_map_protect(&vmspace->vm_map, 16114471Speter vmaddr, 162111798Sdes vmaddr + a_out->a_text, 163111798Sdes VM_PROT_EXECUTE|VM_PROT_READ, 164111798Sdes TRUE); 1659313Ssos if (error) 166101771Sjeff goto fail; 1679313Ssos } 1689313Ssos else { 1699313Ssos#ifdef DEBUG 17037950Sbde printf("imgact: Page aligned binary %lu\n", file_offset); 1719313Ssos#endif 1729313Ssos /* 17314114Speter * Map text+data read/execute 1749313Ssos */ 1759313Ssos vmaddr = virtual_offset; 17614114Speter error = vm_mmap(&vmspace->vm_map, &vmaddr, 17714114Speter a_out->a_text + a_out->a_data, 178111798Sdes VM_PROT_READ | VM_PROT_EXECUTE, 179111798Sdes VM_PROT_ALL, 180111798Sdes MAP_PRIVATE | MAP_FIXED, 181144501Sjhb OBJT_VNODE, 182144501Sjhb imgp->vp, file_offset); 1839313Ssos if (error) 184101771Sjeff goto fail; 185111798Sdes 18614331Speter#ifdef DEBUG 18737950Sbde printf("imgact: startaddr=%08lx, length=%08lx\n", 188131014Sobrien (u_long)vmaddr, (u_long)a_out->a_text + (u_long)a_out->a_data); 18914331Speter#endif 1909313Ssos /* 19114114Speter * allow read/write of data 1929313Ssos */ 19314114Speter error = vm_map_protect(&vmspace->vm_map, 19414114Speter vmaddr + a_out->a_text, 19514114Speter vmaddr + a_out->a_text + a_out->a_data, 19614114Speter VM_PROT_ALL, 19714114Speter FALSE); 1989313Ssos if (error) 199101771Sjeff goto fail; 200111798Sdes 2019313Ssos /* 20214114Speter * Allocate anon demand-zeroed area for uninitialized data 2039313Ssos */ 2049313Ssos if (bss_size != 0) { 2059313Ssos vmaddr = virtual_offset + a_out->a_text + a_out->a_data; 206111798Sdes error = vm_map_find(&vmspace->vm_map, NULL, 0, &vmaddr, 207255426Sjhb bss_size, 0, VMFS_NO_SPACE, VM_PROT_ALL, VM_PROT_ALL, 0); 2089313Ssos if (error) 209101771Sjeff goto fail; 21014331Speter#ifdef DEBUG 21137950Sbde printf("imgact: bssaddr=%08lx, length=%08lx\n", 21237950Sbde (u_long)vmaddr, bss_size); 21314331Speter#endif 21414331Speter 2159313Ssos } 2169313Ssos } 2179313Ssos /* Fill in process VM information */ 2189313Ssos vmspace->vm_tsize = round_page(a_out->a_text) >> PAGE_SHIFT; 2199313Ssos vmspace->vm_dsize = round_page(a_out->a_data + bss_size) >> PAGE_SHIFT; 220119842Sbde vmspace->vm_taddr = (caddr_t)(void *)(uintptr_t)virtual_offset; 221119842Sbde vmspace->vm_daddr = (caddr_t)(void *)(uintptr_t) 222119842Sbde (virtual_offset + a_out->a_text); 2239313Ssos 2249313Ssos /* Fill in image_params */ 22512130Sdg imgp->interpreted = 0; 22612130Sdg imgp->entry_addr = a_out->a_entry; 227111798Sdes 22812130Sdg imgp->proc->p_sysent = &linux_sysvec; 229101771Sjeff 230101771Sjefffail: 231175202Sattilio vn_lock(imgp->vp, LK_EXCLUSIVE | LK_RETRY); 232101771Sjeff return (error); 2339313Ssos} 2349313Ssos 2359313Ssos/* 2369313Ssos * Tell kern_execve.c about it, with a little help from the linker. 2379313Ssos */ 23846803Speterstatic struct execsw linux_execsw = { exec_linux_imgact, "linux a.out" }; 23940435SpeterEXEC_SET(linuxaout, linux_execsw); 240