1/* $NetBSD: netbsd32_exec_aout.c,v 1.31 2021/01/19 03:20:13 simonb Exp $ */ 2/* from: NetBSD: exec_aout.c,v 1.15 1996/09/26 23:34:46 cgd Exp */ 3 4/* 5 * Copyright (c) 1998, 2001 Matthew R. Green. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29/* 30 * Copyright (c) 1993, 1994 Christopher G. Demetriou 31 * All rights reserved. 32 * 33 * Redistribution and use in source and binary forms, with or without 34 * modification, are permitted provided that the following conditions 35 * are met: 36 * 1. Redistributions of source code must retain the above copyright 37 * notice, this list of conditions and the following disclaimer. 38 * 2. Redistributions in binary form must reproduce the above copyright 39 * notice, this list of conditions and the following disclaimer in the 40 * documentation and/or other materials provided with the distribution. 41 * 3. All advertising materials mentioning features or use of this software 42 * must display the following acknowledgement: 43 * This product includes software developed by Christopher G. Demetriou. 44 * 4. The name of the author may not be used to endorse or promote products 45 * derived from this software without specific prior written permission 46 * 47 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 48 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 49 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 50 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 51 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 52 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 53 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 54 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 55 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 56 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 57 */ 58 59#include <sys/cdefs.h> 60__KERNEL_RCSID(0, "$NetBSD: netbsd32_exec_aout.c,v 1.31 2021/01/19 03:20:13 simonb Exp $"); 61 62#include <sys/param.h> 63#include <sys/systm.h> 64#include <sys/proc.h> 65#include <sys/vnode.h> 66#include <sys/exec.h> 67#include <sys/exec_aout.h> 68#include <sys/resourcevar.h> 69#include <sys/signal.h> 70#include <sys/signalvar.h> 71 72#include <compat/netbsd32/netbsd32.h> 73#ifndef EXEC_AOUT 74#define EXEC_AOUT 75#endif 76#include <compat/netbsd32/netbsd32_exec.h> 77 78#include <machine/frame.h> 79#include <machine/netbsd32_machdep.h> 80 81#ifdef COMPAT_NOMID 82static int netbsd32_exec_aout_nomid(struct lwp *, struct exec_package *); 83#endif 84 85/* 86 * exec_netbsd32_makecmds(): Check if it's an netbsd32 a.out format 87 * executable. 88 * 89 * Given a lwp pointer and an exec package pointer, see if the referent 90 * of the epp is in netbsd32 a.out format. Check 'standard' magic 91 * numbers for this architecture. 92 * 93 * This function, in the former case, or the hook, in the latter, is 94 * responsible for creating a set of vmcmds which can be used to build 95 * the process's vm space and inserting them into the exec package. 96 */ 97 98int 99exec_netbsd32_makecmds(struct lwp *l, struct exec_package *epp) 100{ 101 netbsd32_u_long midmag, magic; 102 u_short mid; 103 int error; 104 struct netbsd32_exec *execp = epp->ep_hdr; 105 106 if (epp->ep_hdrvalid < sizeof(struct netbsd32_exec)) 107 return ENOEXEC; 108 109 midmag = (netbsd32_u_long)ntohl(execp->a_midmag); 110 mid = (midmag >> 16) & 0x3ff; 111 magic = midmag & 0xffff; 112 113 midmag = mid << 16 | magic; 114 115 /* this is already needed by setup_stack() */ 116 epp->ep_flags |= EXEC_32; 117 118 switch (midmag) { 119 case (NETBSD32_MID_MACHINE << 16) | ZMAGIC: 120 error = netbsd32_exec_aout_prep_zmagic(l, epp); 121 break; 122 case (NETBSD32_MID_MACHINE << 16) | NMAGIC: 123 error = netbsd32_exec_aout_prep_nmagic(l, epp); 124 break; 125 case (NETBSD32_MID_MACHINE << 16) | OMAGIC: 126 error = netbsd32_exec_aout_prep_omagic(l, epp); 127 break; 128 default: 129#ifdef COMPAT_NOMID 130 error = netbsd32_exec_aout_nomid(l, epp); 131#else 132 error = ENOEXEC; 133#endif 134 break; 135 } 136 137 if (error) { 138 kill_vmcmds(&epp->ep_vmcmds); 139 epp->ep_flags &= ~EXEC_32; 140 } else 141 epp->ep_flags &= ~EXEC_TOPDOWN_VM; 142 return error; 143} 144 145/* 146 * netbsd32_exec_aout_prep_zmagic(): Prepare a 'native' ZMAGIC binary's 147 * exec package 148 * 149 * First, set of the various offsets/lengths in the exec package. 150 * 151 * Then, mark the text image busy (so it can be demand paged) or error 152 * out if this is not possible. Finally, set up vmcmds for the 153 * text, data, bss, and stack segments. 154 */ 155 156int 157netbsd32_exec_aout_prep_zmagic(struct lwp *l, struct exec_package *epp) 158{ 159 struct netbsd32_exec *execp = epp->ep_hdr; 160 int error; 161 162 epp->ep_taddr = AOUT_LDPGSZ; 163 epp->ep_tsize = execp->a_text; 164 epp->ep_daddr = epp->ep_taddr + execp->a_text; 165 epp->ep_dsize = execp->a_data + execp->a_bss; 166 epp->ep_entry = execp->a_entry; 167 epp->ep_vm_minaddr = exec_vm_minaddr(VM_MIN_ADDRESS); 168 epp->ep_vm_maxaddr = VM_MAXUSER_ADDRESS32; 169 170 error = vn_marktext(epp->ep_vp); 171 if (error) 172 return error; 173 174 /* set up command for text segment */ 175 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_pagedvn, execp->a_text, 176 epp->ep_taddr, epp->ep_vp, 0, VM_PROT_READ|VM_PROT_EXECUTE); 177 178 /* set up command for data segment */ 179 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_pagedvn, execp->a_data, 180 epp->ep_daddr, epp->ep_vp, execp->a_text, 181 VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); 182 183 /* set up command for bss segment */ 184 if (execp->a_bss > 0) 185 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, execp->a_bss, 186 epp->ep_daddr + execp->a_data, NULLVP, 0, 187 VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); 188 189 return (*epp->ep_esch->es_setup_stack)(l, epp); 190} 191 192/* 193 * netbsd32_exec_aout_prep_nmagic(): Prepare a 'native' NMAGIC binary's 194 * exec package 195 */ 196 197int 198netbsd32_exec_aout_prep_nmagic(struct lwp *l, struct exec_package *epp) 199{ 200 struct netbsd32_exec *execp = epp->ep_hdr; 201 long bsize, baddr; 202 203 epp->ep_taddr = AOUT_LDPGSZ; 204 epp->ep_tsize = execp->a_text; 205 epp->ep_daddr = roundup(epp->ep_taddr + execp->a_text, AOUT_LDPGSZ); 206 epp->ep_dsize = execp->a_data + execp->a_bss; 207 epp->ep_entry = execp->a_entry; 208 epp->ep_vm_minaddr = exec_vm_minaddr(VM_MIN_ADDRESS); 209 epp->ep_vm_maxaddr = VM_MAXUSER_ADDRESS32; 210 211 /* set up command for text segment */ 212 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_readvn, execp->a_text, 213 epp->ep_taddr, epp->ep_vp, sizeof(struct netbsd32_exec), 214 VM_PROT_READ|VM_PROT_EXECUTE); 215 216 /* set up command for data segment */ 217 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_readvn, execp->a_data, 218 epp->ep_daddr, epp->ep_vp, execp->a_text + sizeof(struct netbsd32_exec), 219 VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); 220 221 /* set up command for bss segment */ 222 baddr = roundup(epp->ep_daddr + execp->a_data, PAGE_SIZE); 223 bsize = epp->ep_daddr + epp->ep_dsize - baddr; 224 if (bsize > 0) 225 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, bsize, baddr, 226 NULLVP, 0, VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); 227 228 return (*epp->ep_esch->es_setup_stack)(l, epp); 229} 230 231/* 232 * netbsd32_exec_aout_prep_omagic(): Prepare a 'native' OMAGIC binary's 233 * exec package 234 */ 235 236int 237netbsd32_exec_aout_prep_omagic(struct lwp *l, struct exec_package *epp) 238{ 239 struct netbsd32_exec *execp = epp->ep_hdr; 240 long dsize, bsize, baddr; 241 242 epp->ep_taddr = AOUT_LDPGSZ; 243 epp->ep_tsize = execp->a_text; 244 epp->ep_daddr = epp->ep_taddr + execp->a_text; 245 epp->ep_dsize = execp->a_data + execp->a_bss; 246 epp->ep_entry = execp->a_entry; 247 epp->ep_vm_minaddr = exec_vm_minaddr(VM_MIN_ADDRESS); 248 epp->ep_vm_maxaddr = VM_MAXUSER_ADDRESS32; 249 250 /* set up command for text and data segments */ 251 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_readvn, 252 execp->a_text + execp->a_data, epp->ep_taddr, epp->ep_vp, 253 sizeof(struct netbsd32_exec), VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); 254 255 /* set up command for bss segment */ 256 baddr = roundup(epp->ep_daddr + execp->a_data, PAGE_SIZE); 257 bsize = epp->ep_daddr + epp->ep_dsize - baddr; 258 if (bsize > 0) 259 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, bsize, baddr, 260 NULLVP, 0, VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); 261 262 /* 263 * Make sure (# of pages) mapped above equals (vm_tsize + vm_dsize); 264 * obreak(2) relies on this fact. Both `vm_tsize' and `vm_dsize' are 265 * computed (in execve(2)) by rounding *up* `ep_tsize' and `ep_dsize' 266 * respectively to page boundaries. 267 * Compensate `ep_dsize' for the amount of data covered by the last 268 * text page. 269 */ 270 dsize = epp->ep_dsize + execp->a_text - roundup(execp->a_text, 271 PAGE_SIZE); 272 epp->ep_dsize = (dsize > 0) ? dsize : 0; 273 return (*epp->ep_esch->es_setup_stack)(l, epp); 274} 275 276#ifdef COMPAT_NOMID 277/* 278 * netbsd32_exec_aout_prep_oldzmagic(): 279 * Prepare the vmcmds to build a vmspace for an old ZMAGIC 280 * binary. [386BSD/BSDI/4.4BSD/NetBSD0.8] 281 * 282 * Cloned from exec_aout_prep_zmagic() in kern/exec_aout.c; a more verbose 283 * description of operation is there. 284 * There were copies of this in the mac68k, hp300, and i386 ports. 285 */ 286static int 287netbsd32_exec_aout_prep_oldzmagic(struct lwp *l, struct exec_package *epp) 288{ 289 struct netbsd32_exec *execp = epp->ep_hdr; 290 int error; 291 292 epp->ep_taddr = 0; 293 epp->ep_tsize = execp->a_text; 294 epp->ep_daddr = epp->ep_taddr + execp->a_text; 295 epp->ep_dsize = execp->a_data + execp->a_bss; 296 epp->ep_entry = execp->a_entry; 297 epp->ep_vm_minaddr = exec_vm_minaddr(VM_MIN_ADDRESS); 298 epp->ep_vm_maxaddr = VM_MAXUSER_ADDRESS32; 299 300 error = vn_marktext(epp->ep_vp); 301 if (error) 302 return error; 303 304 /* set up command for text segment */ 305 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_pagedvn, execp->a_text, 306 epp->ep_taddr, epp->ep_vp, PAGE_SIZE, /* XXX CLBYTES? */ 307 VM_PROT_READ|VM_PROT_EXECUTE); 308 309 /* set up command for data segment */ 310 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_pagedvn, execp->a_data, 311 epp->ep_daddr, epp->ep_vp, 312 execp->a_text + PAGE_SIZE, /* XXX CLBYTES? */ 313 VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); 314 315 /* set up command for bss segment */ 316 if (execp->a_bss) 317 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, execp->a_bss, 318 epp->ep_daddr + execp->a_data, NULLVP, 0, 319 VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); 320 321 return (*epp->ep_esch->es_setup_stack)(l, epp); 322} 323 324 325/* 326 * netbsd32_exec_aout_prep_oldnmagic(): 327 * Prepare the vmcmds to build a vmspace for an old NMAGIC 328 * binary. [BSDI] 329 * 330 * Cloned from exec_aout_prep_nmagic() in kern/exec_aout.c; with text starting 331 * at 0. 332 * XXX: There must be a better way to share this code. 333 */ 334static int 335netbsd32_exec_aout_prep_oldnmagic(struct lwp *l, struct exec_package *epp) 336{ 337 struct netbsd32_exec *execp = epp->ep_hdr; 338 long bsize, baddr; 339 340 epp->ep_taddr = 0; 341 epp->ep_tsize = execp->a_text; 342 epp->ep_daddr = roundup(epp->ep_taddr + execp->a_text, AOUT_LDPGSZ); 343 epp->ep_dsize = execp->a_data + execp->a_bss; 344 epp->ep_entry = execp->a_entry; 345 epp->ep_vm_minaddr = exec_vm_minaddr(VM_MIN_ADDRESS); 346 epp->ep_vm_maxaddr = VM_MAXUSER_ADDRESS32; 347 348 /* set up command for text segment */ 349 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_readvn, execp->a_text, 350 epp->ep_taddr, epp->ep_vp, sizeof(struct netbsd32_exec), 351 VM_PROT_READ|VM_PROT_EXECUTE); 352 353 /* set up command for data segment */ 354 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_readvn, execp->a_data, 355 epp->ep_daddr, epp->ep_vp, execp->a_text + sizeof(struct netbsd32_exec), 356 VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); 357 358 /* set up command for bss segment */ 359 baddr = roundup(epp->ep_daddr + execp->a_data, PAGE_SIZE); 360 bsize = epp->ep_daddr + epp->ep_dsize - baddr; 361 if (bsize > 0) 362 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, bsize, baddr, 363 NULLVP, 0, VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); 364 365 return (*epp->ep_esch->es_setup_stack)(l, epp); 366} 367 368 369/* 370 * netbsd32_exec_aout_prep_oldomagic(): 371 * Prepare the vmcmds to build a vmspace for an old OMAGIC 372 * binary. [BSDI] 373 * 374 * Cloned from exec_aout_prep_omagic() in kern/exec_aout.c; with text starting 375 * at 0. 376 * XXX: There must be a better way to share this code. 377 */ 378static int 379netbsd32_exec_aout_prep_oldomagic(struct lwp *l, struct exec_package *epp) 380{ 381 struct netbsd32_exec *execp = epp->ep_hdr; 382 long dsize, bsize, baddr; 383 384 epp->ep_taddr = 0; 385 epp->ep_tsize = execp->a_text; 386 epp->ep_daddr = epp->ep_taddr + execp->a_text; 387 epp->ep_dsize = execp->a_data + execp->a_bss; 388 epp->ep_entry = execp->a_entry; 389 390 /* set up command for text and data segments */ 391 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_readvn, 392 execp->a_text + execp->a_data, epp->ep_taddr, epp->ep_vp, 393 sizeof(struct netbsd32_exec), VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); 394 395 /* set up command for bss segment */ 396 baddr = roundup(epp->ep_daddr + execp->a_data, PAGE_SIZE); 397 bsize = epp->ep_daddr + epp->ep_dsize - baddr; 398 if (bsize > 0) 399 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, bsize, baddr, 400 NULLVP, 0, VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); 401 402 /* 403 * Make sure (# of pages) mapped above equals (vm_tsize + vm_dsize); 404 * obreak(2) relies on this fact. Both `vm_tsize' and `vm_dsize' are 405 * computed (in execve(2)) by rounding *up* `ep_tsize' and `ep_dsize' 406 * respectively to page boundaries. 407 * Compensate `ep_dsize' for the amount of data covered by the last 408 * text page. 409 */ 410 dsize = epp->ep_dsize + execp->a_text - roundup(execp->a_text, 411 PAGE_SIZE); 412 epp->ep_dsize = (dsize > 0) ? dsize : 0; 413 return (*epp->ep_esch->es_setup_stack)(l, epp); 414} 415 416static int 417netbsd32_exec_aout_nomid(struct lwp *l, struct exec_package *epp) 418{ 419 int error; 420 u_long midmag, magic; 421 u_short mid; 422 struct exec *execp = epp->ep_hdr; 423 424 /* check on validity of epp->ep_hdr performed by exec_out_makecmds */ 425 426 midmag = ntohl(execp->a_midmag); 427 mid = (midmag >> 16) & 0xffff; 428 magic = midmag & 0xffff; 429 430 if (magic == 0) { 431 magic = (execp->a_midmag & 0xffff); 432 mid = MID_ZERO; 433 } 434 435 midmag = mid << 16 | magic; 436 437 switch (midmag) { 438 case (MID_ZERO << 16) | ZMAGIC: 439 /* 440 * 386BSD's ZMAGIC format: 441 */ 442 return netbsd32_exec_aout_prep_oldzmagic(l, epp); 443 break; 444 445 case (MID_ZERO << 16) | QMAGIC: 446 /* 447 * BSDI's QMAGIC format: 448 * same as new ZMAGIC format, but with different magic number 449 */ 450 return netbsd32_exec_aout_prep_zmagic(l, epp); 451 break; 452 453 case (MID_ZERO << 16) | NMAGIC: 454 /* 455 * BSDI's NMAGIC format: 456 * same as NMAGIC format, but with different magic number 457 * and with text starting at 0. 458 */ 459 return netbsd32_exec_aout_prep_oldnmagic(l, epp); 460 461 case (MID_ZERO << 16) | OMAGIC: 462 /* 463 * BSDI's OMAGIC format: 464 * same as OMAGIC format, but with different magic number 465 * and with text starting at 0. 466 */ 467 return netbsd32_exec_aout_prep_oldomagic(l, epp); 468 469 default: 470 return ENOEXEC; 471 } 472 473 return error; 474} 475#endif 476