#define PAGE_SIZE (1 << PAGE_SHIFT)
#define PAGE_MASK (PAGE_SIZE - 1)
+/* As visible from the user space process, where is the top of the
+ * stack (first non-stack byte), when in paged mode?
+ */
+#define VM_STACKTOP 0x80000000
+
#endif /* _I386_VMPARAM_H_ */
#define CPROF 99 /* to PM */
/* Calls provided by PM and FS that are not part of the API */
-#define EXEC_NEWMEM 100 /* from VFS or RS to PM: new memory map for
- * exec
- */
+#define PM_NEWEXEC 100 /* from VFS or RS to PM: new exec */
#define SRV_FORK 101 /* to PM: special fork call for RS */
#define EXEC_RESTART 102 /* to PM: final part of exec for RS */
#define GETPROCNR 104 /* to PM */
#define _KMESS_BUF_SIZE 10000
+/* Default stack size (limit) */
+#define DEFAULT_STACK_LIMIT (64 * 1024 * 1024)
+
#endif /* _MINIX_SYS_CONFIG_H */
phys_bytes mr_limit; /* Highest memory address in range */
};
-/* For EXEC_NEWMEM */
-struct exec_newmem
-{
- vir_bytes text_addr; /* Starting address of text section */
- vir_bytes text_bytes; /* Length of text section (in bytes) */
- vir_bytes data_addr; /* Starting address of data section */
- vir_bytes data_bytes; /* Length of data section (in bytes) */
- vir_bytes tot_bytes; /* Minimum stack region size (in bytes) */
- vir_bytes args_bytes; /* Arguments/environ size on stack (in bytes) */
- int sep_id; /* Separate I&D? */
- int is_elf; /* Is ELF exe? */
- dev_t st_dev; /* Device holding executable file */
- ino_t st_ino; /* Inode of executable file */
- time_t enst_ctime; /* Last changed time of executable file */
- uid_t new_uid; /* Process UID after exec */
- gid_t new_gid; /* Process GID after exec */
- int setugid; /* Process is setuid or setgid */
- char progname[16]; /* Should be at least PROC_NAME_LEN */
-};
-
/* Memory chunks. */
struct memory {
phys_bytes base;
int vm_exit(endpoint_t ep);
int vm_fork(endpoint_t ep, int slotno, endpoint_t *child_ep);
int vm_brk(endpoint_t ep, char *newaddr);
-int vm_exec_newmem(endpoint_t ep, struct exec_newmem *args, int
- args_bytes, char **ret_stack_top, int *ret_flags);
int vm_push_sig(endpoint_t ep, vir_bytes *old_sp);
int vm_willexit(endpoint_t ep);
int vm_adddma(endpoint_t proc_e, phys_bytes start, phys_bytes size);
off_t text_offset, data_offset;
/* Save memory map for kernel tasks */
- r = read_header_elf((const char *)MULTIBOOT_KERNEL_ADDR,
+ r = read_header_elf((char *) MULTIBOOT_KERNEL_ADDR,
4096, /* everything is there */
&text_vaddr, &text_paddr,
&text_filebytes, &text_membytes,
/* 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,
+ r = read_header_elf((char *) module->mod_start,
module->mod_end - module->mod_start + 1,
&text_vaddr, &text_paddr,
&text_filebytes, &text_membytes,
LIB= exec
INCS= libexec.h
-SRCS= exec_aout.c exec_elf.c
+SRCS= exec_aout.c exec_elf.c exec_general.c
.if (${NBSD_LIBC} != "no")
INCSDIR= /usr/include
#include <minix/type.h>
#include <minix/const.h>
+#include <minix/com.h>
+#include <minix/syslib.h>
#include <sys/param.h>
+#include <sys/mman.h>
#include <assert.h>
#include <unistd.h>
#include <errno.h>
#include <libexec.h>
#include <string.h>
#include <machine/elf.h>
+#include <machine/vmparam.h>
+#include <machine/memory.h>
/* For verbose logging */
#define ELF_DEBUG 0
#define SECTOR_SIZE 512
-static int check_header(const Elf_Ehdr *hdr);
+static int check_header(Elf_Ehdr *hdr);
-static int elf_sane(const Elf_Ehdr *hdr)
+static int elf_sane(Elf_Ehdr *hdr)
{
if (check_header(hdr) != OK) {
return 0;
return 1;
}
-static int elf_ph_sane(const Elf_Phdr *phdr)
+static int elf_ph_sane(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)
+static int elf_unpack(char *exec_hdr,
+ int hdr_len, Elf_Ehdr **hdr, Elf_Phdr **phdr)
{
- *hdr = (const Elf_Ehdr *)exec_hdr;
+ *hdr = (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);
+ *phdr = (Elf_Phdr *)(exec_hdr + (*hdr)->e_phoff);
if(!elf_ph_sane(*phdr)) {
#if ELF_DEBUG
printf("elf_ph_sane failed\n");
}
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) */
- vir_bytes *text_membytes, /* text segment size (in memory) */
- vir_bytes *data_vaddr, /* data virtual address */
- phys_bytes *data_paddr, /* data physical address */
- vir_bytes *data_filebytes, /* data segment size (in the file) */
- vir_bytes *data_membytes, /* data segment size (in memory) */
- vir_bytes *pc, /* program entry point (initial PC) */
- off_t *text_offset, /* file offset to text segment */
- off_t *data_offset /* file offset to data segment */
+ 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) */
+ vir_bytes *text_membytes, /* text segment size (in memory) */
+ vir_bytes *data_vaddr, /* data virtual address */
+ phys_bytes *data_paddr, /* data physical address */
+ vir_bytes *data_filebytes, /* data segment size (in the file) */
+ vir_bytes *data_membytes, /* data segment size (in memory) */
+ vir_bytes *pc, /* program entry point (initial PC) */
+ off_t *text_offset, /* file offset to text segment */
+ off_t *data_offset /* file offset to data segment */
)
{
- const Elf_Ehdr *hdr = NULL;
- const Elf_Phdr *phdr = NULL;
+ Elf_Ehdr *hdr = NULL;
+ Elf_Phdr *phdr = NULL;
unsigned long seg_filebytes, seg_membytes;
int e, i = 0;
if((e=elf_unpack(exec_hdr, hdr_len, &hdr, &phdr)) != OK) {
#if ELF_DEBUG
- printf("elf_unpack failed\n");
+ printf("elf_unpack failed\n");
#endif
- return e;
+ return e;
}
#if ELF_DEBUG
for (i = 0; i < hdr->e_phnum; i++) {
switch (phdr[i].p_type) {
case PT_LOAD:
- if (phdr[i].p_memsz == 0)
- break;
- seg_filebytes = phdr[i].p_filesz;
- seg_membytes = round_page(phdr[i].p_memsz + phdr[i].p_vaddr -
- trunc_page(phdr[i].p_vaddr));
-
- if (hdr->e_entry >= phdr[i].p_vaddr &&
- hdr->e_entry < (phdr[i].p_vaddr + phdr[i].p_memsz)) {
- *text_vaddr = phdr[i].p_vaddr;
- *text_paddr = phdr[i].p_paddr;
- *text_filebytes = seg_filebytes;
- *text_membytes = seg_membytes;
- *pc = (vir_bytes)hdr->e_entry;
- *text_offset = phdr[i].p_offset;
- } else {
- *data_vaddr = phdr[i].p_vaddr;
- *data_paddr = phdr[i].p_paddr;
- *data_filebytes = seg_filebytes;
- *data_membytes = seg_membytes;
- *data_offset = phdr[i].p_offset;
- }
- break;
+ if (phdr[i].p_memsz == 0)
+ break;
+ seg_filebytes = phdr[i].p_filesz;
+ seg_membytes = round_page(phdr[i].p_memsz + phdr[i].p_vaddr -
+ trunc_page(phdr[i].p_vaddr));
+
+ if (hdr->e_entry >= phdr[i].p_vaddr &&
+ hdr->e_entry < (phdr[i].p_vaddr + phdr[i].p_memsz)) {
+ *text_vaddr = phdr[i].p_vaddr;
+ *text_paddr = phdr[i].p_paddr;
+ *text_filebytes = seg_filebytes;
+ *text_membytes = seg_membytes;
+ *pc = (vir_bytes)hdr->e_entry;
+ *text_offset = phdr[i].p_offset;
+ } else {
+ *data_vaddr = phdr[i].p_vaddr;
+ *data_paddr = phdr[i].p_paddr;
+ *data_filebytes = seg_filebytes;
+ *data_membytes = seg_membytes;
+ *data_offset = phdr[i].p_offset;
+ }
+ break;
default:
- break;
+ break;
}
}
(ehdr).e_ident[EI_MAG2] == ELFMAG2 && \
(ehdr).e_ident[EI_MAG3] == ELFMAG3)
-static int check_header(const Elf_Ehdr *hdr)
+static int check_header(Elf_Ehdr *hdr)
{
if (!IS_ELF(*hdr) ||
hdr->e_ident[EI_DATA] != ELF_TARG_DATA ||
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 elf_has_interpreter(char *exec_hdr, /* executable header */
int hdr_len, char *interp, int maxsz)
{
- const Elf_Ehdr *hdr = NULL;
- const Elf_Phdr *phdr = NULL;
+ Elf_Ehdr *hdr = NULL;
+ Elf_Phdr *phdr = NULL;
int e, i;
if((e=elf_unpack(exec_hdr, hdr_len, &hdr, &phdr)) != OK) return e;
return 0;
}
+int libexec_load_elf(struct exec_info *execi)
+{
+ int r;
+ Elf_Ehdr *hdr = NULL;
+ Elf_Phdr *phdr = NULL;
+ int e, i = 0;
+ int first = 1;
+ vir_bytes startv, stacklow;
+
+ assert(execi != NULL);
+ assert(execi->hdr != NULL);
+
+ if((e=elf_unpack(execi->hdr, execi->hdr_len, &hdr, &phdr)) != OK) {
+ printf("libexec_load_elf: elf_unpack failed\n");
+ return e;
+ }
+
+ /* 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("libexec: cannot load dynamically linked executable\n");
+ return ENOEXEC;
+ }
+
+ /* Make VM forget about all existing memory in process. */
+ vm_procctl(execi->proc_e, VMPPARAM_CLEAR);
+
+ execi->stack_size = roundup(execi->stack_size, PAGE_SIZE);
+ execi->stack_high = VM_STACKTOP;
+ assert(!(VM_STACKTOP % PAGE_SIZE));
+ stacklow = execi->stack_high - execi->stack_size;
+
+ for (i = 0; i < hdr->e_phnum; i++) {
+ vir_bytes seg_membytes, page_offset, vaddr;
+ Elf_Phdr *ph = &phdr[i];
+ if (ph->p_type != PT_LOAD || ph->p_memsz == 0) continue;
+#if 0
+ printf("index %d memsz 0x%lx vaddr 0x%lx\n", i, ph->p_memsz, ph->p_vaddr);
+#endif
+ vaddr = ph->p_vaddr;
+ seg_membytes = ph->p_memsz;
+ page_offset = vaddr % PAGE_SIZE;
+ vaddr -= page_offset;
+ seg_membytes += page_offset;
+ seg_membytes = roundup(seg_membytes, PAGE_SIZE);
+ if(first || startv > vaddr) startv = vaddr;
+ first = 0;
+
+#if 0
+ printf("libexec_load_elf: mmap 0x%lx bytes at 0x%lx\n",
+ seg_membytes, vaddr);
+#endif
+
+ /* Tell VM to make us some memory */
+ if(minix_mmap_for(execi->proc_e, (void *) vaddr, seg_membytes,
+ PROT_READ|PROT_WRITE|PROT_EXEC,
+ MAP_ANON|MAP_PREALLOC|MAP_FIXED, -1, 0) == MAP_FAILED) {
+ printf("libexec_load_elf: mmap of 0x%lx bytes failed\n", seg_membytes);
+ vm_procctl(execi->proc_e, VMPPARAM_CLEAR);
+ return ENOMEM;
+ }
+
+ /* Copy executable section into it */
+ if(execi->load(execi, ph->p_offset, ph->p_vaddr, ph->p_filesz) != OK) {
+ printf("libexec_load_elf: load callback failed\n");
+ vm_procctl(execi->proc_e, VMPPARAM_CLEAR);
+ return ENOMEM;
+ }
+ }
+
+ /* Make it a stack */
+ if(minix_mmap_for(execi->proc_e, (void *) stacklow, execi->stack_size,
+ PROT_READ|PROT_WRITE|PROT_EXEC,
+ MAP_ANON|MAP_FIXED, -1, 0) == MAP_FAILED) {
+ printf("libexec_load_elf: mmap for stack failed\n");
+ vm_procctl(execi->proc_e, VMPPARAM_CLEAR);
+ return ENOMEM;
+ }
+
+ /* record entry point and lowest load vaddr for caller */
+ execi->pc = hdr->e_entry;
+ execi->load_base = startv;
+
+ if((r = libexec_pm_newexec(execi->proc_e, execi)) != OK) {
+ printf("libexec_load_elf: pm_newexec failed: %d\n", r);
+ }
+
+ return(r);
+}
+
--- /dev/null
+#define _SYSTEM 1
+
+#include <minix/type.h>
+#include <minix/const.h>
+#include <sys/param.h>
+#include <assert.h>
+#include <unistd.h>
+#include <errno.h>
+#include <libexec.h>
+#include <string.h>
+#include <assert.h>
+#include <minix/ipc.h>
+#include <minix/com.h>
+#include <minix/callnr.h>
+#include <machine/elf.h>
+
+void libexec_patch_ptr(char stack[ARG_MAX], vir_bytes base)
+{
+/* When doing an exec(name, argv, envp) call, the user builds up a stack
+ * image with arg and env pointers relative to the start of the stack. Now
+ * these pointers must be relocated, since the stack is not positioned at
+ * address 0 in the user's address space.
+ */
+
+ char **ap, flag;
+ vir_bytes v;
+
+ flag = 0; /* counts number of 0-pointers seen */
+ ap = (char **) stack; /* points initially to 'nargs' */
+ ap++; /* now points to argv[0] */
+ while (flag < 2) {
+ if (ap >= (char **) &stack[ARG_MAX]) return; /* too bad */
+ if (*ap != NULL) {
+ v = (vir_bytes) *ap; /* v is relative pointer */
+ v += base; /* relocate it */
+ *ap = (char *) v; /* put it back */
+ } else {
+ flag++;
+ }
+ ap++;
+ }
+}
+
+int libexec_pm_newexec(endpoint_t proc_e, struct exec_info *e)
+{
+ int r;
+ message m;
+
+ m.m_type = PM_NEWEXEC;
+ m.EXC_NM_PROC = proc_e;
+ m.EXC_NM_PTR = (char *)e;
+ if ((r = sendrec(PM_PROC_NR, &m)) != OK) return(r);
+
+ e->allow_setuid = !!(m.m1_i2 & EXC_NM_RF_ALLOW_SETUID);
+
+ return(m.m_type);
+}
#include <sys/exec_elf.h>
-/* ELF routines */
-int read_header_elf(const char *exec_hdr, int hdr_len,
+struct exec_info;
+
+typedef int (*libexec_loadfunc_t)(struct exec_info *execi,
+ off_t offset, off_t vaddr, size_t len);
+
+typedef int (*libexec_clearfunc_t)(struct exec_info *execi,
+ off_t vaddr, size_t len);
+
+struct exec_info {
+ /* Filled in by libexec caller */
+ endpoint_t proc_e; /* Process endpoint */
+ char *hdr; /* Header or full image */
+ size_t hdr_len; /* Size of hdr */
+ vir_bytes frame_len; /* Stack size */
+ char progname[PROC_NAME_LEN]; /* Program name */
+ uid_t new_uid; /* Process UID after exec */
+ gid_t new_gid; /* Process GID after exec */
+ int allow_setuid; /* Allow set{u,g}id execution? */
+ libexec_loadfunc_t load; /* Load callback */
+ libexec_clearfunc_t clear; /* Clear callback */
+ void *opaque; /* Callback data */
+ vir_bytes stack_size; /* Desired stack size */
+
+ /* Filled in by libexec load function */
+ vir_bytes load_base; /* Where executable is loaded */
+ vir_bytes pc; /* Entry point of exec file */
+ vir_bytes stack_high; /* High stack addr */
+};
+
+int elf_has_interpreter(char *exec_hdr, int hdr_len, char *interp, int maxsz);
+int elf_phdr(char *exec_hdr, int hdr_len, vir_bytes *phdr);
+int read_header_elf(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);
+void libexec_patch_ptr(char stack[ARG_MAX], vir_bytes base);
+int libexec_pm_newexec(endpoint_t proc_e, struct exec_info *execi);
+
+typedef int (*libexec_exec_loadfunc_t)(struct exec_info *execi);
+
+int libexec_load_elf(struct exec_info *execi);
#endif /* !_LIBEXEC_H_ */
link.c _mcontext.c mknod.c mmap.c nanosleep.c open.c \
read.c sbrk.c select.c setuid.c sigprocmask.c stat.c \
stime.c syscall.c _ucontext.c umask.c unlink.c waitpid.c \
- brksize.S _ipc.S _senda.S ucontext.S
+ brksize.S _ipc.S _senda.S ucontext.S mmap.c
.PATH.c: ${LIBCSRCDIR}/sys-minix
.PATH.S: ${LIBCSRCDIR}/arch/${MACHINE}/sys-minix
SRCS+= ${i}
vbox.c \
vm_brk.c \
vm_dmacalls.c \
- vm_exec_newmem.c \
vm_exit.c \
vm_fork.c \
vm_info.c \
+++ /dev/null
-
-#include "syslib.h"
-
-#include <minix/vm.h>
-
-/*===========================================================================*
- * vm_exec_newmem *
- *===========================================================================*/
-int vm_exec_newmem(endpoint_t ep, struct exec_newmem *args,
- int argssize, char **ret_stack_top, int *ret_flags)
-{
- message m;
- int result;
-
- m.VMEN_ENDPOINT = ep;
- m.VMEN_ARGSPTR = (void *) args;
- m.VMEN_ARGSSIZE = argssize;
-
- result = _taskcall(VM_PROC_NR, VM_EXEC_NEWMEM, &m);
-
- *ret_stack_top = m.VMEN_STACK_TOP;
- *ret_flags = m.VMEN_FLAGS;
-
- return result;
-}
-
result = _taskcall(VM_PROC_NR, VM_PROCCTL, &m);
return(result);
}
+
#include <a.out.h>
#include <signal.h>
#include <string.h>
+#include <libexec.h>
#include <sys/ptrace.h>
#include "mproc.h"
#include "param.h"
m.PM_PATH = m_in.exec_name;
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_FRAME_LEN = m_in.msg_frame_len;
m.PM_EXECFLAGS = m_in.PMEXEC_FLAGS;
tell_vfs(mp, &m);
/*===========================================================================*
- * do_exec_newmem *
+ * do_newexec *
*===========================================================================*/
-int do_exec_newmem()
+int do_newexec()
{
int proc_e, proc_n, allow_setuid;
char *ptr;
struct mproc *rmp;
- struct exec_newmem args;
+ struct exec_info args;
int r, flags;
- char *stack_top;
if (who_e != VFS_PROC_NR && who_e != RS_PROC_NR)
return EPERM;
if (r != OK)
panic("do_exec_newmem: sys_datacopy failed: %d", r);
- if ((r = vm_exec_newmem(proc_e, &args, sizeof(args), &stack_top,
- &flags)) == OK) {
- allow_setuid = 0; /* Do not allow setuid execution */
- rmp->mp_flags &= ~TAINTED; /* By default not tainted */
+ allow_setuid = 0; /* Do not allow setuid execution */
+ rmp->mp_flags &= ~TAINTED; /* By default not tainted */
- if (rmp->mp_tracer == NO_TRACER) {
- /* Okay, setuid execution is allowed */
- allow_setuid = 1;
- }
+ if (rmp->mp_tracer == NO_TRACER) {
+ /* Okay, setuid execution is allowed */
+ allow_setuid = 1;
+ }
- if (allow_setuid && args.setugid) {
- rmp->mp_effuid = args.new_uid;
- rmp->mp_effgid = args.new_gid;
- }
+ if (allow_setuid && args.allow_setuid) {
+ rmp->mp_effuid = args.new_uid;
+ rmp->mp_effgid = args.new_gid;
+ }
- /* A process is considered 'tainted' when it's executing with
- * setuid or setgid bit set, or when the real{u,g}id doesn't
- * match the eff{u,g}id, respectively. */
- if (allow_setuid && args.setugid) {
- /* Program has setuid and/or setgid bits set */
- rmp->mp_flags |= TAINTED;
- } else if (rmp->mp_effuid != rmp->mp_realuid ||
- rmp->mp_effgid != rmp->mp_realgid) {
- rmp->mp_flags |= TAINTED;
- }
+ /* A process is considered 'tainted' when it's executing with
+ * setuid or setgid bit set, or when the real{u,g}id doesn't
+ * match the eff{u,g}id, respectively. */
+ if (allow_setuid && args.allow_setuid) {
+ /* Program has setuid and/or setgid bits set */
+ rmp->mp_flags |= TAINTED;
+ } else if (rmp->mp_effuid != rmp->mp_realuid ||
+ rmp->mp_effgid != rmp->mp_realgid) {
+ rmp->mp_flags |= TAINTED;
+ }
- /* System will save command line for debugging, ps(1) output, etc. */
- strncpy(rmp->mp_name, args.progname, PROC_NAME_LEN-1);
- rmp->mp_name[PROC_NAME_LEN-1] = '\0';
+ /* System will save command line for debugging, ps(1) output, etc. */
+ strncpy(rmp->mp_name, args.progname, PROC_NAME_LEN-1);
+ rmp->mp_name[PROC_NAME_LEN-1] = '\0';
- /* Save offset to initial argc (for procfs) */
- rmp->mp_frame_addr = (vir_bytes) stack_top - args.args_bytes;
- rmp->mp_frame_len = args.args_bytes;
+ /* Save offset to initial argc (for procfs) */
+ rmp->mp_frame_addr = (vir_bytes) args.stack_high - args.frame_len;
+ rmp->mp_frame_len = args.frame_len;
- /* Kill process if something goes wrong after this point. */
- rmp->mp_flags |= PARTIAL_EXEC;
+ /* Kill process if something goes wrong after this point. */
+ rmp->mp_flags |= PARTIAL_EXEC;
+
+ mp->mp_reply.reply_res2= (vir_bytes) rmp->mp_frame_addr;
+ mp->mp_reply.reply_res3= flags;
+ if (allow_setuid && args.allow_setuid)
+ mp->mp_reply.reply_res3 |= EXC_NM_RF_ALLOW_SETUID;
- mp->mp_reply.reply_res2= (vir_bytes) stack_top;
- mp->mp_reply.reply_res3= flags;
- if (allow_setuid && args.setugid)
- mp->mp_reply.reply_res3 |= EXC_NM_RF_ALLOW_SETUID;
- } else {
- printf("PM: newmem failed for %s\n", args.progname);
- }
return r;
}
#define new_val m1_p1
#define old_val m1_p2
#define sig m6_i1
-#define frame_len m1_i2
+#define msg_frame_len m1_i2
#define frame_ptr m1_p2
#define status m1_i1
#define usr_id m1_i1
/* exec.c */
int do_exec(void);
-int do_exec_newmem(void);
+int do_newexec(void);
int do_execrestart(void);
void exec_restart(struct mproc *rmp, int result, vir_bytes pc, vir_bytes sp);
no_sys, /* 97 = unused */
do_sprofile, /* 98 = sprofile */
do_cprofile, /* 99 = cprofile */
- do_exec_newmem, /* 100 = exec_newmem */
+ do_newexec, /* 100 = newexec */
do_srv_fork, /* 101 = srv_fork */
do_execrestart, /* 102 = exec_restart */
no_sys, /* 103 = unused */
#include <a.out.h>
#include <assert.h>
#include <libexec.h>
-#include "exec.h"
-
-#define BLOCK_SIZE 1024
+#include <machine/vmparam.h>
static int do_exec(int proc_e, char *exec, size_t exec_len, char *progname,
char *frame, int frame_len);
-static int exec_newmem(int proc_e, vir_bytes text_addr,
- vir_bytes text_bytes, vir_bytes data_addr,
- vir_bytes data_bytes, vir_bytes tot_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 *allow_setuidp);
-static void patch_ptr(char stack[ARG_MAX], vir_bytes base);
static int exec_restart(int proc_e, int result, vir_bytes pc);
static int read_seg(struct exec_info *execi, off_t off,
- int proc_e, int seg, vir_bytes seg_addr, phys_bytes seg_bytes);
-static int load_elf(struct exec_info *execi);
+ off_t seg_addr, size_t seg_bytes);
/* Array of loaders for different object formats */
static struct exec_loaders {
- int (*load_object)(struct exec_info *);
+ libexec_exec_loadfunc_t load_object;
} const exec_loaders[] = {
- { load_elf },
+ { libexec_load_elf },
{ NULL }
};
struct exec_info execi;
int i;
+ memset(&execi, 0, sizeof(execi));
+
+ execi.stack_size = DEFAULT_STACK_LIMIT;
execi.proc_e = proc_e;
- execi.image = exec;
- execi.image_len = exec_len;
+ execi.hdr = exec;
+ execi.hdr_len = exec_len;
strncpy(execi.progname, progname, PROC_NAME_LEN-1);
execi.progname[PROC_NAME_LEN-1] = '\0';
execi.frame_len = frame_len;
+ execi.load = read_seg;
for(i = 0; exec_loaders[i].load_object != NULL; i++) {
r = (*exec_loaders[i].load_object)(&execi);
}
/* Patch up stack and copy it from RS to new core image. */
- vsp = execi.stack_top;
+ vsp = execi.stack_high;
vsp -= frame_len;
- patch_ptr(frame, vsp);
+ libexec_patch_ptr(frame, vsp);
r = sys_datacopy(SELF, (vir_bytes) frame,
proc_e, (vir_bytes) vsp, (phys_bytes)frame_len);
if (r != OK) {
- printf("RS: stack_top is 0x%lx; tried to copy to 0x%lx in %d\n",
- execi.stack_top, vsp, proc_e);
printf("do_exec: copying out new stack failed: %d\n", r);
exec_restart(proc_e, r, execi.pc);
return r;
return exec_restart(proc_e, OK, execi.pc);
}
-static int load_elf(struct exec_info *execi)
-{
- int r;
- int proc_e;
- phys_bytes tot_bytes; /* total space for program, including gap */
- 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, load_text, allow_setuid;
- uid_t new_uid;
- gid_t new_gid;
-
- assert(execi != NULL);
- assert(execi->image != NULL);
-
- proc_e = execi->proc_e;
-
- /* Read the file header and extract the segment sizes. */
- 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,
- &execi->pc, &text_offset, &data_offset);
- if (r != OK) {
- 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;
-
- sep_id = 0;
- is_elf = 1;
- tot_bytes = 0; /* Use default stack size */
-
- r = exec_newmem(proc_e,
- trunc_page(text_vaddr), text_membytes,
- trunc_page(data_vaddr), data_membytes,
- tot_bytes, execi->frame_len, sep_id, is_elf,
- 0 /*dev*/, proc_e /*inum*/, 0 /*ctime*/,
- execi->progname, new_uid, new_gid,
- &execi->stack_top, &load_text, &allow_setuid);
- if (r != OK)
- {
- printf("RS: load_elf: exec_newmem failed: %d\n", r);
- exec_restart(proc_e, r, execi->pc);
- return r;
- }
-
- /* Read in text and data segments. */
- if (load_text) {
- r = read_seg(execi, text_offset, proc_e, T, text_vaddr, text_filebytes);
- if (r != OK)
- {
- printf("RS: load_elf: read_seg failed: %d\n", r);
- exec_restart(proc_e, r, execi->pc);
- return r;
- }
- }
- else
- printf("RS: load_elf: not loading text segment\n");
-
- r = read_seg(execi, data_offset, proc_e, D, data_vaddr, data_filebytes);
- if (r != OK)
- {
- printf("RS: load_elf: read_seg failed: %d\n", r);
- exec_restart(proc_e, r, execi->pc);
- return r;
- }
-
- return(OK);
-}
-
-/*===========================================================================*
- * exec_newmem *
- *===========================================================================*/
-static int exec_newmem(
- int proc_e,
- vir_bytes text_addr,
- vir_bytes text_bytes,
- vir_bytes data_addr,
- vir_bytes data_bytes,
- vir_bytes tot_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 *allow_setuidp
-)
-{
- int r;
- struct exec_newmem e;
- message m;
-
- e.text_addr = text_addr;
- e.text_bytes= text_bytes;
- e.data_addr = data_addr;
- e.data_bytes= data_bytes;
- e.tot_bytes= tot_bytes;
- e.args_bytes= frame_len;
- e.sep_id= sep_id;
- e.is_elf= is_elf;
- e.st_dev= st_dev;
- e.st_ino= st_ino;
- e.enst_ctime= ctime;
- e.new_uid= new_uid;
- e.new_gid= new_gid;
- e.setugid= *allow_setuidp;
- strncpy(e.progname, progname, sizeof(e.progname)-1);
- e.progname[sizeof(e.progname)-1]= '\0';
-
- m.m_type= EXEC_NEWMEM;
- m.EXC_NM_PROC= proc_e;
- m.EXC_NM_PTR= (char *)&e;
- r= sendrec(PM_PROC_NR, &m);
- if (r != OK)
- return r;
-#if 0
- printf("exec_newmem: r = %d, m_type = %d\n", r, m.m_type);
-#endif
- *stack_topp= m.m1_i1;
- *load_textp= !!(m.m1_i2 & EXC_NM_RF_LOAD_TEXT);
- *allow_setuidp= !!(m.m1_i2 & EXC_NM_RF_ALLOW_SETUID);
-#if 0
- printf("RS: exec_newmem: stack_top = 0x%x\n", *stack_topp);
- printf("RS: exec_newmem: load_text = %d\n", *load_textp);
-#endif
- return m.m_type;
-}
-
-
/*===========================================================================*
* exec_restart *
*===========================================================================*/
}
/*===========================================================================*
- * patch_ptr *
- *===========================================================================*/
-static void patch_ptr(
-char stack[ARG_MAX], /* pointer to stack image within PM */
-vir_bytes base /* virtual address of stack base inside user */
-)
-{
-/* When doing an exec(name, argv, envp) call, the user builds up a stack
- * image with arg and env pointers relative to the start of the stack. Now
- * these pointers must be relocated, since the stack is not positioned at
- * address 0 in the user's address space.
- */
-
- char **ap, flag;
- vir_bytes v;
-
- flag = 0; /* counts number of 0-pointers seen */
- ap = (char **) stack; /* points initially to 'nargs' */
- ap++; /* now points to argv[0] */
- while (flag < 2) {
- if (ap >= (char **) &stack[ARG_MAX]) return; /* too bad */
- if (*ap != NULL) {
- v = (vir_bytes) *ap; /* v is relative pointer */
- v += base; /* relocate it */
- *ap = (char *) v; /* put it back */
- } else {
- flag++;
- }
- ap++;
- }
-}
-
-/*===========================================================================*
- * read_seg *
+ * read_seg *
*===========================================================================*/
static int read_seg(
-struct exec_info *execi, /* various data needed for exec */
-off_t off, /* offset in file */
-int proc_e, /* process number (endpoint) */
-int seg, /* T, D, or S */
-vir_bytes seg_addr, /* address to load segment */
-phys_bytes seg_bytes /* how much is to be transferred? */
+struct exec_info *execi, /* various data needed for exec */
+off_t off, /* offset in file */
+off_t seg_addr, /* address to load segment */
+size_t seg_bytes /* how much is to be transferred? */
)
{
/*
int r;
- assert((seg == T)||(seg == D));
-
- if (off+seg_bytes > execi->image_len) return ENOEXEC;
- r= sys_vircopy(SELF, D, ((vir_bytes)execi->image)+off, proc_e, seg, seg_addr, seg_bytes);
+ if (off+seg_bytes > execi->hdr_len) return ENOEXEC;
+ if((r= sys_vircopy(SELF, D, ((vir_bytes)execi->hdr)+off,
+ execi->proc_e, D, seg_addr, seg_bytes)) != OK) {
+ printf("RS: exec read_seg: copy 0x%lx bytes into %d at 0x%lx failed: %d\n",
+ seg_bytes, execi->proc_e, seg_addr, r);
+ }
return r;
}
+++ /dev/null
-#ifndef _RS_EXEC_H_
-#define _RS_EXEC_H_ 1
-
-struct exec_info {
- int proc_e; /* Process endpoint */
- char *image; /* Executable image */
- size_t image_len; /* Size of executable image */
- vir_bytes pc; /* Entry point of exec file */
- vir_bytes stack_top; /* Top of the stack */
- vir_bytes frame_len; /* Stack size */
- char progname[PROC_NAME_LEN]; /* Program name */
-};
-
-#endif /* !_RS_EXEC_H_ */
#include <machine/vmparam.h>
#include <assert.h>
#include <fcntl.h>
-#include "exec.h"
#define _KERNEL /* for ELF_AUX_ENTRIES */
#include <libexec.h>
+/* fields only used by elf and in VFS */
+struct vfs_exec_info {
+ struct exec_info args; /* libexec exec args */
+ struct vnode *vp; /* Exec file's vnode */
+ struct vmnt *vmp; /* Exec file's vmnt */
+ struct stat sb; /* Exec file's stat structure */
+ int userflags; /* exec() flags from userland */
+ int is_dyn; /* Dynamically linked executable */
+ int elf_main_fd; /* Dyn: FD of main program execuatble */
+ char execname[PATH_MAX]; /* Full executable invocation */
+};
+
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,
- vir_bytes data_addr, vir_bytes data_bytes, vir_bytes tot_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 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 is_script(struct vfs_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);
static void clo_exec(struct fproc *rfp);
-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_elf(struct exec_info *execi);
-static int stack_prepare_elf(struct exec_info *execi,
+static int stack_prepare_elf(struct vfs_exec_info *execi,
char *curstack, size_t *frame_len, vir_bytes *vsp, int *extrabase);
-static int map_header(struct exec_info *execi);
+static int map_header(struct vfs_exec_info *execi);
+static int read_seg(struct exec_info *execi, off_t off, off_t seg_addr, size_t seg_bytes);
#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,
+typedef int (*exechook_t)(struct vfs_exec_info *execpackage);
+typedef int (*stackhook_t)(struct vfs_exec_info *execi, char *curstack,
size_t *frame_len, vir_bytes *, int *extrabase);
struct exec_loaders {
- exechook_t load_object; /* load executable into memory */
+ libexec_exec_loadfunc_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_elf, stack_prepare_elf },
+ { libexec_load_elf, stack_prepare_elf },
{ NULL, NULL }
};
/*===========================================================================*
* get_read_vp *
*===========================================================================*/
-static int get_read_vp(struct exec_info *execi, char *fullpath,
- int copyprogname, int sugid, struct lookup *resolve, struct fproc *fp)
+static int get_read_vp(struct vfs_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
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';
+ strncpy(execi->args.progname, cp, sizeof(execi->args.progname)-1);
+ execi->args.progname[sizeof(execi->args.progname)-1] = '\0';
}
/* Open executable */
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;
+ execi->args.new_uid = execi->vp->v_uid;
+ execi->args.allow_setuid = 1;
}
if (execi->vp->v_mode & I_SET_GID_BIT) {
- execi->new_gid = execi->vp->v_gid;
- execi->setugid = 1;
+ execi->args.new_gid = execi->vp->v_gid;
+ execi->args.allow_setuid = 1;
}
}
struct fproc *rfp;
int extrabase = 0;
static char mbuf[ARG_MAX]; /* buffer for stack and zeroes */
- struct exec_info execi;
+ struct vfs_exec_info execi;
int i;
static char fullpath[PATH_MAX],
elf_interpreter[PATH_MAX],
/* passed from exec() libc code */
execi.userflags = user_exec_flags;
+ execi.args.stack_size = DEFAULT_STACK_LIMIT;
okendpt(proc_e, &slot);
rfp = fp = &fproc[slot];
}
/* The default is to keep the original user and group IDs */
- execi.new_uid = rfp->fp_effuid;
- execi.new_gid = rfp->fp_effgid;
+ execi.args.new_uid = rfp->fp_effuid;
+ execi.args.new_gid = rfp->fp_effgid;
/* Get the exec file name. */
FAILCHECK(fetch_name(path, path_len, fullpath));
* executable instead. But open the current executable in an
* fd for the current process.
*/
- if(elf_has_interpreter(execi.hdr, execi.hdr_len,
+ if(elf_has_interpreter(execi.args.hdr, execi.args.hdr_len,
elf_interpreter, sizeof(elf_interpreter))) {
/* Switch the executable vnode to the interpreter */
execi.is_dyn = 1;
Get_read_vp(execi, fullpath, 0, 0, &resolve, fp);
}
- execi.proc_e = proc_e;
- execi.frame_len = frame_len;
+ execi.args.opaque = &execi;
+ execi.args.load = &read_seg;
+ execi.args.clear = NULL;
+ execi.args.proc_e = proc_e;
+ execi.args.frame_len = frame_len;
for (i = 0; exec_loaders[i].load_object != NULL; i++) {
- r = (*exec_loaders[i].load_object)(&execi);
+ r = (*exec_loaders[i].load_object)(&execi.args);
/* Loaded successfully, so no need to try other loaders */
if (r == OK) { makestack = exec_loaders[i].setup_stack; break; }
}
FAILCHECK(r);
/* Save off PC */
- *pc = execi.pc;
+ *pc = execi.args.pc;
/* call a stack-setup function if this executable type wants it */
- vsp = execi.stack_top - frame_len;
+ vsp = execi.args.stack_high - frame_len;
if(makestack) FAILCHECK(makestack(&execi, mbuf, &frame_len, &vsp, &extrabase));
/* Patch up stack and copy it from VFS to new core image. */
- patch_ptr(mbuf, vsp + extrabase);
+ libexec_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;
clo_exec(rfp);
- if (execi.setugid) {
+ if (execi.args.allow_setuid) {
/* If after loading the image we're still allowed to run with
* setuid or setgid, change credentials now */
- rfp->fp_effuid = execi.new_uid;
- rfp->fp_effgid = execi.new_gid;
+ rfp->fp_effuid = execi.args.new_uid;
+ rfp->fp_effgid = execi.args.new_gid;
}
/* Remember the new name of the process */
- strcpy(rfp->fp_name, execi.progname);
+ strcpy(rfp->fp_name, execi.args.progname);
pm_execfinal:
if (execi.vp != NULL) {
return(r);
}
-static int stack_prepare_elf(struct exec_info *execi, char *frame, size_t *framelen,
+static int stack_prepare_elf(struct vfs_exec_info *execi, char *frame, size_t *framelen,
vir_bytes *newsp, int *extrabase)
{
AuxInfo *a, *term;
if(!execi->is_dyn)
return OK;
- assert(execi->hdr_len >= sizeof(*elf_header));
- elf_header = (Elf_Ehdr *) execi->hdr;
+ assert(execi->args.hdr_len >= sizeof(*elf_header));
+ elf_header = (Elf_Ehdr *) execi->args.hdr;
/* exec() promises stack space. Now find it. */
mysp++; /* skip argc */
#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_BASE, execi->args.load_base);
+ AUXINFO(AT_ENTRY, execi->args.pc);
AUXINFO(AT_PAGESZ, PAGE_SIZE);
AUXINFO(AT_EXECFD, execi->elf_main_fd);
return OK;
}
-/*===========================================================================*
- * load_elf *
- *===========================================================================*/
-static int load_elf(struct exec_info *execi)
-{
- int r;
- struct vnode *vp;
- int proc_e;
- phys_bytes tot_bytes; /* total space for program, including gap */
- 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, i;
- vir_bytes text_base, data_base;
-
- assert(execi != NULL);
- assert(execi->hdr != NULL);
- assert(execi->vp != NULL);
-
- 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, 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(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,
- 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,
- &execi->stack_top, &execi->load_text, &execi->setugid);
-
- if (r != OK) {
- printf("VFS: load_elf: exec_newmem failed: %d\n", r);
- return(r);
- }
-
- /* Read in text and data segments. */
- if (execi->load_text)
- r = read_seg(vp, text_offset, proc_e, T, text_vaddr, text_filebytes);
-
- if (r == OK)
- r = read_seg(vp, data_offset, proc_e, D, data_vaddr, data_filebytes);
-
- return(r);
-}
-
-/*===========================================================================*
- * exec_newmem *
- *===========================================================================*/
-static int exec_newmem(
- int proc_e,
- vir_bytes text_addr,
- vir_bytes text_bytes,
- vir_bytes data_addr,
- vir_bytes data_bytes,
- vir_bytes tot_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
-)
-{
-/* Allocate a new memory map for a process that tries to exec */
- int r;
- struct exec_newmem e;
- message m;
-
- assert(setugidp != NULL);
-
- e.text_addr = text_addr;
- e.text_bytes = text_bytes;
- e.data_addr = data_addr;
- e.data_bytes = data_bytes;
- e.tot_bytes = tot_bytes;
- e.args_bytes = frame_len;
- e.sep_id = sep_id;
- e.is_elf = is_elf;
- e.st_dev = st_dev;
- e.st_ino = st_ino;
- e.enst_ctime = ctime;
- e.new_uid = new_uid;
- e.new_gid = new_gid;
- e.setugid = *setugidp;
- strncpy(e.progname, progname, sizeof(e.progname)-1);
- e.progname[sizeof(e.progname)-1] = '\0';
-
- m.m_type = EXEC_NEWMEM;
- m.EXC_NM_PROC = proc_e;
- m.EXC_NM_PTR = (char *)&e;
- if ((r = sendrec(PM_PROC_NR, &m)) != OK) return(r);
-
- *stack_topp = m.m1_i1;
- *load_textp = !!(m.m1_i2 & EXC_NM_RF_LOAD_TEXT);
- *setugidp = !!(m.m1_i2 & EXC_NM_RF_ALLOW_SETUID);
-
- return(m.m_type);
-}
-
/*===========================================================================*
* is_script *
*===========================================================================*/
-static int is_script(struct exec_info *execi)
+static int is_script(struct vfs_exec_info *execi)
{
/* Is Interpreted script? */
- assert(execi->hdr != NULL);
+ assert(execi->args.hdr != NULL);
- return(execi->hdr[0] == '#' && execi->hdr[1] == '!' && execi->hdr_len >= 2);
+ return(execi->args.hdr[0] == '#' && execi->args.hdr[1] == '!'
+ && execi->args.hdr_len >= 2);
}
/*===========================================================================*
((char **) stack)[0]++; /* nargs++; */
}
/* Now patch up argv[] and envp[] by offset. */
- patch_ptr(stack, (vir_bytes) offset);
+ libexec_patch_ptr(stack, (vir_bytes) offset);
((char **) stack)[1] = (char *) a0; /* set argv[0] correctly */
return(TRUE);
}
-
-/*===========================================================================*
- * patch_ptr *
- *===========================================================================*/
-static void patch_ptr(
-char stack[ARG_MAX], /* pointer to stack image within PM */
-vir_bytes base /* virtual address of stack base inside user */
-)
-{
-/* When doing an exec(name, argv, envp) call, the user builds up a stack
- * image with arg and env pointers relative to the start of the stack. Now
- * these pointers must be relocated, since the stack is not positioned at
- * address 0 in the user's address space.
- */
-
- char **ap, flag;
- vir_bytes v;
-
- flag = 0; /* counts number of 0-pointers seen */
- ap = (char **) stack; /* points initially to 'nargs' */
- ap++; /* now points to argv[0] */
- while (flag < 2) {
- if (ap >= (char **) &stack[ARG_MAX]) return; /* too bad */
- if (*ap != NULL) {
- v = (vir_bytes) *ap; /* v is relative pointer */
- v += base; /* relocate it */
- *ap = (char *) v; /* put it back */
- } else {
- flag++;
- }
- ap++;
- }
-}
-
/*===========================================================================*
* read_seg *
*===========================================================================*/
-static int read_seg(
-struct vnode *vp, /* inode descriptor to read from */
-off_t off, /* offset in file */
-int proc_e, /* process number (endpoint) */
-int seg, /* T, D, or S */
-vir_bytes seg_addr, /* address to load segment */
-phys_bytes seg_bytes /* how much is to be transferred? */
-)
+static int read_seg(struct exec_info *execi, off_t off, off_t seg_addr, size_t seg_bytes)
{
/*
* The byte count on read is usually smaller than the segment count, because
* partially initialized.
*/
int r;
- unsigned n, o;
u64_t new_pos;
unsigned int cum_io;
- static char buf[128 * 1024];
-
- assert((seg == T)||(seg == D));
+ struct vnode *vp = ((struct vfs_exec_info *) execi->opaque)->vp;
/* Make sure that the file is big enough */
if (off + seg_bytes > LONG_MAX) return(EIO);
if ((unsigned long) vp->v_size < off+seg_bytes) return(EIO);
- if (seg == T) {
- /* We have to use a copy loop until safecopies support segments */
- o = 0;
- while (o < seg_bytes) {
- n = seg_bytes - o;
- if (n > sizeof(buf))
- n = sizeof(buf);
-
- if ((r = req_readwrite(vp->v_fs_e,vp->v_inode_nr,cvul64(off+o),
- READING, VFS_PROC_NR, buf,
- n, &new_pos, &cum_io)) != OK) {
- printf("VFS: read_seg: req_readwrite failed (text)\n");
- return(r);
- }
-
- if (cum_io != n) {
- printf(
- "VFSread_seg segment has not been read properly by exec() \n");
- return(EIO);
- }
-
- if ((r = sys_vircopy(VFS_PROC_NR, D, (vir_bytes)buf, proc_e,
- seg, seg_addr + o, n)) != OK) {
- printf("VFS: read_seg: copy failed (text)\n");
- return(r);
- }
-
- o += n;
- }
- return(OK);
- } else if (seg == D) {
-
if ((r = req_readwrite(vp->v_fs_e, vp->v_inode_nr, cvul64(off), READING,
- proc_e, (char*)seg_addr, seg_bytes,
+ execi->proc_e, (char*)seg_addr, seg_bytes,
&new_pos, &cum_io)) != OK) {
printf("VFS: read_seg: req_readwrite failed (data)\n");
return(r);
printf("VFS: read_seg segment has not been read properly\n");
return(r);
- }
-
- return(OK);
}
/*===========================================================================*
* map_header *
*===========================================================================*/
-static int map_header(struct exec_info *execi)
+static int map_header(struct vfs_exec_info *execi)
{
int r;
u64_t new_pos;
pos = 0; /* Read from the start of the file */
/* How much is sensible to read */
- execi->hdr_len = MIN(execi->vp->v_size, sizeof(hdr));
- execi->hdr = hdr;
+ execi->args.hdr_len = MIN(execi->vp->v_size, sizeof(hdr));
+ execi->args.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);
+ execi->args.hdr_len, &new_pos, &cum_io);
if (r != OK) {
printf("VFS: exec: map_header: req_readwrite failed\n");
return(r);
+++ /dev/null
-#ifndef _VFS_EXEC_H_
-#define _VFS_EXEC_H_ 1
-
-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 */
- uid_t new_uid; /* Process UID after exec */
- gid_t new_gid; /* Process GID after exec */
- 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 */
- char execname[PATH_MAX]; /* Full executable invocation */
-};
-
-#endif /* !_VFS_EXEC_H_ */
#include <machine/vm.h>
-/* As visible from the user space process, where is the top of the
- * stack (first non-stack byte), when in paged mode?
- */
-#define VM_STACKTOP 0x80000000
-
/* And what is the highest addressable piece of memory, when in paged
* mode? Some data for kernel and stack are subtracted from this, the
* final results stored in bytes in arch.vm_data_top.
#include <errno.h>
#include <assert.h>
+#include <string.h>
#include <env.h>
#include <pagetable.h>
#include <sys/param.h>
#include "memory.h"
-static int new_mem(struct vmproc *vmp, vir_bytes text_addr, vir_bytes
- text_bytes, vir_bytes data_addr, vir_bytes data_bytes, vir_bytes
- stk_bytes, phys_bytes tot_bytes, vir_bytes *stack_top, int is_elf);
-
-/*===========================================================================*
- * exec_newmem *
- *===========================================================================*/
-int do_exec_newmem(message *msg)
-{
- int r, proc_e, proc_n;
- vir_bytes stack_top;
- vir_clicks tc, dc, sc, totc, dvir, s_vir;
- struct vmproc *vmp;
- char *ptr;
- struct exec_newmem args;
-
- SANITYCHECK(SCL_FUNCTIONS);
-
- proc_e= msg->VMEN_ENDPOINT;
- if (vm_isokendpt(proc_e, &proc_n) != OK)
- {
- printf("VM: exec_newmem: bad endpoint %d from %d\n",
- proc_e, msg->m_source);
- return ESRCH;
- }
- vmp= &vmproc[proc_n];
- ptr= msg->VMEN_ARGSPTR;
-
- if(msg->VMEN_ARGSSIZE != sizeof(args)) {
- printf("VM: exec_newmem: args size %d != %u\n",
- msg->VMEN_ARGSSIZE, sizeof(args));
- return EINVAL;
- }
-SANITYCHECK(SCL_DETAIL);
-
- r= sys_datacopy(msg->m_source, (vir_bytes)ptr,
- SELF, (vir_bytes)&args, sizeof(args));
- if (r != OK)
- panic("exec_newmem: sys_datacopy failed: %d", r);
-
- /* Minimum stack region (not preallocated)
- * Stopgap for better rlimit-based stack size system
- */
- if(args.tot_bytes < MINSTACKREGION) {
- args.tot_bytes = MINSTACKREGION;
- }
-
- /* Check to see if segment sizes are feasible. */
- tc = (vir_clicks) (CLICK_CEIL(args.text_bytes) >> CLICK_SHIFT);
- dc = (vir_clicks) (CLICK_CEIL(args.data_bytes) >> CLICK_SHIFT);
- totc = (vir_clicks) (CLICK_CEIL(args.tot_bytes) >> CLICK_SHIFT);
- sc = (vir_clicks) (CLICK_CEIL(args.args_bytes) >> CLICK_SHIFT);
- if (dc >= totc) {
- printf("VM: newmem: no stack?\n");
- return(ENOEXEC); /* stack must be at least 1 click */
- }
-
- dvir = (args.sep_id ? 0 : tc);
- s_vir = dvir + (totc - sc);
- r = (dvir + dc > s_vir) ? ENOMEM : OK;
- if (r != OK) {
- printf("VM: newmem: no virtual space?\n");
- return r;
- }
-
- /* Allocate new memory and release old memory. Fix map and tell
- * kernel.
- */
- r = new_mem(vmp, args.text_addr, args.text_bytes,
- args.data_addr, args.data_bytes,
- args.args_bytes, args.tot_bytes, &stack_top,
- args.is_elf);
- if (r != OK) {
- printf("VM: newmem: new_mem failed\n");
- return(r);
- }
-
- /* Save file identification to allow it to be shared. */
- vmp->vm_ino = args.st_ino;
- vmp->vm_dev = args.st_dev;
- vmp->vm_ctime = args.enst_ctime;
-
- /* set/clear separate I&D flag */
- if (args.sep_id)
- vmp->vm_flags |= VMF_SEPARATE;
- else
- vmp->vm_flags &= ~VMF_SEPARATE;
-
- msg->VMEN_STACK_TOP = (void *) stack_top;
- msg->VMEN_FLAGS = 0;
- msg->VMEN_FLAGS |= EXC_NM_RF_LOAD_TEXT;
-
- return OK;
-}
-
-/*===========================================================================*
- * new_mem *
- *===========================================================================*/
-static int new_mem(
- struct vmproc *rmp, /* process to get a new memory map */
- vir_bytes text_addr, /* text segement load address */
- vir_bytes text_bytes, /* text segment size in bytes */
- vir_bytes data_addr, /* data segment load address */
- vir_bytes data_bytes, /* size of data (incl bss) in bytes */
- vir_bytes stk_bytes, /* size of initial stack segment in bytes */
- phys_bytes tot_bytes, /* total memory to allocate, including gap */
- vir_bytes *stack_top, /* top of process stack */
- int is_elf
-)
-{
-/* Allocate new memory and release the old memory. Change the map and report
- * the new map to the kernel. Zero the new core image's bss, gap and stack.
- */
-
- vir_clicks text_clicks, data_clicks, gap_clicks, stack_clicks, tot_clicks;
- int r, hadpt = 0;
- struct vmproc *vmpold = &vmproc[VMP_EXECTMP];
- int ptok = 1;
-
- SANITYCHECK(SCL_FUNCTIONS);
-
- assert(rmp->vm_flags & VMF_HASPT);
-
- /* Acquire the new memory. Each of the 4 parts: text, (data+bss), gap,
- * and stack occupies an integral number of clicks, starting at click
- * boundary. The data and bss parts are run together with no space.
- */
- text_clicks = (vir_clicks) (CLICK_CEIL(text_bytes) >> CLICK_SHIFT);
- data_clicks = (vir_clicks) (CLICK_CEIL(data_bytes) >> CLICK_SHIFT);
- stack_clicks = (vir_clicks) (CLICK_CEIL(stk_bytes) >> CLICK_SHIFT);
- tot_clicks = (vir_clicks) (CLICK_CEIL(tot_bytes) >> CLICK_SHIFT);
- gap_clicks = tot_clicks - data_clicks - stack_clicks;
- if ( (int) gap_clicks < 0) {
- printf("VM: new_mem: no gap?\n");
- return(ENOMEM);
- }
-
-
- /* Keep previous process state for recovery; the sanity check functions
- * know about the 'vmpold' slot, so the memory that the exec()ing
- * process is still holding is referenced there.
- *
- * Throw away the old page table to avoid having two process slots
- * using the same vm_pt.
- * Just recreate it in the case that we have to revert.
- */
-SANITYCHECK(SCL_DETAIL);
- rmp->vm_flags &= ~VMF_HASPT;
- pt_free(&rmp->vm_pt);
-
- assert(!(vmpold->vm_flags & VMF_INUSE));
- *vmpold = *rmp; /* copy current state. */
-#if SANITYCHECKS
- map_setparent(vmpold);
-#endif
-
- region_init(&rmp->vm_regions_avl); /* exec()ing process regions thrown out. */
- rmp->vm_region_top = 0;
-SANITYCHECK(SCL_DETAIL);
-
- /* Build new process in current slot, without freeing old
- * one. If it fails, revert.
- */
- SANITYCHECK(SCL_DETAIL);
- if((r=pt_new(&rmp->vm_pt)) != OK) {
- ptok = 0;
- printf("exec_newmem: no new pagetable\n");
- }
-
- SANITYCHECK(SCL_DETAIL);
- if(r != OK || (r=proc_new(rmp,
- VM_PROCSTART, /* where to start the process in the page table */
- text_addr, /* text load address */
- CLICK2ABS(text_clicks),/* how big is the text in bytes, page-aligned */
- data_addr, /* data load address */
- CLICK2ABS(data_clicks),/* how big is data+bss, page-aligned */
- CLICK2ABS(stack_clicks),/* how big is stack, page-aligned */
- CLICK2ABS(gap_clicks), /* how big is gap, page-aligned */
- 0,0, /* not preallocated */
- VM_STACKTOP, /* regular stack top */
- 0, is_elf, 1)) != OK) {
- SANITYCHECK(SCL_DETAIL);
- printf("VM: new_mem: failed\n");
- if(ptok) {
- rmp->vm_flags &= ~VMF_HASPT;
- pt_free(&rmp->vm_pt);
- }
- *rmp = *vmpold; /* undo. */
- map_setparent(rmp);
- clear_proc(vmpold); /* disappear. */
- SANITYCHECK(SCL_DETAIL);
- if(hadpt) {
- if(pt_new(&rmp->vm_pt) != OK) {
- /* We secretly know that making a new pagetable
- * in the same slot if one was there will never fail.
- */
- panic("new_mem: pt_new failed: %d", ENOMEM);
- }
- rmp->vm_flags |= VMF_HASPT;
- SANITYCHECK(SCL_DETAIL);
- if(map_writept(rmp) != OK) {
- printf("VM: warning: exec undo failed\n");
- }
- SANITYCHECK(SCL_DETAIL);
- }
- return r;
- }
- SANITYCHECK(SCL_DETAIL);
- /* new process is made; free and unreference
- * page table and memory still held by exec()ing process.
- */
- SANITYCHECK(SCL_DETAIL);
- free_proc(vmpold);
- clear_proc(vmpold); /* disappear. */
- SANITYCHECK(SCL_DETAIL);
- *stack_top = VM_STACKTOP;
-
- SANITYCHECK(SCL_FUNCTIONS);
-
- return(OK);
-}
-
/*===========================================================================*
* find_kernel_top *
*===========================================================================*/
return CLICK2ABS(kernel_top);
}
+void regular_segs(struct vmproc *vmp)
+{
+ int s;
+ memset(vmp->vm_arch.vm_seg, 0, sizeof(vmp->vm_arch.vm_seg));
+ vmp->vm_arch.vm_seg[T].mem_phys =
+ vmp->vm_arch.vm_seg[D].mem_phys = ABS2CLICK(VM_PROCSTART);
+ vmp->vm_arch.vm_seg[T].mem_len =
+ vmp->vm_arch.vm_seg[D].mem_len =
+ vmp->vm_arch.vm_seg[S].mem_len = ABS2CLICK(VM_DATATOP-VM_PROCSTART);
+ if((s=sys_newmap(vmp->vm_endpoint, vmp->vm_arch.vm_seg)) != OK)
+ panic("regular_segs: sys_newmap failed: %d", s);
+ if((s=pt_bind(&vmp->vm_pt, vmp)) != OK)
+ panic("regular_segs: pt_bind failed: %d", s);
+}
+
/*===========================================================================*
* proc_new *
*===========================================================================*/
void free_proc(struct vmproc *vmp)
{
map_free_proc(vmp);
+ vmp->vm_heap = NULL;
if(vmp->vm_flags & VMF_HASPT) {
vmp->vm_flags &= ~VMF_HASPT;
pt_free(&vmp->vm_pt);
pt_new(&vmp->vm_pt);
vmp->vm_flags |= VMF_HASPT;
pt_bind(&vmp->vm_pt, vmp);
+ regular_segs(vmp);
return OK;
default:
return EINVAL;
CALLMAP(VM_EXIT, do_exit);
CALLMAP(VM_FORK, do_fork);
CALLMAP(VM_BRK, do_brk);
- CALLMAP(VM_EXEC_NEWMEM, do_exec_newmem);
CALLMAP(VM_PUSH_SIG, do_push_sig);
CALLMAP(VM_WILLEXIT, do_willexit);
CALLMAP(VM_ADDDMA, do_adddma);
len += VM_PAGE_SIZE - (len % VM_PAGE_SIZE);
vr = NULL;
- if (m->VMM_ADDR) {
+ if (m->VMM_ADDR || (m->VMM_FLAGS & MAP_FIXED)) {
/* An address is given, first try at that address. */
addr = arch_vir2map(vmp, m->VMM_ADDR);
vr = map_page_region(vmp, addr, 0, len, MAP_NONE,
phys_bytes stack, phys_bytes gap, phys_bytes text_here, phys_bytes
data_here, vir_bytes stacktop, int prealloc_stack, int is_elf, int full);
phys_bytes find_kernel_top(void);
+void regular_segs(struct vmproc *);
/* break.c */
int do_brk(message *msg);
sp -= sizeof(struct sigcontext)
+ 3 * sizeof(char *) + 2 * sizeof(int);
- if ((r=adjust(vmp, vmp->vm_arch.vm_seg[D].mem_len, sp)) != OK) {
- printf("VM: do_push_sig: adjust() failed: %d\n", r);
- return r;
- }
-
return OK;
}