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