Home | History | Annotate | Line # | Download | only in common
linux_exec_aout.c revision 1.44.2.2
      1 /*	$NetBSD: linux_exec_aout.c,v 1.44.2.2 2001/11/14 19:13:09 nathanw Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 1995, 1998 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Christos Zoulas, Frank van der Linden and Eric Haszlakiewicz.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  * 3. All advertising materials mentioning features or use of this software
     19  *    must display the following acknowledgement:
     20  *	This product includes software developed by the NetBSD
     21  *	Foundation, Inc. and its contributors.
     22  * 4. Neither the name of The NetBSD Foundation nor the names of its
     23  *    contributors may be used to endorse or promote products derived
     24  *    from this software without specific prior written permission.
     25  *
     26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     36  * POSSIBILITY OF SUCH DAMAGE.
     37  */
     38 
     39 /*
     40  * based on exec_aout.c, sunos_exec.c and svr4_exec.c
     41  */
     42 
     43 #include <sys/cdefs.h>
     44 __KERNEL_RCSID(0, "$NetBSD: linux_exec_aout.c,v 1.44.2.2 2001/11/14 19:13:09 nathanw Exp $");
     45 
     46 #include <sys/param.h>
     47 #include <sys/systm.h>
     48 #include <sys/kernel.h>
     49 #include <sys/proc.h>
     50 #include <sys/malloc.h>
     51 #include <sys/namei.h>
     52 #include <sys/vnode.h>
     53 #include <sys/mount.h>
     54 #include <sys/exec.h>
     55 #include <sys/exec_elf.h>
     56 
     57 #include <sys/mman.h>
     58 #include <sys/syscallargs.h>
     59 
     60 #include <machine/cpu.h>
     61 #include <machine/reg.h>
     62 
     63 #include <compat/linux/common/linux_types.h>
     64 #include <compat/linux/common/linux_signal.h>
     65 #include <compat/linux/common/linux_util.h>
     66 #include <compat/linux/common/linux_exec.h>
     67 #include <compat/linux/common/linux_machdep.h>
     68 
     69 #include <compat/linux/linux_syscallargs.h>
     70 #include <compat/linux/linux_syscall.h>
     71 
     72 int linux_aout_copyargs __P((struct exec_package *, struct ps_strings *,
     73     char **, void *));
     74 
     75 static int exec_linux_aout_prep_zmagic __P((struct proc *,
     76     struct exec_package *));
     77 static int exec_linux_aout_prep_nmagic __P((struct proc *,
     78     struct exec_package *));
     79 static int exec_linux_aout_prep_omagic __P((struct proc *,
     80     struct exec_package *));
     81 static int exec_linux_aout_prep_qmagic __P((struct proc *,
     82     struct exec_package *));
     83 
     84 int
     85 linux_aout_copyargs(pack, arginfo, stackp, argp)
     86 	struct exec_package *pack;
     87 	struct ps_strings *arginfo;
     88 	char **stackp;
     89 	void *argp;
     90 {
     91 	char **cpp = (char **)*stackp;
     92 	char **stk = (char **)*stackp;
     93 	char *dp, *sp;
     94 	size_t len;
     95 	void *nullp = NULL;
     96 	int argc = arginfo->ps_nargvstr;
     97 	int envc = arginfo->ps_nenvstr;
     98 	int error;
     99 
    100 	if ((error = copyout(&argc, cpp++, sizeof(argc))) != 0)
    101 		return error;
    102 
    103 	/* leave room for envp and argv */
    104 	cpp += 2;
    105 	if ((error = copyout(&cpp, &stk[1], sizeof (cpp))) != 0)
    106 		return error;
    107 
    108 	dp = (char *) (cpp + argc + envc + 2);
    109 	sp = argp;
    110 
    111 	/* XXX don't copy them out, remap them! */
    112 	arginfo->ps_argvstr = cpp; /* remember location of argv for later */
    113 
    114 	for (; --argc >= 0; sp += len, dp += len)
    115 		if ((error = copyout(&dp, cpp++, sizeof(dp))) != 0 ||
    116 		    (error = copyoutstr(sp, dp, ARG_MAX, &len)) != 0)
    117 			return error;
    118 
    119 	if ((error = copyout(&nullp, cpp++, sizeof(nullp))) != 0)
    120 		return error;
    121 
    122 	if ((error = copyout(&cpp, &stk[2], sizeof (cpp))) != 0)
    123 		return error;
    124 
    125 	arginfo->ps_envstr = cpp; /* remember location of envp for later */
    126 
    127 	for (; --envc >= 0; sp += len, dp += len)
    128 		if ((error = copyout(&dp, cpp++, sizeof(dp))) != 0 ||
    129 		    (error = copyoutstr(sp, dp, ARG_MAX, &len)) != 0)
    130 			return error;
    131 
    132 	if ((error = copyout(&nullp, cpp++, sizeof(nullp))) != 0)
    133 		return error;
    134 
    135 	*stackp = (char *)cpp;
    136 	return 0;
    137 }
    138 
    139 int
    140 exec_linux_aout_makecmds(p, epp)
    141 	struct proc *p;
    142 	struct exec_package *epp;
    143 {
    144 	struct exec *linux_ep = epp->ep_hdr;
    145 	int machtype, magic;
    146 	int error = ENOEXEC;
    147 
    148 	magic = LINUX_N_MAGIC(linux_ep);
    149 	machtype = LINUX_N_MACHTYPE(linux_ep);
    150 
    151 
    152 	if (machtype != LINUX_MID_MACHINE)
    153 		return (ENOEXEC);
    154 
    155 	switch (magic) {
    156 	case QMAGIC:
    157 		error = exec_linux_aout_prep_qmagic(p, epp);
    158 		break;
    159 	case ZMAGIC:
    160 		error = exec_linux_aout_prep_zmagic(p, epp);
    161 		break;
    162 	case NMAGIC:
    163 		error = exec_linux_aout_prep_nmagic(p, epp);
    164 		break;
    165 	case OMAGIC:
    166 		error = exec_linux_aout_prep_omagic(p, epp);
    167 		break;
    168 	}
    169 	return error;
    170 }
    171 
    172 /*
    173  * Since text starts at 0x400 in Linux ZMAGIC executables, and 0x400
    174  * is very likely not page aligned on most architectures, it is treated
    175  * as an NMAGIC here. XXX
    176  */
    177 
    178 static int
    179 exec_linux_aout_prep_zmagic(p, epp)
    180 	struct proc *p;
    181 	struct exec_package *epp;
    182 {
    183 	struct exec *execp = epp->ep_hdr;
    184 
    185 	epp->ep_taddr = LINUX_N_TXTADDR(*execp, ZMAGIC);
    186 	epp->ep_tsize = execp->a_text;
    187 	epp->ep_daddr = LINUX_N_DATADDR(*execp, ZMAGIC);
    188 	epp->ep_dsize = execp->a_data + execp->a_bss;
    189 	epp->ep_entry = execp->a_entry;
    190 
    191 	/* set up command for text segment */
    192 	NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_readvn, execp->a_text,
    193 	    epp->ep_taddr, epp->ep_vp, LINUX_N_TXTOFF(*execp, ZMAGIC),
    194 	    VM_PROT_READ|VM_PROT_EXECUTE);
    195 
    196 	/* set up command for data segment */
    197 	NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_readvn, execp->a_data,
    198 	    epp->ep_daddr, epp->ep_vp, LINUX_N_DATOFF(*execp, ZMAGIC),
    199 	    VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE);
    200 
    201 	/* set up command for bss segment */
    202 	NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, execp->a_bss,
    203 	    epp->ep_daddr + execp->a_data, NULLVP, 0,
    204 	    VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE);
    205 
    206 	return exec_aout_setup_stack(p, epp);
    207 }
    208 
    209 /*
    210  * exec_aout_prep_nmagic(): Prepare Linux NMAGIC package.
    211  * Not different from the normal stuff.
    212  */
    213 
    214 static int
    215 exec_linux_aout_prep_nmagic(p, epp)
    216 	struct proc *p;
    217 	struct exec_package *epp;
    218 {
    219 	struct exec *execp = epp->ep_hdr;
    220 	long bsize, baddr;
    221 
    222 	epp->ep_taddr = LINUX_N_TXTADDR(*execp, NMAGIC);
    223 	epp->ep_tsize = execp->a_text;
    224 	epp->ep_daddr = LINUX_N_DATADDR(*execp, NMAGIC);
    225 	epp->ep_dsize = execp->a_data + execp->a_bss;
    226 	epp->ep_entry = execp->a_entry;
    227 
    228 	/* set up command for text segment */
    229 	NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_readvn, execp->a_text,
    230 	    epp->ep_taddr, epp->ep_vp, LINUX_N_TXTOFF(*execp, NMAGIC),
    231 	    VM_PROT_READ|VM_PROT_EXECUTE);
    232 
    233 	/* set up command for data segment */
    234 	NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_readvn, execp->a_data,
    235 	    epp->ep_daddr, epp->ep_vp, LINUX_N_DATOFF(*execp, NMAGIC),
    236 	    VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE);
    237 
    238 	/* set up command for bss segment */
    239 	baddr = roundup(epp->ep_daddr + execp->a_data, NBPG);
    240 	bsize = epp->ep_daddr + epp->ep_dsize - baddr;
    241 	if (bsize > 0)
    242 		NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, bsize, baddr,
    243 		    NULLVP, 0, VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE);
    244 
    245 	return exec_aout_setup_stack(p, epp);
    246 }
    247 
    248 /*
    249  * exec_aout_prep_omagic(): Prepare Linux OMAGIC package.
    250  * Business as usual.
    251  */
    252 
    253 static int
    254 exec_linux_aout_prep_omagic(p, epp)
    255 	struct proc *p;
    256 	struct exec_package *epp;
    257 {
    258 	struct exec *execp = epp->ep_hdr;
    259 	long dsize, bsize, baddr;
    260 
    261 	epp->ep_taddr = LINUX_N_TXTADDR(*execp, OMAGIC);
    262 	epp->ep_tsize = execp->a_text;
    263 	epp->ep_daddr = LINUX_N_DATADDR(*execp, OMAGIC);
    264 	epp->ep_dsize = execp->a_data + execp->a_bss;
    265 	epp->ep_entry = execp->a_entry;
    266 
    267 	/* set up command for text and data segments */
    268 	NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_readvn,
    269 	    execp->a_text + execp->a_data, epp->ep_taddr, epp->ep_vp,
    270 	    LINUX_N_TXTOFF(*execp, OMAGIC), VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE);
    271 
    272 	/* set up command for bss segment */
    273 	baddr = roundup(epp->ep_daddr + execp->a_data, NBPG);
    274 	bsize = epp->ep_daddr + epp->ep_dsize - baddr;
    275 	if (bsize > 0)
    276 		NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, bsize, baddr,
    277 		    NULLVP, 0, VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE);
    278 
    279 	/*
    280 	 * Make sure (# of pages) mapped above equals (vm_tsize + vm_dsize);
    281 	 * obreak(2) relies on this fact. Both `vm_tsize' and `vm_dsize' are
    282 	 * computed (in execve(2)) by rounding *up* `ep_tsize' and `ep_dsize'
    283 	 * respectively to page boundaries.
    284 	 * Compensate `ep_dsize' for the amount of data covered by the last
    285 	 * text page.
    286 	 */
    287 	dsize = epp->ep_dsize + execp->a_text - roundup(execp->a_text, NBPG);
    288 	epp->ep_dsize = (dsize > 0) ? dsize : 0;
    289 	return exec_aout_setup_stack(p, epp);
    290 }
    291 
    292 static int
    293 exec_linux_aout_prep_qmagic(p, epp)
    294 	struct proc *p;
    295 	struct exec_package *epp;
    296 {
    297 	struct exec *execp = epp->ep_hdr;
    298 
    299 	epp->ep_taddr = LINUX_N_TXTADDR(*execp, QMAGIC);
    300 	epp->ep_tsize = execp->a_text;
    301 	epp->ep_daddr = LINUX_N_DATADDR(*execp, QMAGIC);
    302 	epp->ep_dsize = execp->a_data + execp->a_bss;
    303 	epp->ep_entry = execp->a_entry;
    304 
    305 	/*
    306 	 * check if vnode is in open for writing, because we want to
    307 	 * demand-page out of it.  if it is, don't do it, for various
    308 	 * reasons
    309 	 */
    310 	if ((execp->a_text != 0 || execp->a_data != 0) &&
    311 	    epp->ep_vp->v_writecount != 0) {
    312 #ifdef DIAGNOSTIC
    313 		if (epp->ep_vp->v_flag & VTEXT)
    314 			panic("exec: a VTEXT vnode has writecount != 0\n");
    315 #endif
    316 		return ETXTBSY;
    317 	}
    318 	epp->ep_vp->v_flag |= VTEXT;
    319 
    320 	/* set up command for text segment */
    321 	NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_pagedvn, execp->a_text,
    322 	    epp->ep_taddr, epp->ep_vp, LINUX_N_TXTOFF(*execp, QMAGIC),
    323 	    VM_PROT_READ|VM_PROT_EXECUTE);
    324 
    325 	/* set up command for data segment */
    326 	NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_pagedvn, execp->a_data,
    327 	    epp->ep_daddr, epp->ep_vp, LINUX_N_DATOFF(*execp, QMAGIC),
    328 	    VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE);
    329 
    330 	/* set up command for bss segment */
    331 	NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, execp->a_bss,
    332 	    epp->ep_daddr + execp->a_data, NULLVP, 0,
    333 	    VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE);
    334 
    335 	return exec_aout_setup_stack(p, epp);
    336 }
    337