Annotation of sys/kern/exec_elf.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: exec_elf.c,v 1.61 2007/05/28 23:10:10 beck Exp $ */
! 2:
! 3: /*
! 4: * Copyright (c) 1996 Per Fogelstrom
! 5: * All rights reserved.
! 6: *
! 7: * Copyright (c) 1994 Christos Zoulas
! 8: * All rights reserved.
! 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. The name of the author may not be used to endorse or promote products
! 19: * derived from this software without specific prior written permission
! 20: *
! 21: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
! 22: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
! 23: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
! 24: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
! 25: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
! 26: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
! 27: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
! 28: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
! 29: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
! 30: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
! 31: *
! 32: */
! 33:
! 34: #include <sys/param.h>
! 35: #include <sys/systm.h>
! 36: #include <sys/kernel.h>
! 37: #include <sys/proc.h>
! 38: #include <sys/malloc.h>
! 39: #include <sys/pool.h>
! 40: #include <sys/mount.h>
! 41: #include <sys/namei.h>
! 42: #include <sys/vnode.h>
! 43: #include <sys/exec.h>
! 44: #include <sys/exec_elf.h>
! 45: #include <sys/exec_olf.h>
! 46: #include <sys/file.h>
! 47: #include <sys/syscall.h>
! 48: #include <sys/signalvar.h>
! 49: #include <sys/stat.h>
! 50:
! 51: #include <sys/mman.h>
! 52: #include <uvm/uvm_extern.h>
! 53:
! 54: #include <machine/cpu.h>
! 55: #include <machine/reg.h>
! 56: #include <machine/exec.h>
! 57:
! 58: #ifdef COMPAT_LINUX
! 59: #include <compat/linux/linux_exec.h>
! 60: #endif
! 61:
! 62: #ifdef COMPAT_SVR4
! 63: #include <compat/svr4/svr4_exec.h>
! 64: #endif
! 65:
! 66: #ifdef COMPAT_FREEBSD
! 67: #include <compat/freebsd/freebsd_exec.h>
! 68: #endif
! 69:
! 70: struct ELFNAME(probe_entry) {
! 71: int (*func)(struct proc *, struct exec_package *, char *,
! 72: u_long *, u_int8_t *);
! 73: int os_mask;
! 74: } ELFNAME(probes)[] = {
! 75: /* XXX - bogus, shouldn't be size independent.. */
! 76: #ifdef COMPAT_FREEBSD
! 77: { freebsd_elf_probe, 1 << OOS_FREEBSD },
! 78: #endif
! 79: #ifdef COMPAT_SVR4
! 80: { svr4_elf_probe,
! 81: 1 << OOS_SVR4 | 1 << OOS_ESIX | 1 << OOS_SOLARIS | 1 << OOS_SCO |
! 82: 1 << OOS_DELL | 1 << OOS_NCR },
! 83: #endif
! 84: #ifdef COMPAT_LINUX
! 85: { linux_elf_probe, 1 << OOS_LINUX },
! 86: #endif
! 87: { 0, 1 << OOS_OPENBSD }
! 88: };
! 89:
! 90: int ELFNAME(load_file)(struct proc *, char *, struct exec_package *,
! 91: struct elf_args *, Elf_Addr *);
! 92: int ELFNAME(check_header)(Elf_Ehdr *, int);
! 93: int ELFNAME(olf_check_header)(Elf_Ehdr *, int, u_int8_t *);
! 94: int ELFNAME(read_from)(struct proc *, struct vnode *, u_long, caddr_t, int);
! 95: void ELFNAME(load_psection)(struct exec_vmcmd_set *, struct vnode *,
! 96: Elf_Phdr *, Elf_Addr *, Elf_Addr *, int *, int);
! 97:
! 98: extern char sigcode[], esigcode[];
! 99: #ifdef SYSCALL_DEBUG
! 100: extern char *syscallnames[];
! 101: #endif
! 102:
! 103: /* round up and down to page boundaries. */
! 104: #define ELF_ROUND(a, b) (((a) + (b) - 1) & ~((b) - 1))
! 105: #define ELF_TRUNC(a, b) ((a) & ~((b) - 1))
! 106:
! 107: /*
! 108: * We limit the number of program headers to 32, this should
! 109: * be a reasonable limit for ELF, the most we have seen so far is 12
! 110: */
! 111: #define ELF_MAX_VALID_PHDR 32
! 112:
! 113: /*
! 114: * This is the basic elf emul. elf_probe_funcs may change to other emuls.
! 115: */
! 116: struct emul ELFNAMEEND(emul) = {
! 117: "native",
! 118: NULL,
! 119: sendsig,
! 120: SYS_syscall,
! 121: SYS_MAXSYSCALL,
! 122: sysent,
! 123: #ifdef SYSCALL_DEBUG
! 124: syscallnames,
! 125: #else
! 126: NULL,
! 127: #endif
! 128: sizeof (AuxInfo) * ELF_AUX_ENTRIES,
! 129: ELFNAME(copyargs),
! 130: setregs,
! 131: ELFNAME2(exec,fixup),
! 132: sigcode,
! 133: esigcode,
! 134: EMUL_ENABLED | EMUL_NATIVE,
! 135: };
! 136:
! 137: /*
! 138: * Copy arguments onto the stack in the normal way, but add some
! 139: * space for extra information in case of dynamic binding.
! 140: */
! 141: void *
! 142: ELFNAME(copyargs)(struct exec_package *pack, struct ps_strings *arginfo,
! 143: void *stack, void *argp)
! 144: {
! 145: stack = copyargs(pack, arginfo, stack, argp);
! 146: if (!stack)
! 147: return (NULL);
! 148:
! 149: /*
! 150: * Push space for extra arguments on the stack needed by
! 151: * dynamically linked binaries.
! 152: */
! 153: if (pack->ep_interp != NULL) {
! 154: pack->ep_emul_argp = stack;
! 155: stack = (char *)stack + ELF_AUX_ENTRIES * sizeof (AuxInfo);
! 156: }
! 157: return (stack);
! 158: }
! 159:
! 160: /*
! 161: * Check header for validity; return 0 for ok, ENOEXEC if error
! 162: */
! 163: int
! 164: ELFNAME(check_header)(Elf_Ehdr *ehdr, int type)
! 165: {
! 166: /*
! 167: * We need to check magic, class size, endianess, and version before
! 168: * we look at the rest of the Elf_Ehdr structure. These few elements
! 169: * are represented in a machine independant fashion.
! 170: */
! 171: if (!IS_ELF(*ehdr) ||
! 172: ehdr->e_ident[EI_CLASS] != ELF_TARG_CLASS ||
! 173: ehdr->e_ident[EI_DATA] != ELF_TARG_DATA ||
! 174: ehdr->e_ident[EI_VERSION] != ELF_TARG_VER)
! 175: return (ENOEXEC);
! 176:
! 177: /* Now check the machine dependant header */
! 178: if (ehdr->e_machine != ELF_TARG_MACH ||
! 179: ehdr->e_version != ELF_TARG_VER)
! 180: return (ENOEXEC);
! 181:
! 182: /* Check the type */
! 183: if (ehdr->e_type != type)
! 184: return (ENOEXEC);
! 185:
! 186: /* Don't allow an insane amount of sections. */
! 187: if (ehdr->e_phnum > ELF_MAX_VALID_PHDR)
! 188: return (ENOEXEC);
! 189:
! 190: return (0);
! 191: }
! 192:
! 193: #ifndef SMALL_KERNEL
! 194: /*
! 195: * Check header for validity; return 0 for ok, ENOEXEC if error.
! 196: * Remember OS tag for callers sake.
! 197: */
! 198: int
! 199: ELFNAME(olf_check_header)(Elf_Ehdr *ehdr, int type, u_int8_t *os)
! 200: {
! 201: int i;
! 202:
! 203: /*
! 204: * We need to check magic, class size, endianess, version, and OS
! 205: * before we look at the rest of the Elf_Ehdr structure. These few
! 206: * elements are represented in a machine independant fashion.
! 207: */
! 208: if (!IS_OLF(*ehdr) ||
! 209: ehdr->e_ident[OI_CLASS] != ELF_TARG_CLASS ||
! 210: ehdr->e_ident[OI_DATA] != ELF_TARG_DATA ||
! 211: ehdr->e_ident[OI_VERSION] != ELF_TARG_VER)
! 212: return (ENOEXEC);
! 213:
! 214: for (i = 0;
! 215: i < sizeof(ELFNAME(probes)) / sizeof(ELFNAME(probes)[0]);
! 216: i++) {
! 217: if ((1 << ehdr->e_ident[OI_OS]) & ELFNAME(probes)[i].os_mask)
! 218: goto os_ok;
! 219: }
! 220: return (ENOEXEC);
! 221:
! 222: os_ok:
! 223: /* Now check the machine dependant header */
! 224: if (ehdr->e_machine != ELF_TARG_MACH ||
! 225: ehdr->e_version != ELF_TARG_VER)
! 226: return (ENOEXEC);
! 227:
! 228: /* Check the type */
! 229: if (ehdr->e_type != type)
! 230: return (ENOEXEC);
! 231:
! 232: /* Don't allow an insane amount of sections. */
! 233: if (ehdr->e_phnum > ELF_MAX_VALID_PHDR)
! 234: return (ENOEXEC);
! 235:
! 236: *os = ehdr->e_ident[OI_OS];
! 237: return (0);
! 238: }
! 239: #endif /* !SMALL_KERNEL */
! 240:
! 241: /*
! 242: * Load a psection at the appropriate address
! 243: */
! 244: void
! 245: ELFNAME(load_psection)(struct exec_vmcmd_set *vcset, struct vnode *vp,
! 246: Elf_Phdr *ph, Elf_Addr *addr, Elf_Addr *size, int *prot, int flags)
! 247: {
! 248: u_long uaddr, msize, lsize, psize, rm, rf;
! 249: long diff, offset, bdiff;
! 250: Elf_Addr base;
! 251:
! 252: /*
! 253: * If the user specified an address, then we load there.
! 254: */
! 255: if (*addr != ELFDEFNNAME(NO_ADDR)) {
! 256: if (ph->p_align > 1) {
! 257: *addr = ELF_TRUNC(*addr, ph->p_align);
! 258: diff = ph->p_vaddr - ELF_TRUNC(ph->p_vaddr, ph->p_align);
! 259: /* page align vaddr */
! 260: base = *addr + trunc_page(ph->p_vaddr)
! 261: - ELF_TRUNC(ph->p_vaddr, ph->p_align);
! 262:
! 263: bdiff = ph->p_vaddr - trunc_page(ph->p_vaddr);
! 264:
! 265: } else
! 266: diff = 0;
! 267: } else {
! 268: *addr = uaddr = ph->p_vaddr;
! 269: if (ph->p_align > 1)
! 270: *addr = ELF_TRUNC(uaddr, ph->p_align);
! 271: base = trunc_page(uaddr);
! 272: bdiff = uaddr - base;
! 273: diff = uaddr - *addr;
! 274: }
! 275:
! 276: *prot |= (ph->p_flags & PF_R) ? VM_PROT_READ : 0;
! 277: *prot |= (ph->p_flags & PF_W) ? VM_PROT_WRITE : 0;
! 278: *prot |= (ph->p_flags & PF_X) ? VM_PROT_EXECUTE : 0;
! 279:
! 280: msize = ph->p_memsz + diff;
! 281: offset = ph->p_offset - bdiff;
! 282: lsize = ph->p_filesz + bdiff;
! 283: psize = round_page(lsize);
! 284:
! 285: /*
! 286: * Because the pagedvn pager can't handle zero fill of the last
! 287: * data page if it's not page aligned we map the last page readvn.
! 288: */
! 289: if (ph->p_flags & PF_W) {
! 290: psize = trunc_page(lsize);
! 291: if (psize > 0)
! 292: NEW_VMCMD2(vcset, vmcmd_map_pagedvn, psize, base, vp,
! 293: offset, *prot, flags);
! 294: if (psize != lsize) {
! 295: NEW_VMCMD2(vcset, vmcmd_map_readvn, lsize - psize,
! 296: base + psize, vp, offset + psize, *prot, flags);
! 297: }
! 298: } else {
! 299: NEW_VMCMD2(vcset, vmcmd_map_pagedvn, psize, base, vp, offset,
! 300: *prot, flags);
! 301: }
! 302:
! 303: /*
! 304: * Check if we need to extend the size of the segment
! 305: */
! 306: rm = round_page(*addr + ph->p_memsz + diff);
! 307: rf = round_page(*addr + ph->p_filesz + diff);
! 308:
! 309: if (rm != rf) {
! 310: NEW_VMCMD2(vcset, vmcmd_map_zero, rm - rf, rf, NULLVP, 0,
! 311: *prot, flags);
! 312: }
! 313: *size = msize;
! 314: }
! 315:
! 316: /*
! 317: * Read from vnode into buffer at offset.
! 318: */
! 319: int
! 320: ELFNAME(read_from)(struct proc *p, struct vnode *vp, u_long off, caddr_t buf,
! 321: int size)
! 322: {
! 323: int error;
! 324: size_t resid;
! 325:
! 326: if ((error = vn_rdwr(UIO_READ, vp, buf, size, off, UIO_SYSSPACE,
! 327: 0, p->p_ucred, &resid, p)) != 0)
! 328: return error;
! 329: /*
! 330: * See if we got all of it
! 331: */
! 332: if (resid != 0)
! 333: return (ENOEXEC);
! 334: return (0);
! 335: }
! 336:
! 337: /*
! 338: * Load a file (interpreter/library) pointed to by path [stolen from
! 339: * coff_load_shlib()]. Made slightly generic so it might be used externally.
! 340: */
! 341: int
! 342: ELFNAME(load_file)(struct proc *p, char *path, struct exec_package *epp,
! 343: struct elf_args *ap, Elf_Addr *last)
! 344: {
! 345: int error, i;
! 346: struct nameidata nd;
! 347: Elf_Ehdr eh;
! 348: Elf_Phdr *ph = NULL;
! 349: u_long phsize;
! 350: Elf_Addr addr;
! 351: struct vnode *vp;
! 352: #ifndef SMALL_KERNEL
! 353: u_int8_t os; /* Just a dummy in this routine */
! 354: #endif
! 355: Elf_Phdr *base_ph = NULL;
! 356: struct interp_ld_sec {
! 357: Elf_Addr vaddr;
! 358: u_long memsz;
! 359: } loadmap[ELF_MAX_VALID_PHDR];
! 360: int nload, idx = 0;
! 361: Elf_Addr pos = *last;
! 362: int file_align;
! 363:
! 364: NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, path, p);
! 365: if ((error = namei(&nd)) != 0) {
! 366: return (error);
! 367: }
! 368: vp = nd.ni_vp;
! 369: if (vp->v_type != VREG) {
! 370: error = EACCES;
! 371: goto bad;
! 372: }
! 373: if ((error = VOP_GETATTR(vp, epp->ep_vap, p->p_ucred, p)) != 0)
! 374: goto bad;
! 375: if (vp->v_mount->mnt_flag & MNT_NOEXEC) {
! 376: error = EACCES;
! 377: goto bad;
! 378: }
! 379: if ((error = VOP_ACCESS(vp, VREAD, p->p_ucred, p)) != 0)
! 380: goto bad1;
! 381: if ((error = ELFNAME(read_from)(p, nd.ni_vp, 0,
! 382: (caddr_t)&eh, sizeof(eh))) != 0)
! 383: goto bad1;
! 384:
! 385: if (ELFNAME(check_header)(&eh, ET_DYN)
! 386: #ifndef SMALL_KERNEL
! 387: && ELFNAME(olf_check_header)(&eh, ET_DYN, &os)
! 388: #endif
! 389: ) {
! 390: error = ENOEXEC;
! 391: goto bad1;
! 392: }
! 393:
! 394: phsize = eh.e_phnum * sizeof(Elf_Phdr);
! 395: ph = malloc(phsize, M_TEMP, M_WAITOK);
! 396:
! 397: if ((error = ELFNAME(read_from)(p, nd.ni_vp, eh.e_phoff, (caddr_t)ph,
! 398: phsize)) != 0)
! 399: goto bad1;
! 400:
! 401: for (i = 0; i < eh.e_phnum; i++) {
! 402: if (ph[i].p_type == PT_LOAD) {
! 403: loadmap[idx].vaddr = trunc_page(ph[i].p_vaddr);
! 404: loadmap[idx].memsz = round_page (ph[i].p_vaddr +
! 405: ph[i].p_memsz - loadmap[idx].vaddr);
! 406: file_align = ph[i].p_align;
! 407: idx++;
! 408: }
! 409: }
! 410: nload = idx;
! 411:
! 412: /*
! 413: * If no position to load the interpreter was set by a probe
! 414: * function, pick the same address that a non-fixed mmap(0, ..)
! 415: * would (i.e. something safely out of the way).
! 416: */
! 417: if (pos == ELFDEFNNAME(NO_ADDR)) {
! 418: pos = uvm_map_hint(p, VM_PROT_EXECUTE);
! 419: }
! 420:
! 421: pos = ELF_ROUND(pos, file_align);
! 422: *last = epp->ep_interp_pos = pos;
! 423: for (i = 0; i < nload;/**/) {
! 424: vaddr_t addr;
! 425: struct uvm_object *uobj;
! 426: off_t uoff;
! 427: size_t size;
! 428:
! 429: #ifdef this_needs_fixing
! 430: if (i == 0) {
! 431: uobj = &vp->v_uvm.u_obj;
! 432: /* need to fix uoff */
! 433: } else {
! 434: #endif
! 435: uobj = NULL;
! 436: uoff = 0;
! 437: #ifdef this_needs_fixing
! 438: }
! 439: #endif
! 440:
! 441: addr = trunc_page(pos + loadmap[i].vaddr);
! 442: size = round_page(addr + loadmap[i].memsz) - addr;
! 443:
! 444: /* CRAP - map_findspace does not avoid daddr+MAXDSIZ */
! 445: if ((addr + size > (vaddr_t)p->p_vmspace->vm_daddr) &&
! 446: (addr < (vaddr_t)p->p_vmspace->vm_daddr + MAXDSIZ))
! 447: addr = round_page((vaddr_t)p->p_vmspace->vm_daddr +
! 448: MAXDSIZ);
! 449:
! 450: if (uvm_map_findspace(&p->p_vmspace->vm_map, addr, size,
! 451: &addr, uobj, uoff, 0, UVM_FLAG_FIXED) == NULL) {
! 452: if (uvm_map_findspace(&p->p_vmspace->vm_map, addr, size,
! 453: &addr, uobj, uoff, 0, 0) == NULL) {
! 454: error = ENOMEM; /* XXX */
! 455: goto bad1;
! 456: }
! 457: }
! 458: if (addr != pos + loadmap[i].vaddr) {
! 459: /* base changed. */
! 460: pos = addr - trunc_page(loadmap[i].vaddr);
! 461: pos = ELF_ROUND(pos,file_align);
! 462: epp->ep_interp_pos = *last = pos;
! 463: i = 0;
! 464: continue;
! 465: }
! 466:
! 467: i++;
! 468: }
! 469:
! 470: /*
! 471: * Load all the necessary sections
! 472: */
! 473: for (i = 0; i < eh.e_phnum; i++) {
! 474: Elf_Addr size = 0;
! 475: int prot = 0;
! 476: int flags;
! 477:
! 478: switch (ph[i].p_type) {
! 479: case PT_LOAD:
! 480: if (base_ph == NULL) {
! 481: flags = VMCMD_BASE;
! 482: addr = *last;
! 483: base_ph = &ph[i];
! 484: } else {
! 485: flags = VMCMD_RELATIVE;
! 486: addr = ph[i].p_vaddr - base_ph->p_vaddr;
! 487: }
! 488: ELFNAME(load_psection)(&epp->ep_vmcmds, nd.ni_vp,
! 489: &ph[i], &addr, &size, &prot, flags);
! 490: /* If entry is within this section it must be text */
! 491: if (eh.e_entry >= ph[i].p_vaddr &&
! 492: eh.e_entry < (ph[i].p_vaddr + size)) {
! 493: epp->ep_entry = addr + eh.e_entry -
! 494: ELF_TRUNC(ph[i].p_vaddr,ph[i].p_align);
! 495: ap->arg_interp = addr;
! 496: }
! 497: addr += size;
! 498: break;
! 499:
! 500: case PT_DYNAMIC:
! 501: case PT_PHDR:
! 502: case PT_NOTE:
! 503: break;
! 504:
! 505: default:
! 506: break;
! 507: }
! 508: }
! 509:
! 510: vn_marktext(nd.ni_vp);
! 511:
! 512: bad1:
! 513: VOP_CLOSE(nd.ni_vp, FREAD, p->p_ucred, p);
! 514: bad:
! 515: if (ph != NULL)
! 516: free(ph, M_TEMP);
! 517:
! 518: *last = addr;
! 519: vput(nd.ni_vp);
! 520: return (error);
! 521: }
! 522:
! 523: /*
! 524: * Prepare an Elf binary's exec package
! 525: *
! 526: * First, set of the various offsets/lengths in the exec package.
! 527: *
! 528: * Then, mark the text image busy (so it can be demand paged) or error out if
! 529: * this is not possible. Finally, set up vmcmds for the text, data, bss, and
! 530: * stack segments.
! 531: */
! 532: int
! 533: ELFNAME2(exec,makecmds)(struct proc *p, struct exec_package *epp)
! 534: {
! 535: Elf_Ehdr *eh = epp->ep_hdr;
! 536: Elf_Phdr *ph, *pp;
! 537: Elf_Addr phdr = 0;
! 538: int error, i;
! 539: char *interp = NULL;
! 540: u_long pos = 0, phsize;
! 541: u_int8_t os = OOS_NULL;
! 542:
! 543: if (epp->ep_hdrvalid < sizeof(Elf_Ehdr))
! 544: return (ENOEXEC);
! 545:
! 546: if (ELFNAME(check_header)(eh, ET_EXEC)
! 547: #ifndef SMALL_KERNEL
! 548: && ELFNAME(olf_check_header)(eh, ET_EXEC, &os)
! 549: #endif
! 550: )
! 551: return (ENOEXEC);
! 552:
! 553: /*
! 554: * check if vnode is in open for writing, because we want to demand-
! 555: * page out of it. if it is, don't do it, for various reasons.
! 556: */
! 557: if (epp->ep_vp->v_writecount != 0) {
! 558: #ifdef DIAGNOSTIC
! 559: if (epp->ep_vp->v_flag & VTEXT)
! 560: panic("exec: a VTEXT vnode has writecount != 0");
! 561: #endif
! 562: return (ETXTBSY);
! 563: }
! 564: /*
! 565: * Allocate space to hold all the program headers, and read them
! 566: * from the file
! 567: */
! 568: phsize = eh->e_phnum * sizeof(Elf_Phdr);
! 569: ph = malloc(phsize, M_TEMP, M_WAITOK);
! 570:
! 571: if ((error = ELFNAME(read_from)(p, epp->ep_vp, eh->e_phoff, (caddr_t)ph,
! 572: phsize)) != 0)
! 573: goto bad;
! 574:
! 575: epp->ep_tsize = ELFDEFNNAME(NO_ADDR);
! 576: epp->ep_dsize = ELFDEFNNAME(NO_ADDR);
! 577:
! 578: for (i = 0; i < eh->e_phnum; i++) {
! 579: pp = &ph[i];
! 580: if (pp->p_type == PT_INTERP) {
! 581: if (pp->p_filesz >= MAXPATHLEN)
! 582: goto bad;
! 583: interp = pool_get(&namei_pool, PR_WAITOK);
! 584: if ((error = ELFNAME(read_from)(p, epp->ep_vp,
! 585: pp->p_offset, interp, pp->p_filesz)) != 0) {
! 586: goto bad;
! 587: }
! 588: break;
! 589: }
! 590: }
! 591:
! 592: /*
! 593: * OK, we want a slightly different twist of the
! 594: * standard emulation package for "real" elf.
! 595: */
! 596: epp->ep_emul = &ELFNAMEEND(emul);
! 597: pos = ELFDEFNNAME(NO_ADDR);
! 598:
! 599: /*
! 600: * On the same architecture, we may be emulating different systems.
! 601: * See which one will accept this executable.
! 602: *
! 603: * Probe functions would normally see if the interpreter (if any)
! 604: * exists. Emulation packages may possibly replace the interpreter in
! 605: * *interp with a changed path (/emul/xxx/<path>), and also
! 606: * set the ep_emul field in the exec package structure.
! 607: */
! 608: error = ENOEXEC;
! 609: p->p_os = OOS_OPENBSD;
! 610: #ifdef NATIVE_EXEC_ELF
! 611: if (ELFNAME(os_pt_note)(p, epp, epp->ep_hdr, "OpenBSD", 8, 4) == 0) {
! 612: goto native;
! 613: }
! 614: #endif
! 615: for (i = 0;
! 616: i < sizeof(ELFNAME(probes)) / sizeof(ELFNAME(probes)[0]) && error;
! 617: i++) {
! 618: if (os == OOS_NULL || ((1 << os) & ELFNAME(probes)[i].os_mask))
! 619: error = ELFNAME(probes)[i].func ?
! 620: (*ELFNAME(probes)[i].func)(p, epp, interp, &pos, &os) :
! 621: 0;
! 622: }
! 623: if (!error)
! 624: p->p_os = os;
! 625: #ifndef NATIVE_EXEC_ELF
! 626: else
! 627: goto bad;
! 628: #else
! 629: native:
! 630: #endif /* NATIVE_EXEC_ELF */
! 631: /*
! 632: * Load all the necessary sections
! 633: */
! 634: for (i = 0; i < eh->e_phnum; i++) {
! 635: Elf_Addr addr = ELFDEFNNAME(NO_ADDR), size = 0;
! 636: int prot = 0;
! 637:
! 638: pp = &ph[i];
! 639:
! 640: switch (ph[i].p_type) {
! 641: case PT_LOAD:
! 642: /*
! 643: * Calculates size of text and data segments
! 644: * by starting at first and going to end of last.
! 645: * 'rwx' sections are treated as data.
! 646: * this is correct for BSS_PLT, but may not be
! 647: * for DATA_PLT, is fine for TEXT_PLT.
! 648: */
! 649: ELFNAME(load_psection)(&epp->ep_vmcmds, epp->ep_vp,
! 650: &ph[i], &addr, &size, &prot, 0);
! 651: /*
! 652: * Decide whether it's text or data by looking
! 653: * at the protection of the section
! 654: */
! 655: if (prot & VM_PROT_WRITE) {
! 656: /* data section */
! 657: if (epp->ep_dsize == ELFDEFNNAME(NO_ADDR)) {
! 658: epp->ep_daddr = addr;
! 659: epp->ep_dsize = size;
! 660: } else {
! 661: if (addr < epp->ep_daddr) {
! 662: epp->ep_dsize =
! 663: epp->ep_dsize +
! 664: epp->ep_daddr -
! 665: addr;
! 666: epp->ep_daddr = addr;
! 667: } else
! 668: epp->ep_dsize = addr+size -
! 669: epp->ep_daddr;
! 670: }
! 671: } else if (prot & VM_PROT_EXECUTE) {
! 672: /* text section */
! 673: if (epp->ep_tsize == ELFDEFNNAME(NO_ADDR)) {
! 674: epp->ep_taddr = addr;
! 675: epp->ep_tsize = size;
! 676: } else {
! 677: if (addr < epp->ep_taddr) {
! 678: epp->ep_tsize =
! 679: epp->ep_tsize +
! 680: epp->ep_taddr -
! 681: addr;
! 682: epp->ep_taddr = addr;
! 683: } else
! 684: epp->ep_tsize = addr+size -
! 685: epp->ep_taddr;
! 686: }
! 687: }
! 688: break;
! 689:
! 690: case PT_SHLIB:
! 691: error = ENOEXEC;
! 692: goto bad;
! 693:
! 694: case PT_INTERP:
! 695: /* Already did this one */
! 696: case PT_DYNAMIC:
! 697: case PT_NOTE:
! 698: break;
! 699:
! 700: case PT_PHDR:
! 701: /* Note address of program headers (in text segment) */
! 702: phdr = pp->p_vaddr;
! 703: break;
! 704:
! 705: default:
! 706: /*
! 707: * Not fatal, we don't need to understand everything
! 708: * :-)
! 709: */
! 710: break;
! 711: }
! 712: }
! 713:
! 714: /*
! 715: * Strangely some linux programs may have all load sections marked
! 716: * writeable, in this case, textsize is not -1, but rather 0;
! 717: */
! 718: if (epp->ep_tsize == ELFDEFNNAME(NO_ADDR))
! 719: epp->ep_tsize = 0;
! 720: /*
! 721: * Another possibility is that it has all load sections marked
! 722: * read-only. Fake a zero-sized data segment right after the
! 723: * text segment.
! 724: */
! 725: if (epp->ep_dsize == ELFDEFNNAME(NO_ADDR)) {
! 726: epp->ep_daddr = round_page(epp->ep_taddr + epp->ep_tsize);
! 727: epp->ep_dsize = 0;
! 728: }
! 729:
! 730: epp->ep_interp = interp;
! 731: epp->ep_entry = eh->e_entry;
! 732:
! 733: /*
! 734: * Check if we found a dynamically linked binary and arrange to load
! 735: * its interpreter when the exec file is released.
! 736: */
! 737: if (interp) {
! 738: struct elf_args *ap;
! 739:
! 740: ap = malloc(sizeof(struct elf_args), M_TEMP, M_WAITOK);
! 741:
! 742: ap->arg_phaddr = phdr;
! 743: ap->arg_phentsize = eh->e_phentsize;
! 744: ap->arg_phnum = eh->e_phnum;
! 745: ap->arg_entry = eh->e_entry;
! 746: ap->arg_os = os;
! 747:
! 748: epp->ep_emul_arg = ap;
! 749: epp->ep_interp_pos = pos;
! 750: }
! 751:
! 752: #if defined(COMPAT_SVR4) && defined(i386)
! 753: #ifndef ELF_MAP_PAGE_ZERO
! 754: /* Dell SVR4 maps page zero, yeuch! */
! 755: if (p->p_os == OOS_DELL)
! 756: #endif
! 757: NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_readvn, PAGE_SIZE, 0,
! 758: epp->ep_vp, 0, VM_PROT_READ);
! 759: #endif
! 760:
! 761: free(ph, M_TEMP);
! 762: vn_marktext(epp->ep_vp);
! 763: return (exec_setup_stack(p, epp));
! 764:
! 765: bad:
! 766: if (interp)
! 767: pool_put(&namei_pool, interp);
! 768: free(ph, M_TEMP);
! 769: kill_vmcmds(&epp->ep_vmcmds);
! 770: return (ENOEXEC);
! 771: }
! 772:
! 773: /*
! 774: * Phase II of load. It is now safe to load the interpreter. Info collected
! 775: * when loading the program is available for setup of the interpreter.
! 776: */
! 777: int
! 778: ELFNAME2(exec,fixup)(struct proc *p, struct exec_package *epp)
! 779: {
! 780: char *interp;
! 781: int error;
! 782: struct elf_args *ap;
! 783: AuxInfo ai[ELF_AUX_ENTRIES], *a;
! 784: Elf_Addr pos = epp->ep_interp_pos;
! 785:
! 786: if (epp->ep_interp == NULL) {
! 787: return (0);
! 788: }
! 789:
! 790: interp = epp->ep_interp;
! 791: ap = epp->ep_emul_arg;
! 792:
! 793: if ((error = ELFNAME(load_file)(p, interp, epp, ap, &pos)) != 0) {
! 794: free(ap, M_TEMP);
! 795: pool_put(&namei_pool, interp);
! 796: kill_vmcmds(&epp->ep_vmcmds);
! 797: return (error);
! 798: }
! 799: /*
! 800: * We have to do this ourselves...
! 801: */
! 802: error = exec_process_vmcmds(p, epp);
! 803:
! 804: /*
! 805: * Push extra arguments on the stack needed by dynamically
! 806: * linked binaries
! 807: */
! 808: if (error == 0) {
! 809: a = ai;
! 810:
! 811: a->au_id = AUX_phdr;
! 812: a->au_v = ap->arg_phaddr;
! 813: a++;
! 814:
! 815: a->au_id = AUX_phent;
! 816: a->au_v = ap->arg_phentsize;
! 817: a++;
! 818:
! 819: a->au_id = AUX_phnum;
! 820: a->au_v = ap->arg_phnum;
! 821: a++;
! 822:
! 823: a->au_id = AUX_pagesz;
! 824: a->au_v = PAGE_SIZE;
! 825: a++;
! 826:
! 827: a->au_id = AUX_base;
! 828: a->au_v = ap->arg_interp;
! 829: a++;
! 830:
! 831: a->au_id = AUX_flags;
! 832: a->au_v = 0;
! 833: a++;
! 834:
! 835: a->au_id = AUX_entry;
! 836: a->au_v = ap->arg_entry;
! 837: a++;
! 838:
! 839: a->au_id = AUX_null;
! 840: a->au_v = 0;
! 841: a++;
! 842:
! 843: error = copyout(ai, epp->ep_emul_argp, sizeof ai);
! 844: }
! 845: free(ap, M_TEMP);
! 846: pool_put(&namei_pool, interp);
! 847: return (error);
! 848: }
! 849:
! 850: /*
! 851: * Older ELF binaries use EI_ABIVERSION (formerly EI_BRAND) to brand
! 852: * executables. Newer ELF binaries use EI_OSABI instead.
! 853: */
! 854: char *
! 855: ELFNAME(check_brand)(Elf_Ehdr *eh)
! 856: {
! 857: if (eh->e_ident[EI_ABIVERSION] == '\0')
! 858: return (NULL);
! 859: return (&eh->e_ident[EI_ABIVERSION]);
! 860: }
! 861:
! 862: int
! 863: ELFNAME(os_pt_note)(struct proc *p, struct exec_package *epp, Elf_Ehdr *eh,
! 864: char *os_name, size_t name_size, size_t desc_size)
! 865: {
! 866: Elf_Phdr *hph, *ph;
! 867: Elf_Note *np = NULL;
! 868: size_t phsize;
! 869: int error;
! 870:
! 871: phsize = eh->e_phnum * sizeof(Elf_Phdr);
! 872: hph = malloc(phsize, M_TEMP, M_WAITOK);
! 873: if ((error = ELFNAME(read_from)(p, epp->ep_vp, eh->e_phoff,
! 874: (caddr_t)hph, phsize)) != 0)
! 875: goto out1;
! 876:
! 877: for (ph = hph; ph < &hph[eh->e_phnum]; ph++) {
! 878: if (ph->p_type != PT_NOTE ||
! 879: ph->p_filesz > 1024 ||
! 880: ph->p_filesz < sizeof(Elf_Note) + name_size)
! 881: continue;
! 882:
! 883: np = malloc(ph->p_filesz, M_TEMP, M_WAITOK);
! 884: if ((error = ELFNAME(read_from)(p, epp->ep_vp, ph->p_offset,
! 885: (caddr_t)np, ph->p_filesz)) != 0)
! 886: goto out2;
! 887:
! 888: #if 0
! 889: if (np->type != ELF_NOTE_TYPE_OSVERSION) {
! 890: free(np, M_TEMP);
! 891: np = NULL;
! 892: continue;
! 893: }
! 894: #endif
! 895:
! 896: /* Check the name and description sizes. */
! 897: if (np->namesz != name_size ||
! 898: np->descsz != desc_size)
! 899: goto out3;
! 900:
! 901: if (bcmp((np + 1), os_name, name_size))
! 902: goto out3;
! 903:
! 904: /* XXX: We could check for the specific emulation here */
! 905: /* All checks succeeded. */
! 906: error = 0;
! 907: goto out2;
! 908: }
! 909:
! 910: out3:
! 911: error = ENOEXEC;
! 912: out2:
! 913: if (np)
! 914: free(np, M_TEMP);
! 915: out1:
! 916: free(hph, M_TEMP);
! 917: return error;
! 918: }
CVSweb