1 /* $NetBSD: linux_exec_aout.c,v 1.66 2009/08/15 23:39:35 matt 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 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /* 33 * based on exec_aout.c, sunos_exec.c and svr4_exec.c 34 */ 35 36 #include <sys/cdefs.h> 37 __KERNEL_RCSID(0, "$NetBSD: linux_exec_aout.c,v 1.66 2009/08/15 23:39:35 matt Exp $"); 38 39 #ifdef _KERNEL_OPT 40 #include "opt_execfmt.h" 41 #endif 42 43 #include <sys/param.h> 44 #include <sys/systm.h> 45 #include <sys/kernel.h> 46 #include <sys/proc.h> 47 #include <sys/malloc.h> 48 #include <sys/namei.h> 49 #include <sys/vnode.h> 50 #include <sys/mount.h> 51 #include <sys/exec.h> 52 53 #include <sys/mman.h> 54 #include <sys/syscallargs.h> 55 56 #include <sys/cpu.h> 57 #include <machine/reg.h> 58 59 #include <compat/linux/common/linux_types.h> 60 #include <compat/linux/common/linux_signal.h> 61 #include <compat/linux/common/linux_util.h> 62 #include <compat/linux/common/linux_exec.h> 63 #include <compat/linux/common/linux_machdep.h> 64 65 #include <compat/linux/linux_syscallargs.h> 66 #include <compat/linux/linux_syscall.h> 67 68 int linux_aout_copyargs(struct lwp *, struct exec_package *, 69 struct ps_strings *, char **, void *); 70 71 static int exec_linux_aout_prep_zmagic(struct lwp *, 72 struct exec_package *); 73 static int exec_linux_aout_prep_nmagic(struct lwp *, 74 struct exec_package *); 75 static int exec_linux_aout_prep_omagic(struct lwp *, 76 struct exec_package *); 77 static int exec_linux_aout_prep_qmagic(struct lwp *, 78 struct exec_package *); 79 80 int 81 linux_aout_copyargs(struct lwp *l, struct exec_package *pack, 82 struct ps_strings *arginfo, char **stackp, void *argp) 83 { 84 char **cpp = (char **)*stackp; 85 char **stk = (char **)*stackp; 86 char *dp, *sp; 87 size_t len; 88 void *nullp = NULL; 89 int argc = arginfo->ps_nargvstr; 90 int envc = arginfo->ps_nenvstr; 91 int error; 92 93 if ((error = copyout(&argc, cpp++, sizeof(argc))) != 0) 94 return error; 95 96 /* leave room for envp and argv */ 97 cpp += 2; 98 if ((error = copyout(&cpp, &stk[1], sizeof (cpp))) != 0) 99 return error; 100 101 dp = (char *) (cpp + argc + envc + 2); 102 sp = argp; 103 104 /* XXX don't copy them out, remap them! */ 105 arginfo->ps_argvstr = cpp; /* remember location of argv for later */ 106 107 for (; --argc >= 0; sp += len, dp += len) 108 if ((error = copyout(&dp, cpp++, sizeof(dp))) != 0 || 109 (error = copyoutstr(sp, dp, ARG_MAX, &len)) != 0) 110 return error; 111 112 if ((error = copyout(&nullp, cpp++, sizeof(nullp))) != 0) 113 return error; 114 115 if ((error = copyout(&cpp, &stk[2], sizeof (cpp))) != 0) 116 return error; 117 118 arginfo->ps_envstr = cpp; /* remember location of envp for later */ 119 120 for (; --envc >= 0; sp += len, dp += len) 121 if ((error = copyout(&dp, cpp++, sizeof(dp))) != 0 || 122 (error = copyoutstr(sp, dp, ARG_MAX, &len)) != 0) 123 return error; 124 125 if ((error = copyout(&nullp, cpp++, sizeof(nullp))) != 0) 126 return error; 127 128 *stackp = (char *)cpp; 129 return 0; 130 } 131 132 int 133 exec_linux_aout_makecmds(struct lwp *l, struct exec_package *epp) 134 { 135 struct exec *linux_ep = epp->ep_hdr; 136 int machtype, magic; 137 int error = ENOEXEC; 138 139 magic = LINUX_N_MAGIC(linux_ep); 140 machtype = LINUX_N_MACHTYPE(linux_ep); 141 142 143 if (machtype != LINUX_MID_MACHINE) 144 return (ENOEXEC); 145 146 switch (magic) { 147 case QMAGIC: 148 error = exec_linux_aout_prep_qmagic(l, epp); 149 break; 150 case ZMAGIC: 151 error = exec_linux_aout_prep_zmagic(l, epp); 152 break; 153 case NMAGIC: 154 error = exec_linux_aout_prep_nmagic(l, epp); 155 break; 156 case OMAGIC: 157 error = exec_linux_aout_prep_omagic(l, epp); 158 break; 159 } 160 return error; 161 } 162 163 /* 164 * Since text starts at 0x400 in Linux ZMAGIC executables, and 0x400 165 * is very likely not page aligned on most architectures, it is treated 166 * as an NMAGIC here. XXX 167 */ 168 169 static int 170 exec_linux_aout_prep_zmagic(struct lwp *l, struct exec_package *epp) 171 { 172 struct exec *execp = epp->ep_hdr; 173 174 epp->ep_taddr = LINUX_N_TXTADDR(*execp, ZMAGIC); 175 epp->ep_tsize = execp->a_text; 176 epp->ep_daddr = LINUX_N_DATADDR(*execp, ZMAGIC); 177 epp->ep_dsize = execp->a_data + execp->a_bss; 178 epp->ep_entry = execp->a_entry; 179 180 /* set up command for text segment */ 181 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_readvn, execp->a_text, 182 epp->ep_taddr, epp->ep_vp, LINUX_N_TXTOFF(*execp, ZMAGIC), 183 VM_PROT_READ|VM_PROT_EXECUTE); 184 185 /* set up command for data segment */ 186 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_readvn, execp->a_data, 187 epp->ep_daddr, epp->ep_vp, LINUX_N_DATOFF(*execp, ZMAGIC), 188 VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); 189 190 /* set up command for bss segment */ 191 if (execp->a_bss) 192 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, execp->a_bss, 193 epp->ep_daddr + execp->a_data, NULLVP, 0, 194 VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); 195 196 return (*epp->ep_esch->es_setup_stack)(l, epp); 197 } 198 199 /* 200 * exec_aout_prep_nmagic(): Prepare Linux NMAGIC package. 201 * Not different from the normal stuff. 202 */ 203 204 static int 205 exec_linux_aout_prep_nmagic(struct lwp *l, struct exec_package *epp) 206 { 207 struct exec *execp = epp->ep_hdr; 208 long bsize, baddr; 209 210 epp->ep_taddr = LINUX_N_TXTADDR(*execp, NMAGIC); 211 epp->ep_tsize = execp->a_text; 212 epp->ep_daddr = LINUX_N_DATADDR(*execp, NMAGIC); 213 epp->ep_dsize = execp->a_data + execp->a_bss; 214 epp->ep_entry = execp->a_entry; 215 216 /* set up command for text segment */ 217 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_readvn, execp->a_text, 218 epp->ep_taddr, epp->ep_vp, LINUX_N_TXTOFF(*execp, NMAGIC), 219 VM_PROT_READ|VM_PROT_EXECUTE); 220 221 /* set up command for data segment */ 222 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_readvn, execp->a_data, 223 epp->ep_daddr, epp->ep_vp, LINUX_N_DATOFF(*execp, NMAGIC), 224 VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); 225 226 /* set up command for bss segment */ 227 baddr = roundup(epp->ep_daddr + execp->a_data, PAGE_SIZE); 228 bsize = epp->ep_daddr + epp->ep_dsize - baddr; 229 if (bsize > 0) 230 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, bsize, baddr, 231 NULLVP, 0, VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); 232 233 return (*epp->ep_esch->es_setup_stack)(l, epp); 234 } 235 236 /* 237 * exec_aout_prep_omagic(): Prepare Linux OMAGIC package. 238 * Business as usual. 239 */ 240 241 static int 242 exec_linux_aout_prep_omagic(struct lwp *l, struct exec_package *epp) 243 { 244 struct exec *execp = epp->ep_hdr; 245 long dsize, bsize, baddr; 246 247 epp->ep_taddr = LINUX_N_TXTADDR(*execp, OMAGIC); 248 epp->ep_tsize = execp->a_text; 249 epp->ep_daddr = LINUX_N_DATADDR(*execp, OMAGIC); 250 epp->ep_dsize = execp->a_data + execp->a_bss; 251 epp->ep_entry = execp->a_entry; 252 253 /* set up command for text and data segments */ 254 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_readvn, 255 execp->a_text + execp->a_data, epp->ep_taddr, epp->ep_vp, 256 LINUX_N_TXTOFF(*execp, OMAGIC), VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); 257 258 /* set up command for bss segment */ 259 baddr = roundup(epp->ep_daddr + execp->a_data, PAGE_SIZE); 260 bsize = epp->ep_daddr + epp->ep_dsize - baddr; 261 if (bsize > 0) 262 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, bsize, baddr, 263 NULLVP, 0, VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); 264 265 /* 266 * Make sure (# of pages) mapped above equals (vm_tsize + vm_dsize); 267 * obreak(2) relies on this fact. Both `vm_tsize' and `vm_dsize' are 268 * computed (in execve(2)) by rounding *up* `ep_tsize' and `ep_dsize' 269 * respectively to page boundaries. 270 * Compensate `ep_dsize' for the amount of data covered by the last 271 * text page. 272 */ 273 dsize = epp->ep_dsize + execp->a_text - roundup(execp->a_text, 274 PAGE_SIZE); 275 epp->ep_dsize = (dsize > 0) ? dsize : 0; 276 return (*epp->ep_esch->es_setup_stack)(l, epp); 277 } 278 279 static int 280 exec_linux_aout_prep_qmagic(struct lwp *l, struct exec_package *epp) 281 { 282 struct exec *execp = epp->ep_hdr; 283 int error; 284 285 epp->ep_taddr = LINUX_N_TXTADDR(*execp, QMAGIC); 286 epp->ep_tsize = execp->a_text; 287 epp->ep_daddr = LINUX_N_DATADDR(*execp, QMAGIC); 288 epp->ep_dsize = execp->a_data + execp->a_bss; 289 epp->ep_entry = execp->a_entry; 290 291 error = vn_marktext(epp->ep_vp); 292 if (error) 293 return (error); 294 295 /* set up command for text segment */ 296 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_pagedvn, execp->a_text, 297 epp->ep_taddr, epp->ep_vp, LINUX_N_TXTOFF(*execp, QMAGIC), 298 VM_PROT_READ|VM_PROT_EXECUTE); 299 300 /* set up command for data segment */ 301 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_pagedvn, execp->a_data, 302 epp->ep_daddr, epp->ep_vp, LINUX_N_DATOFF(*execp, QMAGIC), 303 VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); 304 305 /* set up command for bss segment */ 306 if (execp->a_bss) 307 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, execp->a_bss, 308 epp->ep_daddr + execp->a_data, NULLVP, 0, 309 VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); 310 311 return (*epp->ep_esch->es_setup_stack)(l, epp); 312 } 313