]> Zhao Yanbai Git Server - minix.git/commitdiff
recognize and execute dynamically linked executables
authorBen Gras <ben@minix3.org>
Tue, 3 Apr 2012 13:52:25 +0000 (15:52 +0200)
committerBen Gras <ben@minix3.org>
Mon, 16 Apr 2012 00:41:42 +0000 (00:41 +0000)
   . generalize libexec slightly to get some more necessary information
  from ELF files, e.g. the interpreter
. execute dynamically linked executables when exec()ed by VFS
. switch to netbsd variant of elf32.h exclusively, solves some
  conflicting headers

21 files changed:
common/include/sys/Makefile.inc
common/include/sys/elf32.h [deleted file]
include/arch/i386/include/elf.h
include/minix/com.h
include/sys/Makefile
kernel/arch/i386/pre_init.c
lib/libc/sys-minix/execve.c
lib/libexec/exec_elf.c
lib/libexec/libexec.h
libexec/ld.elf_so/Makefile
libexec/ld.elf_so/map_object.c
servers/pm/exec.c
servers/pm/main.c
servers/pm/proto.h
servers/rs/exec.c
servers/vfs/coredump.c
servers/vfs/exec.c
servers/vfs/exec.h
servers/vfs/fproc.h
servers/vfs/main.c
servers/vfs/proto.h

index e670fcbc5871b85ba39ff38b40003cbe1a0b479f..5394cd6d54da64ad38732eaf62fc944258c366e2 100644 (file)
@@ -2,7 +2,7 @@
 
 .PATH: ${MINIXSRCDIR}/common/include/sys
 
-INCS+=         elf32.h elf64.h elf_common.h elf_generic.h \
+INCS+=         elf64.h elf_common.h elf_generic.h \
        ioc_block.h ioc_fbd.h ioc_file.h ioc_tape.h ioc_disk.h \
        ioc_memory.h ioc_sound.h ioc_tty.h \
        kbdio.h mtio.h svrctl.h video.h vm.h procfs.h elf_core.h exec_elf.h \
diff --git a/common/include/sys/elf32.h b/common/include/sys/elf32.h
deleted file mode 100644 (file)
index 8ae6d92..0000000
+++ /dev/null
@@ -1,249 +0,0 @@
-/*-
- * Copyright (c) 1996-1998 John D. Polstra.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * $FreeBSD$
- */
-
-#ifndef _SYS_ELF32_H_
-#define _SYS_ELF32_H_ 1
-
-#include <sys/elf_common.h>
-
-/*
- * ELF definitions common to all 32-bit architectures.
- */
-
-typedef uint32_t       Elf32_Addr;
-typedef uint16_t       Elf32_Half;
-typedef uint32_t       Elf32_Off;
-typedef int32_t                Elf32_Sword;
-typedef uint32_t       Elf32_Word;
-#if defined(__ACK__)
-typedef uint32_t       Elf32_Lword;
-#else
-typedef uint64_t       Elf32_Lword;
-#endif
-
-typedef Elf32_Word     Elf32_Hashelt;
-
-/* Non-standard class-dependent datatype used for abstraction. */
-typedef Elf32_Word     Elf32_Size;
-typedef Elf32_Sword    Elf32_Ssize;
-
-/*
- * ELF header.
- */
-
-typedef struct {
-       unsigned char   e_ident[EI_NIDENT];     /* File identification. */
-       Elf32_Half      e_type;         /* File type. */
-       Elf32_Half      e_machine;      /* Machine architecture. */
-       Elf32_Word      e_version;      /* ELF format version. */
-       Elf32_Addr      e_entry;        /* Entry point. */
-       Elf32_Off       e_phoff;        /* Program header file offset. */
-       Elf32_Off       e_shoff;        /* Section header file offset. */
-       Elf32_Word      e_flags;        /* Architecture-specific flags. */
-       Elf32_Half      e_ehsize;       /* Size of ELF header in bytes. */
-       Elf32_Half      e_phentsize;    /* Size of program header entry. */
-       Elf32_Half      e_phnum;        /* Number of program header entries. */
-       Elf32_Half      e_shentsize;    /* Size of section header entry. */
-       Elf32_Half      e_shnum;        /* Number of section header entries. */
-       Elf32_Half      e_shstrndx;     /* Section name strings section. */
-} Elf32_Ehdr;
-
-/*
- * Section header.
- */
-
-typedef struct {
-       Elf32_Word      sh_name;        /* Section name (index into the
-                                          section header string table). */
-       Elf32_Word      sh_type;        /* Section type. */
-       Elf32_Word      sh_flags;       /* Section flags. */
-       Elf32_Addr      sh_addr;        /* Address in memory image. */
-       Elf32_Off       sh_offset;      /* Offset in file. */
-       Elf32_Word      sh_size;        /* Size in bytes. */
-       Elf32_Word      sh_link;        /* Index of a related section. */
-       Elf32_Word      sh_info;        /* Depends on section type. */
-       Elf32_Word      sh_addralign;   /* Alignment in bytes. */
-       Elf32_Word      sh_entsize;     /* Size of each entry in section. */
-} Elf32_Shdr;
-
-/*
- * Program header.
- */
-
-typedef struct {
-       Elf32_Word      p_type;         /* Entry type. */
-       Elf32_Off       p_offset;       /* File offset of contents. */
-       Elf32_Addr      p_vaddr;        /* Virtual address in memory image. */
-       Elf32_Addr      p_paddr;        /* Physical address (not used). */
-       Elf32_Word      p_filesz;       /* Size of contents in file. */
-       Elf32_Word      p_memsz;        /* Size of contents in memory. */
-       Elf32_Word      p_flags;        /* Access permission flags. */
-       Elf32_Word      p_align;        /* Alignment in memory and file. */
-} Elf32_Phdr;
-
-/*
- * Dynamic structure.  The ".dynamic" section contains an array of them.
- */
-
-typedef struct {
-       Elf32_Sword     d_tag;          /* Entry type. */
-       union {
-               Elf32_Word      d_val;  /* Integer value. */
-               Elf32_Addr      d_ptr;  /* Address value. */
-       } d_un;
-} Elf32_Dyn;
-
-/*
- * Relocation entries.
- */
-
-/* Relocations that don't need an addend field. */
-typedef struct {
-       Elf32_Addr      r_offset;       /* Location to be relocated. */
-       Elf32_Word      r_info;         /* Relocation type and symbol index. */
-} Elf32_Rel;
-
-/* Relocations that need an addend field. */
-typedef struct {
-       Elf32_Addr      r_offset;       /* Location to be relocated. */
-       Elf32_Word      r_info;         /* Relocation type and symbol index. */
-       Elf32_Sword     r_addend;       /* Addend. */
-} Elf32_Rela;
-
-/* Macros for accessing the fields of r_info. */
-#define ELF32_R_SYM(info)      ((info) >> 8)
-#define ELF32_R_TYPE(info)     ((unsigned char)(info))
-
-/* Macro for constructing r_info from field values. */
-#define ELF32_R_INFO(sym, type)        (((sym) << 8) + (unsigned char)(type))
-
-/*
- *     Note entry header
- */
-typedef Elf_Note Elf32_Nhdr;
-
-/*
- *     Move entry
- */
-typedef struct {
-       Elf32_Lword     m_value;        /* symbol value */
-       Elf32_Word      m_info;         /* size + index */
-       Elf32_Word      m_poffset;      /* symbol offset */
-       Elf32_Half      m_repeat;       /* repeat count */
-       Elf32_Half      m_stride;       /* stride info */
-} Elf32_Move;
-
-/*
- *     The macros compose and decompose values for Move.r_info
- *
- *     sym = ELF32_M_SYM(M.m_info)
- *     size = ELF32_M_SIZE(M.m_info)
- *     M.m_info = ELF32_M_INFO(sym, size)
- */
-#define        ELF32_M_SYM(info)       ((info)>>8)
-#define        ELF32_M_SIZE(info)      ((unsigned char)(info))
-#define        ELF32_M_INFO(sym, size) (((sym)<<8)+(unsigned char)(size))
-
-/*
- *     Hardware/Software capabilities entry
- */
-typedef struct {
-       Elf32_Word      c_tag;          /* how to interpret value */
-       union {
-               Elf32_Word      c_val;
-               Elf32_Addr      c_ptr;
-       } c_un;
-} Elf32_Cap;
-
-/*
- * Symbol table entries.
- */
-
-typedef struct {
-       Elf32_Word      st_name;        /* String table index of name. */
-       Elf32_Addr      st_value;       /* Symbol value. */
-       Elf32_Word      st_size;        /* Size of associated object. */
-       unsigned char   st_info;        /* Type and binding information. */
-       unsigned char   st_other;       /* Reserved (not used). */
-       Elf32_Half      st_shndx;       /* Section index of symbol. */
-} Elf32_Sym;
-
-/* Macros for accessing the fields of st_info. */
-#define ELF32_ST_BIND(info)            ((info) >> 4)
-#define ELF32_ST_TYPE(info)            ((info) & 0xf)
-
-/* Macro for constructing st_info from field values. */
-#define ELF32_ST_INFO(bind, type)      (((bind) << 4) + ((type) & 0xf))
-
-/* Macro for accessing the fields of st_other. */
-#define ELF32_ST_VISIBILITY(oth)       ((oth) & 0x3)
-
-/* Structures used by Sun & GNU symbol versioning. */
-typedef struct
-{
-       Elf32_Half      vd_version;
-       Elf32_Half      vd_flags;
-       Elf32_Half      vd_ndx;
-       Elf32_Half      vd_cnt;
-       Elf32_Word      vd_hash;
-       Elf32_Word      vd_aux;
-       Elf32_Word      vd_next;
-} Elf32_Verdef;
-
-typedef struct
-{
-       Elf32_Word      vda_name;
-       Elf32_Word      vda_next;
-} Elf32_Verdaux;
-
-typedef struct
-{
-       Elf32_Half      vn_version;
-       Elf32_Half      vn_cnt;
-       Elf32_Word      vn_file;
-       Elf32_Word      vn_aux;
-       Elf32_Word      vn_next;
-} Elf32_Verneed;
-
-typedef struct
-{
-       Elf32_Word      vna_hash;
-       Elf32_Half      vna_flags;
-       Elf32_Half      vna_other;
-       Elf32_Word      vna_name;
-       Elf32_Word      vna_next;
-} Elf32_Vernaux;
-
-typedef Elf32_Half Elf32_Versym;
-
-typedef struct {
-       Elf32_Half      si_boundto;     /* direct bindings - symbol bound to */
-       Elf32_Half      si_flags;       /* per symbol flags */
-} Elf32_Syminfo;
-
-#endif /* !_SYS_ELF32_H_ */
index 6490f2af631afc651901c0bc743a61cb106e727e..6d6e2376fc97fa4d7e1edf82acfce7bade0e977e 100644 (file)
  * ELF definitions for the i386 architecture.
  */
 
-#include <sys/elf32.h> /* Definitions common to all 32 bit architectures. */
-#if defined(__ELF_WORD_SIZE) && __ELF_WORD_SIZE == 64
-#include <sys/elf64.h> /* Definitions common to all 64 bit architectures. */
-#endif
-
-#ifndef __ELF_WORD_SIZE
-#define        __ELF_WORD_SIZE 32      /* Used by <sys/elf_generic.h> */
-#endif
-
-#include <sys/elf_generic.h>
-
-#define        ELF_ARCH        EM_386
-
-#define        ELF_MACHINE_OK(x) ((x) == EM_386 || (x) == EM_486)
-
-/*
- * Auxiliary vector entries for passing information to the interpreter.
- *
- * The i386 supplement to the SVR4 ABI specification names this "auxv_t",
- * but POSIX lays claim to all symbols ending with "_t".
- */
-
-typedef struct {       /* Auxiliary vector entry on initial stack */
-       int     a_type;                 /* Entry type. */
-       union {
-               long    a_val;          /* Integer value. */
-               void    *a_ptr;         /* Address. */
-               void    (*a_fcn)(void); /* Function pointer (not used). */
-       } a_un;
-} Elf32_Auxinfo;
-
-#if __ELF_WORD_SIZE == 64
-/* Fake for amd64 loader support */
-typedef struct {
-       int fake;
-} Elf64_Auxinfo;
-#endif
-
-__ElfType(Auxinfo);
-
-/* Values for a_type. */
-#define        AT_NULL         0       /* Terminates the vector. */
-#define        AT_IGNORE       1       /* Ignored entry. */
-#define        AT_EXECFD       2       /* File descriptor of program to load. */
-#define        AT_PHDR         3       /* Program header of program already loaded. */
-#define        AT_PHENT        4       /* Size of each program header entry. */
-#define        AT_PHNUM        5       /* Number of program header entries. */
-#define        AT_PAGESZ       6       /* Page size in bytes. */
-#define        AT_BASE         7       /* Interpreter's base address. */
-#define        AT_FLAGS        8       /* Flags (unused for i386). */
-#define        AT_ENTRY        9       /* Where interpreter should transfer control. */
-#define        AT_NOTELF       10      /* Program is not ELF ?? */
-#define        AT_UID          11      /* Real uid. */
-#define        AT_EUID         12      /* Effective uid. */
-#define        AT_GID          13      /* Real gid. */
-#define        AT_EGID         14      /* Effective gid. */
-#define        AT_EXECPATH     15      /* Path to the executable. */
-#define        AT_CANARY       16      /* Canary for SSP. */
-#define        AT_CANARYLEN    17      /* Length of the canary. */
-#define        AT_OSRELDATE    18      /* OSRELDATE. */
-#define        AT_NCPUS        19      /* Number of CPUs. */
-#define        AT_PAGESIZES    20      /* Pagesizes. */
-#define        AT_PAGESIZESLEN 21      /* Number of pagesizes. */
-
-#define        AT_COUNT        22      /* Count of defined aux entry types. */
-
-/*
- * Relocation types.
- */
-
-#define        R_386_COUNT     38      /* Count of defined relocation types. */
-
 /* Define "machine" characteristics */
 #define        ELF_TARG_CLASS  ELFCLASS32
 #define        ELF_TARG_DATA   ELFDATA2LSB
 #define        ELF_TARG_MACH   EM_386
 #define        ELF_TARG_VER    1
 
-#define        ET_DYN_LOAD_ADDR 0x01001000
-
 #endif /* !_MACHINE_ELF_H_ */
index d995b5a8f8ea1377c4ad93986d51f034ddb501b5..3a95f6fd1555e34d94c7edbf64d06190b0e19688 100644 (file)
 #define PR_FORK_MSGADDR m1_p1  /* reply message address of forked child */
 #define PR_CTX_PTR     m1_p1   /* pointer to mcontext_t structure */
 
+/* Field names for EXEC sent from userland to PM. */
+#define PMEXEC_FLAGS   m1_i3   /* PMEF_* */
+
+#define PMEF_AUXVECTORS        20
+#define PMEF_AUXVECTORSPACE 0x01 /* space for PMEF_AUXVECTORS on stack */
+
 /* Flags for PR_FORK_FLAGS. */
 #define PFF_VMINHIBIT  0x01    /* Don't schedule until release by VM. */
 
                                         */
 #  define PM_FRAME             m7_p2   /* arguments and environment */
 #  define PM_FRAME_LEN         m7_i3   /* size of frame */
+#  define PM_EXECFLAGS         m7_i4   /* PMEXEC_FLAGS */
 
 /* Additional parameters for PM_EXEC_REPLY and PM_CORE_REPLY */
 #  define PM_STATUS            m7_i2   /* OK or failure */
 #  define PM_PC                        m7_p1   /* program counter */
+#  define PM_NEWSP             m7_p2   /* possibly-changed stack ptr */
 
 /* Additional parameters for PM_FORK and PM_SRV_FORK */
 #  define PM_PPROC             m7_i2   /* parent process endpoint */
index 50c82258402335290322a971241c8d40ac646554..16f7ef7744fec472e2506952bdcb150288094606 100644 (file)
@@ -47,9 +47,7 @@ INCSYMLINKS=\
        sys/sha1.h ${NETBSDINCSDIR}/sha1.h \
        sys/sha2.h ${NETBSDINCSDIR}/sha2.h \
        sys/md4.h ${NETBSDINCSDIR}/md4.h \
-       sys/md5.h ${NETBSDINCSDIR}/md5.h \
-       sys/exec_elf.h ${NETBSDINCSDIR}/elf.h \
-
+       sys/md5.h ${NETBSDINCSDIR}/md5.h 
 
 #INCSYMLINKS+= ../soundcard.h ${INCSDIR}/soundcard.h
 
index 70c7153ea3ae5543927931b3585197fdad91e2df..65fb69826c72bf99a4e3fe5fdfba399af159d3cd 100644 (file)
@@ -369,6 +369,7 @@ static void mb_extract_image(multiboot_info_t mbi)
 
        /* Save memory map for kernel tasks */
        r = read_header_elf((const char *)MULTIBOOT_KERNEL_ADDR,
+                               4096, /* everything is there */
                            &text_vaddr, &text_paddr,
                            &text_filebytes, &text_membytes,
                            &data_vaddr, &data_paddr,
@@ -401,6 +402,7 @@ static void mb_extract_image(multiboot_info_t mbi)
        /* Load boot image services into memory and save memory map */
        for (i = 0; module < &mb_module_info[mods_count]; ++module, ++i) {
            r = read_header_elf((const char *)module->mod_start,
+                               module->mod_end - module->mod_start + 1,
                                &text_vaddr, &text_paddr,
                                &text_filebytes, &text_membytes,
                                &data_vaddr, &data_paddr,
index 499448afa9853e3c94e05139f50f2235a8ab0d2a..06b5d1e45f58a8a6d90d7d8114a5b80ec5455eae 100644 (file)
@@ -10,6 +10,7 @@
 #include <unistd.h>
 #include <string.h>
 #include <stddef.h>
+#include <sys/exec_elf.h>
 
 #ifdef __weak_alias
 __weak_alias(execve, _execve)
@@ -23,6 +24,7 @@ int execve(const char *path, char * const *argv, char * const *envp)
        char **vp;
        char *sp;
        size_t argc;
+       int vectors;
        size_t frame_size;
        size_t string_off;
        size_t n;
@@ -55,9 +57,14 @@ int execve(const char *path, char * const *argv, char * const *envp)
                string_off+= sizeof(*ap);
        }
 
-       /* Add an argument count and two terminating nulls. */
-       frame_size+= sizeof(argc) + sizeof(*ap) + sizeof(*ep);
-       string_off+= sizeof(argc) + sizeof(*ap) + sizeof(*ep);
+       /* Add an argument count, two terminating nulls and
+        * space for the ELF aux vectors, that must come before
+        * (i.e. at a higher address) then the strings.
+        */
+       vectors = sizeof(argc) + sizeof(*ap) + sizeof(*ep) +
+               sizeof(AuxInfo) * PMEF_AUXVECTORS;
+       frame_size+= vectors;
+       string_off+= vectors;
 
        /* Align. */
        frame_size= (frame_size + sizeof(char *) - 1) & ~(sizeof(char *) - 1);
@@ -100,15 +107,17 @@ int execve(const char *path, char * const *argv, char * const *envp)
        /* Padding. */
        while (sp < frame + frame_size) *sp++= 0;
 
+       /* Clear unused message fields */
+       memset(&m, 0, sizeof(m));
+
        /* We can finally make the system call. */
        m.m1_i1 = strlen(path) + 1;
        m.m1_i2 = frame_size;
        m.m1_p1 = (char *) __UNCONST(path);
        m.m1_p2 = frame;
 
-       /* Clear unused fields */
-       m.m1_i3 = 0;
-       m.m1_p3 = NULL;
+       /* Tell PM/VFS we have left space for the aux vectors */
+       m.PMEXEC_FLAGS = PMEF_AUXVECTORSPACE;
 
        (void) _syscall(PM_PROC_NR, EXEC, &m);
 
index 03e3dc8eb64984082a5f7f26fa29303ad1ce3146..1f332685f30c0ab28cc62931a6d03f3b0dccba34 100644 (file)
@@ -7,6 +7,8 @@
 #include <unistd.h>
 #include <errno.h>
 #include <libexec.h>
+#include <string.h>
+#include <machine/elf.h>
 
 /* For verbose logging */
 #define ELF_DEBUG 0
 
 #define SECTOR_SIZE 512
 
-static int __elfN(check_header)(const Elf_Ehdr *hdr);
+static int check_header(const Elf_Ehdr *hdr);
+
+static int elf_sane(const Elf_Ehdr *hdr)
+{
+  if (check_header(hdr) != OK) {
+     return 0;
+  }
+
+  if((hdr->e_type != ET_EXEC) && (hdr->e_type != ET_DYN)) {
+     return 0;
+  }
+
+  if ((hdr->e_phoff > SECTOR_SIZE) ||
+      (hdr->e_phoff + hdr->e_phentsize * hdr->e_phnum) > SECTOR_SIZE) {
+#if ELF_DEBUG
+       printf("peculiar phoff\n");
+#endif
+     return 0;
+  }
+
+  return 1;
+}
+
+static int elf_ph_sane(const Elf_Phdr *phdr)
+{
+  if (rounddown((uintptr_t)phdr, sizeof(Elf_Addr)) != (uintptr_t)phdr) {
+     return 0;
+  }
+  return 1;
+}
+
+static int elf_unpack(const char *exec_hdr,
+       int hdr_len, const Elf_Ehdr **hdr, const Elf_Phdr **phdr)
+{
+  *hdr = (const Elf_Ehdr *)exec_hdr;
+  if(!elf_sane(*hdr)) {
+#if ELF_DEBUG
+       printf("elf_sane failed\n");
+#endif
+       return ENOEXEC;
+  }
+  *phdr = (const Elf_Phdr *)(exec_hdr + (*hdr)->e_phoff);
+  if(!elf_ph_sane(*phdr)) {
+#if ELF_DEBUG
+       printf("elf_ph_sane failed\n");
+#endif
+       return ENOEXEC;
+  }
+#if 0
+  if((int)((*phdr) + (*hdr)->e_phnum) >= hdr_len) return ENOEXEC;
+#endif
+  return OK;
+}
 
 int read_header_elf(
   const char *exec_hdr,                /* executable header */
+  int hdr_len,                 /* significant bytes in exec_hdr */
   vir_bytes *text_vaddr,       /* text virtual address */
   phys_bytes *text_paddr,      /* text physical address */
   vir_bytes *text_filebytes,   /* text segment size (in the file) */
@@ -36,7 +91,7 @@ int read_header_elf(
   const Elf_Ehdr *hdr = NULL;
   const Elf_Phdr *phdr = NULL;
   unsigned long seg_filebytes, seg_membytes;
-  int i = 0;
+  int e, i = 0;
 
   *text_vaddr = *text_paddr = 0;
   *text_filebytes = *text_membytes = 0;
@@ -44,27 +99,12 @@ int read_header_elf(
   *data_filebytes = *data_membytes = 0;
   *pc = *text_offset = *data_offset = 0;
 
-  hdr = (const Elf_Ehdr *)exec_hdr;
-  if (__elfN(check_header)(hdr) != OK || (hdr->e_type != ET_EXEC))
-  {
-     return ENOEXEC;
-  }
-
-  if ((hdr->e_phoff > SECTOR_SIZE) ||
-      (hdr->e_phoff + hdr->e_phentsize * hdr->e_phnum) > SECTOR_SIZE) {
-     return ENOEXEC;
-  }
-
-  phdr = (const Elf_Phdr *)(exec_hdr + hdr->e_phoff);
-  if (
-#ifdef __NBSD_LIBC
-      rounddown((uintptr_t)phdr, sizeof(Elf_Addr)) != (uintptr_t)phdr
-#else
-      !_minix_aligned(hdr->e_phoff, Elf_Addr)
+  if((e=elf_unpack(exec_hdr, hdr_len, &hdr, &phdr)) != OK) {
+#if ELF_DEBUG
+       printf("elf_unpack failed\n");
 #endif
-     ) {
-     return ENOEXEC;
-  }
+       return e;
+   }
 
 #if ELF_DEBUG
   printf("Program header file offset (phoff): %ld\n", hdr->e_phoff);
@@ -124,7 +164,12 @@ int read_header_elf(
   return OK;
 }
 
-static int __elfN(check_header)(const Elf_Ehdr *hdr)
+#define IS_ELF(ehdr)   ((ehdr).e_ident[EI_MAG0] == ELFMAG0 && \
+                        (ehdr).e_ident[EI_MAG1] == ELFMAG1 && \
+                        (ehdr).e_ident[EI_MAG2] == ELFMAG2 && \
+                        (ehdr).e_ident[EI_MAG3] == ELFMAG3)
+
+static int check_header(const Elf_Ehdr *hdr)
 {
   if (!IS_ELF(*hdr) ||
       hdr->e_ident[EI_DATA] != ELF_TARG_DATA ||
@@ -135,3 +180,66 @@ static int __elfN(check_header)(const Elf_Ehdr *hdr)
 
   return OK;
 }
+
+int elf_phdr(const char *exec_hdr, int hdr_len, vir_bytes *ret_phdr)
+{
+  const Elf_Ehdr *hdr = NULL;
+  const Elf_Phdr *phdr = NULL;
+  int e, i, have_computed_phdr = 1;
+
+  if((e=elf_unpack(exec_hdr, hdr_len, &hdr, &phdr)) != OK) return e;
+
+  for (i = 0; i < hdr->e_phnum; i++) {
+      switch (phdr[i].p_type) {
+      case PT_LOAD:
+               /* compute phdr based on this heuristic, to be used
+                * if there is no PT_PHDR
+                */
+               if(phdr[i].p_offset == 0) {
+                       *ret_phdr = phdr[i].p_vaddr + hdr->e_phoff;
+                       have_computed_phdr = 1;
+               }
+               break;
+      case PT_PHDR:
+         *ret_phdr = phdr[i].p_vaddr;
+         return OK;
+      default:
+         break;;
+      }
+  }
+  if(have_computed_phdr) return OK;
+  return ENOENT;
+}
+
+/* Return >0 if there is an ELF interpreter (i.e. it is a dynamically linked
+ * executable) and we could extract it successfully.
+ * Return 0 if there isn't one.
+ * Return <0 on error.
+ */
+int elf_has_interpreter(const char *exec_hdr,          /* executable header */
+               int hdr_len, char *interp, int maxsz)
+{
+  const Elf_Ehdr *hdr = NULL;
+  const Elf_Phdr *phdr = NULL;
+  int e, i;
+
+  if((e=elf_unpack(exec_hdr, hdr_len, &hdr, &phdr)) != OK) return e;
+
+  for (i = 0; i < hdr->e_phnum; i++) {
+      switch (phdr[i].p_type) {
+      case PT_INTERP:
+         if(!interp) return 1;
+         if(phdr[i].p_filesz >= maxsz)
+               return -1;
+         if(phdr[i].p_offset + phdr[i].p_filesz >= hdr_len)
+               return -1;
+         memcpy(interp, exec_hdr + phdr[i].p_offset, phdr[i].p_filesz);
+         interp[phdr[i].p_filesz] = '\0';
+         return 1;
+      default:
+         continue;
+      }
+  }
+  return 0;
+}
+
index abe51df260c883c68b40cdd38ba156cecc365a7f..8829225594bca54ade73390782b4734f1e89a4c1 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef _LIBEXEC_H_
 #define _LIBEXEC_H_ 1
 
-#include <machine/elf.h>
+#include <sys/exec_elf.h>
 
 /* a.out routines */
 int read_header_aout(const char *exec_hdr, size_t exec_len, int *sep_id,
@@ -10,11 +10,14 @@ int read_header_aout(const char *exec_hdr, size_t exec_len, int *sep_id,
    int *hdrlenp);
 
 /* ELF routines */
-int read_header_elf(const char *exec_hdr,
+int read_header_elf(const char *exec_hdr, int hdr_len,
    vir_bytes *text_vaddr, phys_bytes *text_paddr,
    vir_bytes *text_filebytes, vir_bytes *text_membytes,
    vir_bytes *data_vaddr, phys_bytes *data_paddr,
    vir_bytes *data_filebytes, vir_bytes *data_membytes,
    vir_bytes *pc, off_t *text_offset, off_t *data_offset);
 
+int elf_has_interpreter(const char *exec_hdr, int hdr_len, char *interp, int maxsz);
+int elf_phdr(const char *exec_hdr, int hdr_len, vir_bytes *phdr);
+
 #endif /* !_LIBEXEC_H_ */
index 42feec03db46000904bb2e9b39518bbb3200a171..179d9a9a63440fe88ac2f3c28254b074e2a50408 100644 (file)
@@ -38,7 +38,11 @@ M=           ${.CURDIR}/arch/${ARCHSUBDIR}
      (${MACHINE_ARCH} == "vax")) &&                                    \
     ${MKPIC} != "no"
 
+.if ${CC} == "gcc"
 LDFLAGS+=      -shared -symbolic -nostartfiles
+.else
+LDFLAGS+=      -shared -Wl,-Bsymbolic -nostartfiles
+.endif
 LDFLAGS+=      -Wl,-static
 LDFLAGS+=      -Wl,--warn-shared-textrel
 
index 71cc85335d1b6d1139a42572d9ecdfc4298ec221..9771b80dc18fdabb4e1edd571cdf8056f1252508 100644 (file)
@@ -53,6 +53,53 @@ static int protflags(int);   /* Elf flags -> mmap protection */
 
 #define EA_UNDEF               (~(Elf_Addr)0)
 
+#ifdef __minix
+#define mmap   minix_mmap_emulator
+#define munmap minix_munmap
+
+/* for minix, ignore MAP_SHARED and MAP_FILE for now. */
+#define MAP_SHARED 0
+#define MAP_FILE 0
+#endif
+
+#undef MINIXVERBOSE
+
+static void * minix_mmap_emulator(void *addrhint, size_t size, int prot, int flags, int fd, off_t off)
+{
+       void *ret;
+       int mapflags;
+       size_t s;
+
+       mapflags = flags & (MAP_FIXED);
+
+#ifdef MINIXVERBOSE
+       if(addrhint) {
+               fprintf(stderr, "0x%lx-0x%lx requested\n", addrhint,
+                       (char *) addrhint + size);
+       }
+#endif
+
+       if((ret = minix_mmap(addrhint, size, PROT_READ|PROT_WRITE,
+               MAP_ANON|MAP_PRIVATE|MAP_PREALLOC|mapflags, -1, 0)) == MAP_FAILED) {
+               return ret;
+       }
+
+       if(!(mapflags & MAP_ANON)) {
+               if((s=pread(fd, ret, size, off)) <= 0) {
+                       munmap(ret, size);
+                       return MAP_FAILED;
+               }
+       }
+
+#ifdef MINIXVERBOSE
+       fprintf(stderr, "0x%lx-0x%lx mapped\n",
+               ret, (char *) ret + size);
+
+#endif
+
+       return ret;
+}
+
 /*
  * Map a shared object into memory.  The argument is a file descriptor,
  * which must be open on the object and positioned at its beginning.
@@ -296,8 +343,15 @@ _rtld_map_object(const char *path, int fd, const struct stat *sb)
        base_addr = NULL;
 #endif
        mapsize = base_vlimit - base_vaddr;
+
+#ifndef __minix
        mapbase = mmap(base_addr, mapsize, text_flags,
            mapflags | MAP_FILE | MAP_PRIVATE, fd, base_offset);
+#else
+       /* minix doesn't want overlapping mmap()s */
+       mapbase = mmap(base_addr, obj->textsize, text_flags,
+           mapflags | MAP_FILE | MAP_PRIVATE, fd, base_offset);
+#endif
        if (mapbase == MAP_FAILED) {
                _rtld_error("mmap of entire address space failed: %s",
                    xstrerror(errno));
index 4768363ca54de76b8c9c98976359c33ea3c10da3..785b544e5ce1ab88a6c9c51f98301fdf933d13f0 100644 (file)
@@ -47,6 +47,7 @@ int do_exec()
        m.PM_PATH_LEN = m_in.exec_len;
        m.PM_FRAME = m_in.frame_ptr;
        m.PM_FRAME_LEN = m_in.frame_len;
+       m.PM_EXECFLAGS = m_in.PMEXEC_FLAGS;
 
        tell_vfs(mp, &m);
 
@@ -148,7 +149,7 @@ int do_execrestart()
        result= m_in.EXC_RS_RESULT;
        pc= (vir_bytes)m_in.EXC_RS_PC;
 
-       exec_restart(rmp, result, pc);
+       exec_restart(rmp, result, pc, rmp->mp_frame_addr);
 
        return OK;
 }
@@ -157,13 +158,13 @@ int do_execrestart()
 /*===========================================================================*
  *                             exec_restart                                 *
  *===========================================================================*/
-void exec_restart(rmp, result, pc)
+void exec_restart(rmp, result, pc, vfs_newsp)
 struct mproc *rmp;
 int result;
 vir_bytes pc;
+vir_bytes vfs_newsp;
 {
        int r, sn;
-       char *new_sp;
 
        if (result != OK)
        {
@@ -202,8 +203,8 @@ vir_bytes pc;
        }
 #endif /* USE_TRACE */
 
-       new_sp= (char *)rmp->mp_frame_addr;
-       r= sys_exec(rmp->mp_endpoint, new_sp, rmp->mp_name, pc);
+       /* Call kernel to exec with SP and PC set by VFS. */
+       r= sys_exec(rmp->mp_endpoint, (char *) vfs_newsp, rmp->mp_name, pc);
        if (r != OK) panic("sys_exec failed: %d", r);
 }
 
index 221a63021b8c85021a52d31f32cf7e0d7f29c1e5..45796594ca440e7b5c78bcd8c8b2e189a4ae75dd 100644 (file)
@@ -447,7 +447,8 @@ static void handle_vfs_reply()
        break;
 
   case PM_EXEC_REPLY:
-       exec_restart(rmp, m_in.PM_STATUS, (vir_bytes)m_in.PM_PC);
+       exec_restart(rmp, m_in.PM_STATUS, (vir_bytes)m_in.PM_PC,
+               (vir_bytes)m_in.PM_NEWSP);
 
        break;
 
index 4eef4b4c468f6bbe86d80dcd22d52f0d644d0416..76148ae971393d53cfa08a4e58b01c441d2333a8 100644 (file)
@@ -20,7 +20,7 @@ int do_brk(void);
 int do_exec(void);
 int do_exec_newmem(void);
 int do_execrestart(void);
-void exec_restart(struct mproc *rmp, int result, vir_bytes pc);
+void exec_restart(struct mproc *rmp, int result, vir_bytes pc, vir_bytes sp);
 
 /* forkexit.c */
 int do_fork(void);
index a706d0d9df24e5dacd46fde2b9698215520bdad4..0ff1f4a84842b36a9fb446ad8ae700d1c49d3fb2 100644 (file)
@@ -253,7 +253,7 @@ static int load_elf(struct exec_info *execi)
   proc_e = execi->proc_e;
 
   /* Read the file header and extract the segment sizes. */
-  r = read_header_elf(execi->image, &text_vaddr, &text_paddr,
+  r = read_header_elf(execi->image, execi->image_len, &text_vaddr, &text_paddr,
                      &text_filebytes, &text_membytes,
                      &data_vaddr, &data_paddr,
                      &data_filebytes, &data_membytes,
@@ -262,6 +262,11 @@ static int load_elf(struct exec_info *execi)
       return(r);
   }
 
+  if(elf_has_interpreter(execi->image, execi->image_len, NULL, 0)) {
+       printf("RS: can't execute dynamically linked executables\n");
+       return ENOEXEC;
+  }
+
   new_uid= getuid();
   new_gid= getgid();
   allow_setuid = 0;
index 0fa1bc4d6bf2d8e1930e5e14f16e106910aa2ab8..37e24d024ec90f3aa9c932ee3e3b7af3e2bc1f90 100644 (file)
@@ -4,11 +4,12 @@
 #include "fproc.h"
 #include <minix/vm.h>
 #include <sys/mman.h>
-#include <machine/elf.h>
+#include <sys/exec_elf.h>
 #include "param.h"
 
 /* Include ELF headers */
 #include <sys/elf_core.h>
+#include <machine/elf.h>
 
 static void fill_elf_header(Elf32_Ehdr *elf_header, int phnum);
 static void fill_prog_header(Elf32_Phdr *prog_header, Elf32_Word
index 0de11270de2a529f4c7e03de43a9a4079ecff3bc..3898588726e49a1817e614f6a2e18f2ebea8797d 100644 (file)
 #include "param.h"
 #include "vnode.h"
 #include <minix/vfsif.h>
+#include <machine/vmparam.h>
 #include <assert.h>
-#include <libexec.h>
+#include <fcntl.h>
 #include "exec.h"
 
+#define _KERNEL        /* for ELF_AUX_ENTRIES */
+#include <libexec.h>
+
 static void lock_exec(void);
 static void unlock_exec(void);
 static int exec_newmem(int proc_e, vir_bytes text_addr, vir_bytes text_bytes,
@@ -42,9 +46,9 @@ static int exec_newmem(int proc_e, vir_bytes text_addr, vir_bytes text_bytes,
        vir_bytes frame_len, int sep_id, int is_elf, dev_t st_dev,
        ino_t st_ino, time_t ctime, char *progname, int new_uid, int new_gid,
        vir_bytes *stack_topp, int *load_textp, int *setugidp);
-static int is_script(const char *exec_hdr, size_t exec_len);
 static int patch_stack(struct vnode *vp, char stack[ARG_MAX],
        size_t *stk_bytes, char path[PATH_MAX]);
+static int is_script(struct exec_info *execi);
 static int insert_arg(char stack[ARG_MAX], size_t *stk_bytes, char *arg,
        int replace);
 static void patch_ptr(char stack[ARG_MAX], vir_bytes base);
@@ -53,23 +57,27 @@ static int read_seg(struct vnode *vp, off_t off, int proc_e, int seg,
        vir_bytes seg_addr, phys_bytes seg_bytes);
 static int load_aout(struct exec_info *execi);
 static int load_elf(struct exec_info *execi);
-static int map_header(char **exec_hdr, const struct vnode *vp);
+static int stack_prepare_elf(struct exec_info *execi,
+       char *curstack, size_t *frame_len, int *extrabase);
+static int map_header(struct exec_info *execi);
 
 #define PTRSIZE        sizeof(char *) /* Size of pointers in argv[] and envp[]. */
 
 /* Array of loaders for different object file formats */
+typedef int (*exechook_t)(struct exec_info *execpackage);
+typedef int (*stackhook_t)(struct exec_info *execi, char *curstack,
+       size_t *frame_len, int *extrabase);
 struct exec_loaders {
-       int (*load_object)(struct exec_info *);
+       exechook_t load_object;  /* load executable into memory */
+       stackhook_t setup_stack; /* prepare stack before argc and argv push */
 };
 
 static const struct exec_loaders exec_loaders[] = {
-       { load_aout },
-       { load_elf },
-       { NULL }
+       { load_aout, NULL },
+       { load_elf,  stack_prepare_elf },
+       { NULL, NULL }
 };
 
-static char hdr[PAGE_SIZE]; /* Assume that header is not larger than a page */
-
 /*===========================================================================*
  *                             lock_exec                                    *
  *===========================================================================*/
@@ -101,112 +109,186 @@ static void unlock_exec(void)
        panic("Could not release lock on exec");
 }
 
+/*===========================================================================*
+ *                             get_read_vp                                  *
+ *===========================================================================*/
+static int get_read_vp(struct exec_info *execi, char *fullpath,
+       int copyprogname, int sugid, struct lookup *resolve, struct fproc *fp)
+{
+/* Make the executable that we want to exec() into the binary pointed
+ * to by 'fullpath.' This function fills in necessary details in the execi
+ * structure, such as opened vnode. It unlocks and releases the vnode if
+ * it was already there. This makes it easy to change the executable
+ * during the exec(), which is often necessary, by calling this function
+ * more than once. This is specifically necessary when we discover the
+ * executable is actually a script or a dynamically linked executable.
+ */
+       int r;
+
+       /* Caller wants to switch vp to the file in 'fullpath.'
+        * unlock and put it first if there is any there.
+        */
+       if(execi->vp) {
+               unlock_vnode(execi->vp);
+               put_vnode(execi->vp);
+               execi->vp = NULL;
+       }
+
+       /* Remember/overwrite the executable name if requested. */
+       if(copyprogname) {
+               char *cp = strrchr(fullpath, '/');
+               if(cp) cp++;
+               else cp = fullpath;
+               strncpy(execi->progname, cp, sizeof(execi->progname)-1);
+               execi->progname[sizeof(execi->progname)-1] = '\0';
+       }
+
+       /* Open executable */
+       if ((execi->vp = eat_path(resolve, fp)) == NULL)
+               return err_code;
+
+       unlock_vmnt(execi->vmp);
+
+       if ((execi->vp->v_mode & I_TYPE) != I_REGULAR)
+               return ENOEXEC;
+       else if ((r = forbidden(fp, execi->vp, X_BIT)) != OK)
+               return r;
+       else
+               r = req_stat(execi->vp->v_fs_e, execi->vp->v_inode_nr,
+                       VFS_PROC_NR, (vir_bytes) &(execi->sb), 0, 0);
+
+       if (r != OK) return r;
+
+       /* If caller wants us to, honour suid/guid mode bits. */
+        if (sugid) {
+               /* Deal with setuid/setgid executables */
+               if (execi->vp->v_mode & I_SET_UID_BIT) {
+                       execi->new_uid = execi->vp->v_uid;
+                       execi->setugid = 1;
+               }
+               if (execi->vp->v_mode & I_SET_GID_BIT) {
+                       execi->new_gid = execi->vp->v_gid;
+                       execi->setugid = 1;
+               }
+        }
+
+       /* Read in first chunk of file. */
+       if((r=map_header(execi)) != OK)
+               return r;
+
+       return OK;
+}
+
+#define FAILCHECK(expr) if((r=(expr)) != OK) { goto pm_execfinal; } while(0)
+#define Get_read_vp(e,f,p,s,rs,fp) do { \
+       r=get_read_vp(&e,f,p,s,rs,fp); if(r != OK) { FAILCHECK(r); }    \
+       } while(0)
+
 /*===========================================================================*
  *                             pm_exec                                      *
  *===========================================================================*/
 int pm_exec(endpoint_t proc_e, vir_bytes path, size_t path_len,
-                  vir_bytes frame, size_t frame_len, vir_bytes *pc)
+                  vir_bytes frame, size_t frame_len, vir_bytes *pc,
+                  vir_bytes *newsp, int user_exec_flags)
 {
 /* Perform the execve(name, argv, envp) call.  The user library builds a
  * complete stack image, including pointers, args, environ, etc.  The stack
  * is copied to a buffer inside VFS, and then to the new core image.
  */
-  int r, r1, round, slot;
+  int r, slot;
   vir_bytes vsp;
   struct fproc *rfp;
-  struct vnode *vp;
-  struct vmnt *vmp;
-  char *cp;
+  int extrabase = 0;
   static char mbuf[ARG_MAX];   /* buffer for stack and zeroes */
   struct exec_info execi;
   int i;
-  char fullpath[PATH_MAX];
+  static char fullpath[PATH_MAX],
+       elf_interpreter[PATH_MAX],
+       finalexec[PATH_MAX];
   struct lookup resolve;
+  stackhook_t makestack = NULL;
 
   lock_exec();
 
+  /* unset execi values are 0. */
+  memset(&execi, 0, sizeof(execi));
+
+  /* passed from exec() libc code */
+  execi.userflags = user_exec_flags;
+
   okendpt(proc_e, &slot);
   rfp = fp = &fproc[slot];
-  vp = NULL;
 
-  lookup_init(&resolve, fullpath, PATH_NOFLAGS, &vmp, &vp);
+  lookup_init(&resolve, fullpath, PATH_NOFLAGS, &execi.vmp, &execi.vp);
   resolve.l_vmnt_lock = VMNT_READ;
   resolve.l_vnode_lock = VNODE_READ;
 
-  /* Get the exec file name. */
-  if ((r = fetch_name(path, path_len, fullpath)) != OK)
-       goto pm_execfinal;
-
   /* Fetch the stack from the user before destroying the old core image. */
-  if (frame_len > ARG_MAX) {
-               r = ENOMEM; /* stack too big */
-               goto pm_execfinal;
-  }
+  if (frame_len > ARG_MAX)
+       FAILCHECK(ENOMEM); /* stack too big */
+
   r = sys_datacopy(proc_e, (vir_bytes) frame, SELF, (vir_bytes) mbuf,
                   (size_t) frame_len);
   if (r != OK) { /* can't fetch stack (e.g. bad virtual addr) */
         printf("VFS: pm_exec: sys_datacopy failed\n");
-        goto pm_execfinal;
+       FAILCHECK(r);
   }
 
   /* The default is to keep the original user and group IDs */
   execi.new_uid = rfp->fp_effuid;
   execi.new_gid = rfp->fp_effgid;
 
-  for (round = 0; round < 2; round++) {
-       /* round = 0 (first attempt), or 1 (interpreted script) */
-       /* Save the name of the program */
-       (cp = strrchr(fullpath, '/')) ? cp++ : (cp = fullpath);
-
-       strncpy(execi.progname, cp, PROC_NAME_LEN-1);
-       execi.progname[PROC_NAME_LEN-1] = '\0';
-       execi.setugid = 0;
+  /* Get the exec file name. */
+  FAILCHECK(fetch_name(path, path_len, fullpath));
+  strcpy(finalexec, fullpath);
+
+  /* Get_read_vp will return an opened vn in execi.
+   * if necessary it releases the existing vp so we can
+   * switch after we find out what's inside the file.
+   * It reads the start of the file.
+   */
+  Get_read_vp(execi, fullpath, 1, 1, &resolve, fp);
+
+  /* If this is a script (i.e. has a #!/interpreter line),
+   * retrieve the name of the interpreter and open that
+   * executable instead.
+   */
+  if(is_script(&execi)) {
+       /* patch_stack will add interpreter name and
+        * args to stack and retrieve the new binary
+        * name into fullpath.
+        */
+       FAILCHECK(fetch_name(path, path_len, fullpath));
+       FAILCHECK(patch_stack(execi.vp, mbuf, &frame_len, fullpath));
+       strcpy(finalexec, fullpath);
+       Get_read_vp(execi, fullpath, 1, 0, &resolve, fp);
+  }
 
-       /* Open executable */
-       if ((vp = eat_path(&resolve, fp)) == NULL) {
-               r = err_code;
-               goto pm_execfinal;
+  /* If this is a dynamically linked executable, retrieve
+   * the name of that interpreter in elf_interpreter and open that
+   * executable instead. But open the current executable in an
+   * fd for the current process.
+   */
+  if(elf_has_interpreter(execi.hdr, execi.hdr_len,
+       elf_interpreter, sizeof(elf_interpreter))) {
+       /* Switch the executable vnode to the interpreter */
+       execi.is_dyn = 1;
+
+       /* The interpreter (loader) needs an fd to the main program,
+        * which is currently in finalexec
+        */
+       if((r = execi.elf_main_fd = common_open(finalexec, O_RDONLY, 0)) < 0) {
+               printf("VFS: exec: dynamic: open main exec failed %s (%d)\n",
+                       fullpath, r);
+               FAILCHECK(r);
        }
-       execi.vp = vp;
-       unlock_vmnt(vmp);
-
-       if ((vp->v_mode & I_TYPE) != I_REGULAR)
-               r = ENOEXEC;
-       else if ((r1 = forbidden(fp, vp, X_BIT)) != OK)
-               r = r1;
-       else
-               r = req_stat(vp->v_fs_e, vp->v_inode_nr, VFS_PROC_NR,
-                            (vir_bytes) &(execi.sb), 0, 0);
-       if (r != OK) goto pm_execfinal;
-
-        if (round == 0) {
-               /* Deal with setuid/setgid executables */
-               if (vp->v_mode & I_SET_UID_BIT) {
-                       execi.new_uid = vp->v_uid;
-                       execi.setugid = 1;
-               }
-               if (vp->v_mode & I_SET_GID_BIT) {
-                       execi.new_gid = vp->v_gid;
-                       execi.setugid = 1;
-               }
-        }
-
-       r = map_header(&execi.hdr, execi.vp);
-       if (r != OK) goto pm_execfinal;
 
-       if (!is_script(execi.hdr, execi.vp->v_size) || round != 0)
-               break;
-
-       /* Get fresh copy of the file name. */
-       if ((r = fetch_name(path, path_len, fullpath)) != OK)
-               printf("VFS pm_exec: 2nd fetch_name failed\n");
-       else
-               r = patch_stack(vp, mbuf, &frame_len, fullpath);
-
-       unlock_vnode(vp);
-       put_vnode(vp);
-       vp = NULL;
-       if (r != OK) goto pm_execfinal;
+       /* The executable we need to execute first (loader)
+        * is in elf_interpreter, and has to be in fullpath to
+        * be looked up
+        */
+       strcpy(fullpath, elf_interpreter);
+       Get_read_vp(execi, fullpath, 0, 0, &resolve, fp);
   }
 
   execi.proc_e = proc_e;
@@ -215,28 +297,27 @@ int pm_exec(endpoint_t proc_e, vir_bytes path, size_t path_len,
   for (i = 0; exec_loaders[i].load_object != NULL; i++) {
       r = (*exec_loaders[i].load_object)(&execi);
       /* Loaded successfully, so no need to try other loaders */
-      if (r == OK) break;
+      if (r == OK) { makestack = exec_loaders[i].setup_stack; break; }
   }
 
-  if (r != OK) {   /* No exec loader could load the object */
-       r = ENOEXEC;
-       goto pm_execfinal;
-  }
+  FAILCHECK(r);
 
   /* Save off PC */
   *pc = execi.pc;
 
-  /* Patch up stack and copy it from VFS to new core image. */
+  /* call a stack-setup function if this executable type wants it */
   vsp = execi.stack_top;
+  if(makestack) FAILCHECK(makestack(&execi, mbuf, &frame_len, &extrabase));
+
+  /* Patch up stack and copy it from VFS to new core image. */
   vsp -= frame_len;
-  patch_ptr(mbuf, vsp);
-  if ((r = sys_datacopy(SELF, (vir_bytes) mbuf, proc_e, (vir_bytes) vsp,
-                  (phys_bytes)frame_len)) != OK) {
-       printf("VFS: datacopy failed (%d) trying to copy to %lu\n", r, vsp);
-       goto pm_execfinal;
-  }
+  patch_ptr(mbuf, vsp + extrabase);
+  FAILCHECK(sys_datacopy(SELF, (vir_bytes) mbuf, proc_e, (vir_bytes) vsp,
+                  (phys_bytes)frame_len));
+  
+  /* Return new stack pointer to caller */
+  *newsp = vsp;
 
-  if (r != OK) goto pm_execfinal;
   clo_exec(rfp);
 
   if (execi.setugid) {
@@ -246,10 +327,13 @@ int pm_exec(endpoint_t proc_e, vir_bytes path, size_t path_len,
        rfp->fp_effgid = execi.new_gid;
   }
 
+  /* Remember the new name of the process */
+  strcpy(rfp->fp_name, execi.progname);
+
 pm_execfinal:
-  if (vp != NULL) {
-       unlock_vnode(vp);
-       put_vnode(vp);
+  if (execi.vp != NULL) {
+       unlock_vnode(execi.vp);
+       put_vnode(execi.vp);
   }
   unlock_exec();
   return(r);
@@ -306,6 +390,79 @@ static int load_aout(struct exec_info *execi)
   return(r);
 }
 
+static int stack_prepare_elf(struct exec_info *execi, char *frame, size_t *framelen, int *extrabase)
+{
+       AuxInfo *a;
+       Elf_Ehdr *elf_header;
+       int nulls;
+       char    **mysp = (char **) frame,
+               **mysp_end = (char **) ((char *)frame + *framelen);
+
+       if(!execi->is_dyn)
+               return OK;
+
+       assert(execi->hdr_len >= sizeof(*elf_header));
+       elf_header = (Elf_Ehdr *) execi->hdr;
+
+       /* exec() promises stack space. Now find it. */
+       mysp++; /* skip argc */
+
+       /* find a terminating NULL entry twice: one for argv[], one for envp[]. */
+       for(nulls = 0; nulls < 2; nulls++) {
+               assert(mysp < mysp_end);
+               while(*mysp && mysp < mysp_end) mysp++; /* find terminating NULL */
+               if(mysp >= mysp_end) {
+                       printf("VFS: malformed stack for exec()\n");
+                       return ENOEXEC;
+               }
+               assert(!*mysp);
+               mysp++;
+       }
+
+       /* Userland provides a fully filled stack frame, with argc, argv, envp
+        * and then all the argv and envp strings; consistent with ELF ABI, except
+        * for a list of Aux vectors that should be between envp points and the
+        * start of the strings.
+        *
+        * It would take some very unpleasant hackery to insert the aux vectors before
+        * the strings, and correct all the pointers, so the exec code in libc makes
+        * space for us first and indicates the fact it did this with this flag.
+        */
+       if(!(execi->userflags & PMEF_AUXVECTORSPACE)) {
+               char *f = (char *) mysp;
+               int remain;
+               vir_bytes extrabytes = sizeof(*a) * PMEF_AUXVECTORS;
+               
+               /* Create extrabytes more space */
+               remain = *framelen - (int)(f - frame);
+               if(*framelen + extrabytes >= ARG_MAX)
+                       return ENOMEM;
+               *framelen += extrabytes;
+               *extrabase += extrabytes;
+               memmove(f+extrabytes, f, remain);
+               memset(f, 0, extrabytes);
+       }
+
+       /* Ok, what mysp points to now we can use for the aux vectors. */
+       a = (AuxInfo *) mysp;
+#define AUXINFO(type, value) \
+       { assert((char *) a < (char *) mysp_end); a->a_type = type; a->a_v = value; a++; }
+#if 0
+       AUXINFO(AT_PHDR, execi->elf_phdr);
+       AUXINFO(AT_PHENT, elf_header->e_phentsize);
+       AUXINFO(AT_PHNUM, elf_header->e_phnum);
+#endif
+       AUXINFO(AT_BASE, execi->elf_base);
+       AUXINFO(AT_ENTRY, execi->pc);
+       AUXINFO(AT_PAGESZ, PAGE_SIZE);
+       AUXINFO(AT_EXECFD, execi->elf_main_fd);
+
+       /* Always terminate with AT_NULL */
+       AUXINFO(AT_NULL, 0);
+
+       return OK;
+}
+
 /*===========================================================================*
  *                             load_elf                                     *
  *===========================================================================*/
@@ -318,7 +475,8 @@ static int load_elf(struct exec_info *execi)
   vir_bytes text_vaddr, text_paddr, text_filebytes, text_membytes;
   vir_bytes data_vaddr, data_paddr, data_filebytes, data_membytes;
   off_t text_offset, data_offset;
-  int sep_id, is_elf;
+  int sep_id, is_elf, i;
+  vir_bytes text_base, data_base;
 
   assert(execi != NULL);
   assert(execi->hdr != NULL);
@@ -327,20 +485,39 @@ static int load_elf(struct exec_info *execi)
   proc_e = execi->proc_e;
   vp = execi->vp;
 
+  /* this function can load the dynamic linker, but that 
+   * shouldn't require an interpreter itself.
+   */
+  i = elf_has_interpreter(execi->hdr, execi->hdr_len, NULL, 0);
+  if(i > 0) {
+       printf("VFS: cannot load dynamically linked executable\n");
+       return ENOEXEC;
+  }
+
   /* Read the file header and extract the segment sizes. */
-  r = read_header_elf(execi->hdr, &text_vaddr, &text_paddr,
+  r = read_header_elf(execi->hdr, execi->hdr_len, &text_vaddr, &text_paddr,
                      &text_filebytes, &text_membytes,
                      &data_vaddr, &data_paddr,
                      &data_filebytes, &data_membytes,
                      &execi->pc, &text_offset, &data_offset);
-  if (r != OK) return(r);
+
+  if (r != OK) {
+       return(r);
+  }
+
+  if(elf_phdr(execi->hdr, execi->hdr_len, &execi->elf_phdr) == OK)
+       if(execi->elf_phdr == 0)        /* 0 should indicate: not known */
+               printf("VFS: warning: unexpected zero elf_phdr\n");
 
   sep_id = 0;
   is_elf = 1;
   tot_bytes = 0; /* Use default stack size */
+  text_base = trunc_page(text_vaddr);
+  data_base = trunc_page(data_vaddr);
+  execi->elf_base = MIN(text_base, data_base);
   r = exec_newmem(proc_e,
-                 trunc_page(text_vaddr), text_membytes,
-                 trunc_page(data_vaddr), data_membytes,
+                  text_base, text_membytes,
+                  data_base, data_membytes,
                  tot_bytes, execi->frame_len, sep_id, is_elf,
                  vp->v_dev, vp->v_inode_nr, execi->sb.st_ctime,
                  execi->progname, execi->new_uid, execi->new_gid,
@@ -424,12 +601,12 @@ static int exec_newmem(
 /*===========================================================================*
  *                             is_script                                    *
  *===========================================================================*/
-static int is_script(const char *exec_hdr, size_t exec_len)
+static int is_script(struct exec_info *execi)
 {
 /* Is Interpreted script? */
-  assert(exec_hdr != NULL);
+  assert(execi->hdr != NULL);
 
-  return(exec_hdr[0] == '#' && exec_hdr[1] == '!' && exec_len >= 2);
+  return(execi->hdr[0] == '#' && execi->hdr[1] == '!' && execi->hdr_len >= 2);
 }
 
 /*===========================================================================*
@@ -695,23 +872,27 @@ static void clo_exec(struct fproc *rfp)
 /*===========================================================================*
  *                             map_header                                   *
  *===========================================================================*/
-static int map_header(char **exec_hdr, const struct vnode *vp)
+static int map_header(struct exec_info *execi)
 {
   int r;
   u64_t new_pos;
   unsigned int cum_io;
   off_t pos;
+  static char hdr[PAGE_SIZE]; /* Assume that header is not larger than a page */
 
   pos = 0;     /* Read from the start of the file */
 
-  r = req_readwrite(vp->v_fs_e, vp->v_inode_nr, cvul64(pos), READING,
-                   VFS_PROC_NR, hdr, MIN(vp->v_size, PAGE_SIZE),
-                   &new_pos, &cum_io);
+  /* How much is sensible to read */
+  execi->hdr_len = MIN(execi->vp->v_size, sizeof(hdr));
+  execi->hdr = hdr;
+
+  r = req_readwrite(execi->vp->v_fs_e, execi->vp->v_inode_nr,
+       cvul64(pos), READING, VFS_PROC_NR, hdr,
+       execi->hdr_len, &new_pos, &cum_io);
   if (r != OK) {
        printf("VFS: exec: map_header: req_readwrite failed\n");
        return(r);
   }
 
-  *exec_hdr = hdr;
   return(OK);
 }
index ddf6e5a5fbb1bc0f29127b73ff843bec67a27cb2..63dfa37b072d1d393fac5c8373a7647c8ab997e1 100644 (file)
@@ -4,6 +4,7 @@
 struct exec_info {
     int  proc_e;                       /* Process endpoint */
     char *hdr;                         /* Exec file's header */
+    int hdr_len;                       /* How many bytes are in hdr */
     vir_bytes pc;                      /* Entry point of exec file */
     vir_bytes stack_top;               /* Top of the stack */
     vir_bytes frame_len;               /* Stack size */
@@ -12,8 +13,16 @@ struct exec_info {
     int load_text;                     /* Load text section? */
     int setugid;                       /* Allow set{u,g}id execution? */
     struct vnode *vp;                  /* Exec file's vnode */
+    struct vmnt *vmp;                  /* Exec file's vmnt */
     struct stat sb;                    /* Exec file's stat structure */
     char progname[PROC_NAME_LEN];      /* Program name */
+    int userflags;                     /* exec() flags from userland */
+
+    /* fields only used by elf and in VFS */
+    int is_dyn;                                /* Dynamically linked executable */
+    vir_bytes elf_phdr;                        /* Program header location */
+    vir_bytes elf_base;                        /* Userland addr load address */
+    int elf_main_fd;                   /* Dyn: FD of main program execuatble */
 };
 
 #endif /* !_VFS_EXEC_H_ */
index 79ede32f71e811c072d20c04ad1564bf457e282a..46115da5f6460ef514c3f1b3f874007ee468eb10 100644 (file)
@@ -46,6 +46,7 @@ EXTERN struct fproc {
   mutex_t fp_lock;             /* mutex to lock fproc object */
   struct job fp_job;           /* pending job */
   thread_t fp_wtid;            /* Thread ID of worker */
+  char fp_name[PROC_NAME_LEN]; /* Last exec() */
 #if LOCK_DEBUG
   int fp_vp_rdlocks;           /* number of read-only locks on vnodes */
   int fp_vmnt_rdlocks;         /* number of read-only locks on vmnts */
index f71ff1591495c7534077d5b3106a06fb0da03abd..ab17a32897bfc5435e14f9d7ca9fb1a07fbad391 100644 (file)
@@ -791,7 +791,7 @@ void reply(endpoint_t whom, int result)
 static void service_pm_postponed(void)
 {
   int r;
-  vir_bytes pc;
+  vir_bytes pc, newsp;
 
   switch(job_call_nr) {
     case PM_EXEC:
@@ -807,13 +807,14 @@ static void service_pm_postponed(void)
                stack_frame_len = (size_t) job_m_in.PM_FRAME_LEN;
 
                r = pm_exec(proc_e, exec_path, exec_path_len, stack_frame,
-                           stack_frame_len, &pc);
+                           stack_frame_len, &pc, &newsp, m_in.PM_EXECFLAGS);
 
                /* Reply status to PM */
                m_out.m_type = PM_EXEC_REPLY;
                m_out.PM_PROC = proc_e;
                m_out.PM_PC = (void*) pc;
                m_out.PM_STATUS = r;
+               m_out.PM_NEWSP = (void *) newsp;
        }
        break;
 
index 6cde7927c368b35fe33fea29466f0c74e2d450b9..0e11470a06613ef51361eedda6dce8589d3bcfa2 100644 (file)
@@ -70,8 +70,8 @@ int map_service(struct rprocpub *rpub);
 void write_elf_core_file(struct filp *f, int csig, char *exe_name);
 
 /* exec.c */
-int pm_exec(int proc_e, vir_bytes path, size_t path_len, vir_bytes frame,
-       size_t frame_len, vir_bytes *pc);
+int pm_exec(endpoint_t proc_e, vir_bytes path, size_t path_len, vir_bytes frame,
+       size_t frame_len, vir_bytes *pc, vir_bytes *newsp, int flags);
 #define check_bsf_lock() do {                                          \
        assert(mutex_trylock(&bsf_lock) == 0);                          \
        unlock_bsf();                                                   \