diff --git a/include/lib.h b/include/lib.h index fa2761a3b..512714f66 100644 --- a/include/lib.h +++ b/include/lib.h @@ -21,6 +21,14 @@ #include +struct ps_strings; /* forward declaration for minix_stack_fill. */ + +void minix_stack_params(const char *path, char * const *argv, char * const *envp, + size_t *stack_size, char *overflow, int *argc, int *envc); +void minix_stack_fill(const char *path, int argc, char * const *argv, + int envc, char * const *envp, size_t stack_size, char *frame, + int *vsp, struct ps_strings **psp); + int __execve(const char *_path, char *const _argv[], char *const _envp[], int _nargs, int _nenvps); int _syscall(endpoint_t _who, int _syscallnr, message *_msgptr); diff --git a/include/minix/com.h b/include/minix/com.h index 47c93bccd..860a8e448 100644 --- a/include/minix/com.h +++ b/include/minix/com.h @@ -549,6 +549,7 @@ #define PR_STACK_PTR m1_p1 /* used for stack ptr in sys_exec, sys_getsp */ #define PR_NAME_PTR m1_p2 /* tells where program name is for dmp */ #define PR_IP_PTR m1_p3 /* initial value for ip after exec */ +#define PR_PS_STR_PTR m1_p4 /* pointer to ps_strings, expected by __start */ #define PR_FORK_FLAGS m1_i3 /* optional flags for fork operation */ #define PR_FORK_MSGADDR m1_p1 /* reply message address of forked child */ #define PR_CTX_PTR m1_p1 /* pointer to mcontext_t structure */ @@ -557,9 +558,7 @@ #define PMEXEC_FLAGS m1_i3 /* PMEF_* */ #define PMEF_AUXVECTORS 20 -#define PMEF_EXECNAMELEN1 256 -#define PMEF_AUXVECTORSPACE 0x01 /* space for PMEF_AUXVECTORS on stack */ -#define PMEF_EXECNAMESPACE1 0x02 /* space for PMEF_EXECNAMELEN1 execname */ +#define PMEF_EXECNAMELEN1 PATH_MAX /* Flags for PR_FORK_FLAGS. */ #define PFF_VMINHIBIT 0x01 /* Don't schedule until release by VM. */ @@ -811,11 +810,13 @@ # define PM_FRAME m7_p2 /* arguments and environment */ # define PM_FRAME_LEN m7_i3 /* size of frame */ # define PM_EXECFLAGS m7_i4 /* PMEXEC_FLAGS */ +# define PM_PS_STR m7_i5 /* ps_strings pointer */ /* 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 */ +# define PM_NEWPS_STR m7_i5 /* possibly-changed ps_strings ptr */ /* Additional parameters for PM_FORK and PM_SRV_FORK */ # define PM_PPROC m7_i2 /* parent process endpoint */ @@ -848,6 +849,7 @@ #define EXC_RS_PROC m1_i1 /* process that needs to be restarted */ #define EXC_RS_RESULT m1_i2 /* result of the exec */ #define EXC_RS_PC m1_p1 /* program counter */ +#define EXC_RS_PS_STR m1_p2 /* ps_strings pointer */ /*===========================================================================* * Messages used from VFS to file servers * diff --git a/include/minix/ipc.h b/include/minix/ipc.h index 24ef9eee2..c703ad925 100644 --- a/include/minix/ipc.h +++ b/include/minix/ipc.h @@ -15,7 +15,7 @@ #define M3_STRING 16 /* legacy m3_ca1 size (must not be changed) */ #define M3_LONG_STRING 16 /* current m3_ca1 size (may be increased) */ -typedef struct {int m1i1, m1i2, m1i3; char *m1p1, *m1p2, *m1p3;} mess_1; +typedef struct {int m1i1, m1i2, m1i3; char *m1p1, *m1p2, *m1p3, *m1p4;} mess_1; typedef struct {int m2i1, m2i2, m2i3; long m2l1, m2l2; char *m2p1; short m2s1;} mess_2; typedef struct {int m3i1, m3i2; char *m3p1; char m3ca1[M3_LONG_STRING];} mess_3; @@ -84,6 +84,7 @@ typedef struct { #define m1_p1 m_u.m_m1.m1p1 #define m1_p2 m_u.m_m1.m1p2 #define m1_p3 m_u.m_m1.m1p3 +#define m1_p4 m_u.m_m1.m1p4 #define m2_i1 m_u.m_m2.m2i1 #define m2_i2 m_u.m_m2.m2i2 diff --git a/include/minix/syslib.h b/include/minix/syslib.h index 0d1a922da..c789acc7f 100644 --- a/include/minix/syslib.h +++ b/include/minix/syslib.h @@ -30,8 +30,8 @@ int _sendcall(endpoint_t who, int type, message *msgptr); int sys_abort(int how); int sys_enable_iop(endpoint_t proc_ep); -int sys_exec(endpoint_t proc_ep, char *ptr, char *aout, vir_bytes - initpc); +int sys_exec(endpoint_t proc_ep, char *stack_ptr, char *progname, + vir_bytes pc, vir_bytes ps_str); int sys_fork(endpoint_t parent, endpoint_t child, endpoint_t *, u32_t vm, vir_bytes *); int sys_clear(endpoint_t proc_ep); diff --git a/kernel/arch/earm/memory.c b/kernel/arch/earm/memory.c index 607a3a413..f3a4e260c 100644 --- a/kernel/arch/earm/memory.c +++ b/kernel/arch/earm/memory.c @@ -672,7 +672,8 @@ void memory_init(void) /*===========================================================================* * arch_proc_init * *===========================================================================*/ -void arch_proc_init(struct proc *pr, const u32_t ip, const u32_t sp, char *name) +void arch_proc_init(struct proc *pr, const u32_t ip, const u32_t sp, + const u32_t ps_str, char *name) { arch_proc_reset(pr); strcpy(pr->p_name, name); @@ -680,6 +681,7 @@ void arch_proc_init(struct proc *pr, const u32_t ip, const u32_t sp, char *name) /* set custom state we know */ pr->p_reg.pc = ip; pr->p_reg.sp = sp; + pr->p_reg.retreg = ps_str; /* a.k.a r0*/ } /* TODO keesj: rewrite the free running clock to use callbacks diff --git a/kernel/arch/earm/protect.c b/kernel/arch/earm/protect.c index 73e37a339..2db24007c 100644 --- a/kernel/arch/earm/protect.c +++ b/kernel/arch/earm/protect.c @@ -3,16 +3,17 @@ * for local descriptors in the process table. */ -#include #include +#include + #include #include "kernel/kernel.h" -#include "kernel/proc.h" -#include "archconst.h" +#include "archconst.h" #include "arch_proto.h" +#include #include struct tss_s tss[CONFIG_MAX_CPUS]; @@ -114,6 +115,8 @@ static int libexec_pg_alloc(struct exec_info *execi, vir_bytes vaddr, size_t len void arch_boot_proc(struct boot_image *ip, struct proc *rp) { multiboot_module_t *mod; + struct ps_strings *psp; + char *sp; if(rp->p_nr < 0) return; @@ -134,24 +137,41 @@ void arch_boot_proc(struct boot_image *ip, struct proc *rp) execi.proc_e = ip->endpoint; execi.hdr = (char *) mod->mod_start; /* phys mem direct */ execi.filesize = execi.hdr_len = mod->mod_end - mod->mod_start; - strcpy(execi.progname, ip->proc_name); + strlcpy(execi.progname, ip->proc_name, sizeof(execi.progname)); execi.frame_len = 0; /* callbacks for use in the kernel */ execi.copymem = libexec_copy_memcpy; execi.clearmem = libexec_clear_memset; - execi.allocmem_prealloc_cleared = libexec_pg_alloc; execi.allocmem_prealloc_junk = libexec_pg_alloc; + execi.allocmem_prealloc_cleared = libexec_pg_alloc; execi.allocmem_ondemand = libexec_pg_alloc; execi.clearproc = NULL; /* parse VM ELF binary and alloc/map it into bootstrap pagetable */ - libexec_load_elf(&execi); + if(libexec_load_elf(&execi) != OK) + panic("VM loading failed"); - /* Initialize the server stack pointer. Take it down three words - * to give startup code something to use as "argc", "argv" and "envp". + /* Setup a ps_strings struct on the stack, pointing to the + * following argv, envp. */ + sp = (char *)execi.stack_high; + sp -= sizeof(struct ps_strings); + psp = (struct ps_strings *) sp; + + /* Take the stack pointer down three words to give startup code + * something to use as "argc", "argv" and "envp". */ - arch_proc_init(rp, execi.pc, kinfo.user_sp - 3*4, ip->proc_name); + sp -= (sizeof(void *) + sizeof(void *) + sizeof(int)); + + // linear address space, so it is available. + psp->ps_argvstr = (char **)(sp + sizeof(int)); + psp->ps_nargvstr = 0; + psp->ps_envstr = psp->ps_argvstr + sizeof(void *); + psp->ps_nenvstr = 0; + + arch_proc_init(rp, execi.pc, (vir_bytes)sp, + execi.stack_high - sizeof(struct ps_strings), + ip->proc_name); /* Free VM blob that was just copied into existence. */ add_memmap(&kinfo, mod->mod_start, mod->mod_end-mod->mod_start); diff --git a/kernel/arch/i386/memory.c b/kernel/arch/i386/memory.c index be3687aca..24b866f0b 100644 --- a/kernel/arch/i386/memory.c +++ b/kernel/arch/i386/memory.c @@ -770,7 +770,8 @@ void memory_init(void) /*===========================================================================* * arch_proc_init * *===========================================================================*/ -void arch_proc_init(struct proc *pr, const u32_t ip, const u32_t sp, char *name) +void arch_proc_init(struct proc *pr, const u32_t ip, const u32_t sp, + const u32_t ps_str, char *name) { arch_proc_reset(pr); strlcpy(pr->p_name, name, sizeof(pr->p_name)); @@ -778,6 +779,7 @@ void arch_proc_init(struct proc *pr, const u32_t ip, const u32_t sp, char *name) /* set custom state we know */ pr->p_reg.pc = ip; pr->p_reg.sp = sp; + pr->p_reg.bx = ps_str; } static int oxpcie_mapping_index = -1, diff --git a/kernel/arch/i386/protect.c b/kernel/arch/i386/protect.c index 0a9d2d25d..5baf44f83 100644 --- a/kernel/arch/i386/protect.c +++ b/kernel/arch/i386/protect.c @@ -3,16 +3,17 @@ * for local descriptors in the process table. */ -#include #include +#include + #include #include - #include "kernel/kernel.h" -#include "archconst.h" +#include "archconst.h" #include "arch_proto.h" +#include #include #define INT_GATE_TYPE (INT_286_GATE | DESC_386_BIT) @@ -388,6 +389,8 @@ static int libexec_pg_alloc(struct exec_info *execi, vir_bytes vaddr, size_t len void arch_boot_proc(struct boot_image *ip, struct proc *rp) { multiboot_module_t *mod; + struct ps_strings *psp; + char *sp; if(rp->p_nr < 0) return; @@ -404,7 +407,7 @@ void arch_boot_proc(struct boot_image *ip, struct proc *rp) /* exec parameters */ execi.stack_high = kinfo.user_sp; - execi.stack_size = 64 * 1024; /* not too crazy as it must be preallocated */ + execi.stack_size = 64 * 1024; /* not too crazy as it must be preallocated */ execi.proc_e = ip->endpoint; execi.hdr = (char *) mod->mod_start; /* phys mem direct */ execi.filesize = execi.hdr_len = mod->mod_end - mod->mod_start; @@ -423,14 +426,30 @@ void arch_boot_proc(struct boot_image *ip, struct proc *rp) if(libexec_load_elf(&execi) != OK) panic("VM loading failed"); - /* Initialize the server stack pointer. Take it down three words - * to give startup code something to use as "argc", "argv" and "envp". + /* Setup a ps_strings struct on the stack, pointing to the + * following argv, envp. */ + sp = (char *)execi.stack_high; + sp -= sizeof(struct ps_strings); + psp = (struct ps_strings *) sp; + + /* Take the stack pointer down three words to give startup code + * something to use as "argc", "argv" and "envp". */ - arch_proc_init(rp, execi.pc, kinfo.user_sp - 3*4, ip->proc_name); + sp -= (sizeof(void *) + sizeof(void *) + sizeof(int)); + + // linear address space, so it is available. + psp->ps_argvstr = (char **)(sp + sizeof(int)); + psp->ps_nargvstr = 0; + psp->ps_envstr = psp->ps_argvstr + sizeof(void *); + psp->ps_nenvstr = 0; + + arch_proc_init(rp, execi.pc, (vir_bytes)sp, + execi.stack_high - sizeof(struct ps_strings), + ip->proc_name); /* Free VM blob that was just copied into existence. */ add_memmap(&kinfo, mod->mod_start, mod->mod_end-mod->mod_start); - mod->mod_end = mod->mod_start = 0; + mod->mod_end = mod->mod_start = 0; /* Remember them */ kinfo.vm_allocated_bytes = alloc_for_vm; diff --git a/kernel/proto.h b/kernel/proto.h index 9ac2fd483..a26f9cb56 100644 --- a/kernel/proto.h +++ b/kernel/proto.h @@ -192,7 +192,7 @@ void do_ser_debug(void); int arch_get_params(char *parm, int max); void memory_init(void); void mem_clear_mapcache(void); -void arch_proc_init(struct proc *pr, u32_t, u32_t, char *); +void arch_proc_init(struct proc *pr, u32_t, u32_t, u32_t, char *); int arch_do_vmctl(message *m_ptr, struct proc *p); int vm_contiguous(const struct proc *targetproc, vir_bytes vir_buf, size_t count); diff --git a/kernel/system/do_exec.c b/kernel/system/do_exec.c index 74370544b..9c038a131 100644 --- a/kernel/system/do_exec.c +++ b/kernel/system/do_exec.c @@ -41,7 +41,8 @@ int do_exec(struct proc * caller, message * m_ptr) name[sizeof(name)-1] = '\0'; /* Set process state. */ - arch_proc_init(rp, (u32_t) m_ptr->PR_IP_PTR, (u32_t) m_ptr->PR_STACK_PTR, name); + arch_proc_init(rp, (u32_t) m_ptr->PR_IP_PTR, (u32_t) m_ptr->PR_STACK_PTR, + (u32_t) m_ptr->PR_PS_STR_PTR, name); /* No reply to EXEC call */ RTS_UNSET(rp, RTS_RECEIVING); diff --git a/lib/csu/arch/earm/crt0.S b/lib/csu/arch/earm/crt0.S index 5c964807f..1359874bf 100644 --- a/lib/csu/arch/earm/crt0.S +++ b/lib/csu/arch/earm/crt0.S @@ -36,33 +36,16 @@ RCSID("$NetBSD: crt0.S,v 1.1 2012/08/13 02:49:04 matt Exp $") STRONG_ALIAS(_start,__start) _ENTRY(__start) -#ifdef __minix - mov r3, r2 /* cleanup */ - mov r4, r1 /* obj_main */ - and r5, r5, #0 /* ps_strings, always NULL on MINIX */ - - /* Get argc, argv, and envp from stack */ - ldr r0, [sp, #0] /* get argc */ - add r1, sp, #4 /* argv = sp + 4 */ - add r2, r1, r0, lsl #2 /* envp = argv + argc*4 */ - add r2, r2, #4 /* skip NULL terminator */ -#else /* * We need to swap ps_strings and cleanup */ mov ip, r0 /* ps_strings -> tmp */ mov r0, r2 /* cleanup -> ps_strings */ mov r2, ip /* tmp -> ps_strings */ -#endif /* __minix */ + /* Ensure the stack is properly aligned before calling C code. */ bic sp, sp, #7 -#ifdef __minix - /* Store obj and ps_strings on the stack */ - sub sp, sp, #8 - str r5, [sp, #4] - str r4, [sp, #0] -#endif /* * void ___start(void (*cleanup)(void), * const Obj_Entry *obj, diff --git a/lib/csu/arch/i386/crt0.S b/lib/csu/arch/i386/crt0.S index 1029f7a7d..9adabdd21 100644 --- a/lib/csu/arch/i386/crt0.S +++ b/lib/csu/arch/i386/crt0.S @@ -46,12 +46,4 @@ _ENTRY(__start) pushl %ebx pushl %ecx pushl %edx -#ifdef __minix - movl 12(%esp),%eax - leal 16(%esp),%edx - leal 20(%esp,%eax,4),%ecx - pushl %ecx - pushl %edx - pushl %eax -#endif /* __minix */ call ___start diff --git a/lib/csu/common/crt0-common.c b/lib/csu/common/crt0-common.c index 3766cac1c..98d60adbc 100644 --- a/lib/csu/common/crt0-common.c +++ b/lib/csu/common/crt0-common.c @@ -80,15 +80,12 @@ struct ps_strings *__ps_strings = 0; static char empty_string[] = ""; char *__progname = empty_string; -#ifndef __minix __dead __dso_hidden void ___start(void (*)(void), const Obj_Entry *, struct ps_strings *); +#ifndef __minix #define write(fd, s, n) __syscall(SYS_write, (fd), (s), (n)) #else -__dead __dso_hidden void ___start(int, char **, char **, void (*)(void), - const Obj_Entry *, struct ps_strings *); - #define write(fd, s, n) /* NO write() from here on minix */ #endif @@ -129,30 +126,11 @@ _fini(void) #endif /* HAVE_INITFINI_ARRAY */ void -#ifdef __minix -___start(int argc, char **argv, char **envp, - void (*cleanup)(void), /* from shared loader */ -#else ___start(void (*cleanup)(void), /* from shared loader */ -#endif /* __minix */ const Obj_Entry *obj, /* from shared loader */ struct ps_strings *ps_strings) { -#ifdef __minix - /* LSC: We have not yet updated the way we pass arguments to - the userspace, so here some code to adapt this to the new - ways. */ - struct ps_strings minix_ps_strings; - if (ps_strings == NULL) { - memset(&minix_ps_strings, 0, sizeof(minix_ps_strings)); - - minix_ps_strings.ps_envstr = envp; - minix_ps_strings.ps_argvstr = argv; - minix_ps_strings.ps_nargvstr = argc; - ps_strings = &minix_ps_strings; - } -#endif /* __minix */ if (ps_strings == NULL) _FATAL("ps_strings missing\n"); __ps_strings = ps_strings; diff --git a/lib/libc/sys-minix/Makefile.inc b/lib/libc/sys-minix/Makefile.inc index 38ef33de8..22c409420 100644 --- a/lib/libc/sys-minix/Makefile.inc +++ b/lib/libc/sys-minix/Makefile.inc @@ -23,6 +23,6 @@ SRCS+= accept.c access.c adjtime.c bind.c brk.c sbrk.c m_closefrom.c getsid.c \ getrusage.c # Minix specific syscalls. -SRCS+= cprofile.c lseek64.c sprofile.c _mcontext.c +SRCS+= cprofile.c lseek64.c sprofile.c stack_utils.c _mcontext.c .include "${ARCHDIR}/sys-minix/Makefile.inc" diff --git a/lib/libc/sys-minix/execve.c b/lib/libc/sys-minix/execve.c index 27b350584..95ca5a9db 100644 --- a/lib/libc/sys-minix/execve.c +++ b/lib/libc/sys-minix/execve.c @@ -1,6 +1,4 @@ -/* execve() - basic program execution call Author: Kees J. Bot - * 21 Jan 1994 - */ +/* execve() - basic program execution call */ #include #include "namespace.h" @@ -9,7 +7,9 @@ #include #include #include +#include #include +#include #ifdef __weak_alias __weak_alias(execve, _execve) @@ -17,62 +17,21 @@ __weak_alias(execve, _execve) int execve(const char *path, char * const *argv, char * const *envp) { - char * const *ap; - char * const *ep; - char *frame; - char **vp; - char *sp; - size_t argc; - int extra; - int vectors; - size_t frame_size; - size_t string_off; - size_t n; - int ov; message m; + size_t frame_size = 0; /* Size of the new initial stack. */ + int argc = 0; /* Argument count. */ + int envc = 0; /* Environment count */ + char overflow = 0; /* No overflow yet. */ + char *frame; + struct ps_strings *psp; + int vsp = 0; /* (virtual) Stack pointer in new address space. */ - /* Assumptions: size_t and char *, it's all the same thing. */ - - /* Create a stack image that only needs to be patched up slightly - * by the kernel to be used for the process to be executed. - */ - - ov= 0; /* No overflow yet. */ - frame_size= 0; /* Size of the new initial stack. */ - string_off= 0; /* Offset to start of the strings. */ - argc= 0; /* Argument count. */ - - for (ap= argv; *ap != NULL; ap++) { - n = sizeof(*ap) + strlen(*ap) + 1; - frame_size+= n; - if (frame_size < n) ov= 1; - string_off+= sizeof(*ap); - argc++; - } - - for (ep= envp; *ep != NULL; ep++) { - n = sizeof(*ep) + strlen(*ep) + 1; - frame_size+= n; - if (frame_size < n) ov= 1; - string_off+= sizeof(*ap); - } - - /* 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; - extra = vectors + PMEF_EXECNAMELEN1; - frame_size+= extra; - string_off+= extra; - - /* Align. */ - frame_size= (frame_size + sizeof(char *) - 1) & ~(sizeof(char *) - 1); + minix_stack_params(path, argv, envp, &frame_size, &overflow, + &argc, &envc); /* The party is off if there is an overflow. */ - if (ov || frame_size < 3 * sizeof(char *)) { - errno= E2BIG; + if (overflow) { + errno = E2BIG; return -1; } @@ -82,31 +41,8 @@ int execve(const char *path, char * const *argv, char * const *envp) return -1; } - /* Set arg count, init pointers to vector and string tables. */ - * (size_t *) frame = argc; - vp = (char **) (frame + sizeof(argc)); - sp = frame + string_off; - - /* Load the argument vector and strings. */ - for (ap= argv; *ap != NULL; ap++) { - *vp++= (char *) (sp - frame); - n= strlen(*ap) + 1; - memcpy(sp, *ap, n); - sp+= n; - } - *vp++= NULL; - - /* Load the environment vector and strings. */ - for (ep= envp; *ep != NULL; ep++) { - *vp++= (char *) (sp - frame); - n= strlen(*ep) + 1; - memcpy(sp, *ep, n); - sp+= n; - } - *vp++= NULL; - - /* Padding. */ - while (sp < frame + frame_size) *sp++= 0; + minix_stack_fill(path, argc, argv, envc, envp, frame_size, frame, + &vsp, &psp); /* Clear unused message fields */ memset(&m, 0, sizeof(m)); @@ -116,15 +52,12 @@ int execve(const char *path, char * const *argv, char * const *envp) m.m1_i2 = frame_size; m.m1_p1 = (char *) __UNCONST(path); m.m1_p2 = frame; - - /* Tell PM/VFS we have left space for the aux vectors - * and executable name - */ - m.PMEXEC_FLAGS = PMEF_AUXVECTORSPACE | PMEF_EXECNAMESPACE1; + m.m1_p4 = (char *)(vsp + ((char *)psp - frame)); (void) _syscall(PM_PROC_NR, EXEC, &m); /* Failure, return the memory used for the frame and exit. */ (void) sbrk(-frame_size); + return -1; } diff --git a/lib/libc/sys-minix/stack_utils.c b/lib/libc/sys-minix/stack_utils.c new file mode 100644 index 000000000..ef3807889 --- /dev/null +++ b/lib/libc/sys-minix/stack_utils.c @@ -0,0 +1,177 @@ +/* Utilities to generate a proper C stack. + * + * Author: Lionel A. Sambuc. + */ + +#include +#include "namespace.h" +#include + +#include +#include +#include +#include +#include +#include + +#ifdef __weak_alias +__weak_alias(execve, _execve) +#endif + +extern struct minix_kerninfo *_minix_kerninfo; + +/* Create a stack image that only needs to be patched up slightly by + * the kernel to be used for the process to be executed. + * + * Every pointers are stored here as offset from the frame base, and + * will be adapted as required for the new process address space. + * + * The following parameters are passed by register to either __start + * for static binaries, or _rtld_start for dynamic ones: + * *fct, *ObjEntry, *ps_string + * + * The following stack layout is expected by _rtld(): + * + * | XXXXXXXXXX | 0x0000_00000 + * | ... | + * | ... | Top of the stack + * | argc | + * | *argv1 | points to the first char of the argv1 + * | ... | + * | *argvN | + * | NULL | + * | *env1 | + * | ... | + * | *envN | + * | NULL | + * | ElfAuxV1 | + * | ... | + * | ElfAuxVX | + * | AuxExecName| fully resolve executable name, as an ASCIIZ string, + * at most PMEF_EXECNAMELEN1 long. + * + * Here we put first the strings, then word-align, then ps_strings, to + * comply with the expected layout of NetBSD. This seems to matter for + * the NetBSD ps command, so let's make sure we are compatible... + * + * | strings | Maybe followed by some padding to word-align. + * | **argv | \ + * | argc | +---> ps_string structure content. + * | **env | | + * | envc | / + * | sigcode | On NetBSD, there may be a compatibility stub here, + * +------------+ for native code, it is not present. + * Stack Base , 0xF000_0000, descending stack. + */ + +/* The minimum size of the frame is composed of: + * argc, the NULL terminator for argv as well as one for + * environ, the ELF Aux vectors, executable name and the + * ps_strings struct. */ +#define STACK_MIN_SZ \ +( \ + sizeof(int) + sizeof(void *) * 2 + \ + sizeof(AuxInfo) * PMEF_AUXVECTORS + PMEF_EXECNAMELEN1 + \ + sizeof(struct ps_strings) \ +) + +/***************************************************************************** + * Computes stack size, argc, envc, for a given set of path, argv, envp. * + *****************************************************************************/ +void minix_stack_params(const char *path, char * const *argv, char * const *envp, + size_t *stack_size, char *overflow, int *argc, int *envc) +{ + char * const *p; + size_t const min_size = STACK_MIN_SZ; + + *stack_size = min_size; /* Size of the new initial stack. */ + *overflow = 0; /* No overflow yet. */ + *argc = 0; /* Argument count. */ + *envc = 0; /* Environment count */ + + /* Compute and add the size required to store argv and env. */ + for (p = argv; *p != NULL; p++) { + size_t const n = sizeof(*p) + strlen(*p) + 1; + *stack_size += n; + if (*stack_size < n) { + *overflow = 1; + } + (*argc)++; + } + + for (p = envp; *p != NULL; p++) { + size_t const n = sizeof(*p) + strlen(*p) + 1; + *stack_size += n; + if (*stack_size < n) { + *overflow = 1; + } + (*envc)++; + } + + /* Compute the aligned frame size. */ + *stack_size = (*stack_size + sizeof(void *) - 1) & + ~(sizeof(void *) - 1); + + if (*stack_size < min_size) { + /* This is possible only in case of overflow. */ + *overflow = 1; + } +} + +/***************************************************************************** + * Generate a stack in the buffer frame, ready to be used. * + *****************************************************************************/ +void minix_stack_fill(const char *path, int argc, char * const *argv, + int envc, char * const *envp, size_t stack_size, char *frame, + int *vsp, struct ps_strings **psp) +{ + char * const *p; + + /* Frame pointers (a.k.a stack pointer within the buffer in current + * address space.) */ + char *fp; /* byte aligned */ + char **fpw; /* word aligned */ + + size_t const min_size = STACK_MIN_SZ; + + /* Virtual address of the stack pointer, in new memory space. */ + *vsp = _minix_kerninfo->kinfo->user_sp - stack_size; + + /* Fill in the frame now. */ + fpw = (char **) frame; + *fpw++ = (char *) argc; + + /* The strings themselves are stored after the aux vectors, + * cf. top comment. */ + fp = frame + (min_size - sizeof(struct ps_strings)) + + (envc + argc) * sizeof(char *); + + /* Fill in argv and the environment, as well as copy the strings + * themselves. */ + for (p = argv; *p != NULL; p++) { + size_t const n = strlen(*p) + 1; + *fpw++= (char *)(*vsp + (fp - frame)); + memcpy(fp, *p, n); + fp += n; + } + *fpw++ = NULL; + + for (p = envp; *p != NULL; p++) { + size_t const n = strlen(*p) + 1; + *fpw++= (char *)(*vsp + (fp - frame)); + memcpy(fp, *p, n); + fp += n; + } + *fpw++ = NULL; + + /* Padding, because of the stack alignement. */ + while ((size_t)fp % sizeof(void *)) *fp++= 0; + + /* Fill in the ps_string struct*/ + *psp = (struct ps_strings *) fp; + + (*psp)->ps_argvstr = (char **)(*vsp + sizeof(argc)); + (*psp)->ps_nargvstr = argc; + (*psp)->ps_envstr = (*psp)->ps_argvstr + argc + 1; + (*psp)->ps_nenvstr = envc; +} diff --git a/lib/libexec/exec_general.c b/lib/libexec/exec_general.c index e9145c611..3a38516b9 100644 --- a/lib/libexec/exec_general.c +++ b/lib/libexec/exec_general.c @@ -75,33 +75,6 @@ int libexec_clear_memset(struct exec_info *execi, vir_bytes vaddr, size_t len) return OK; } -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; diff --git a/lib/libexec/libexec.h b/lib/libexec/libexec.h index b9ba03ee5..f7e218fd1 100644 --- a/lib/libexec/libexec.h +++ b/lib/libexec/libexec.h @@ -55,7 +55,6 @@ struct exec_info { 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); -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); diff --git a/lib/libminc/Makefile b/lib/libminc/Makefile index 18da0cf02..2530ed938 100644 --- a/lib/libminc/Makefile +++ b/lib/libminc/Makefile @@ -146,8 +146,8 @@ CPPFLAGS.${i}+= -I${LIBCDIR}/locale .for i in access.c brk.c close.c environ.c execve.c fork.c \ getgid.c getpid.c geteuid.c getuid.c gettimeofday.c getvfsstat.c \ link.c loadname.c _mcontext.c mknod.c mmap.c nanosleep.c open.c \ - read.c reboot.c sbrk.c select.c setuid.c sigprocmask.c stat.c \ - stime.c syscall.c _ucontext.c umask.c unlink.c waitpid.c \ + read.c reboot.c sbrk.c select.c setuid.c sigprocmask.c stack_utils.c \ + stat.c stime.c syscall.c _ucontext.c umask.c unlink.c waitpid.c \ brksize.S _ipc.S _senda.S ucontext.S mmap.c init.c .PATH.c: ${LIBCDIR}/sys-minix .PATH.S: ${ARCHDIR}/sys-minix diff --git a/lib/libsys/sys_exec.c b/lib/libsys/sys_exec.c index cd84d6a39..342dd4a44 100644 --- a/lib/libsys/sys_exec.c +++ b/lib/libsys/sys_exec.c @@ -1,18 +1,17 @@ #include "syslib.h" -int sys_exec(proc_ep, ptr, prog_name, initpc) -endpoint_t proc_ep; /* process that did exec */ -char *ptr; /* new stack pointer */ -char *prog_name; /* name of the new program */ -vir_bytes initpc; +int sys_exec(endpoint_t proc_ep, char *stack_ptr, char *progname, + vir_bytes pc, vir_bytes ps_str) { /* A process has exec'd. Tell the kernel. */ - message m; + message m; - m.PR_ENDPT = proc_ep; - m.PR_STACK_PTR = ptr; - m.PR_NAME_PTR = prog_name; - m.PR_IP_PTR = (char *)initpc; - return(_kernel_call(SYS_EXEC, &m)); + m.PR_ENDPT = proc_ep; + m.PR_STACK_PTR = stack_ptr; + m.PR_NAME_PTR = progname; + m.PR_IP_PTR = (char *)pc; + m.PR_PS_STR_PTR = (char *)ps_str; + + return _kernel_call(SYS_EXEC, &m); } diff --git a/servers/pm/exec.c b/servers/pm/exec.c index 4691c731b..89285920b 100644 --- a/servers/pm/exec.c +++ b/servers/pm/exec.c @@ -48,6 +48,7 @@ int do_exec() m.PM_FRAME = m_in.frame_ptr; m.PM_FRAME_LEN = m_in.msg_frame_len; m.PM_EXECFLAGS = m_in.PMEXEC_FLAGS; + m.PM_PS_STR = (vir_bytes)m_in.m1_p4; /* ps_strings pointer into the frame. */ tell_vfs(mp, &m); @@ -59,7 +60,7 @@ int do_exec() /*===========================================================================* * do_newexec * *===========================================================================*/ -int do_newexec() +int do_newexec(void) { int proc_e, proc_n, allow_setuid; char *ptr; @@ -127,24 +128,25 @@ int do_newexec() /*===========================================================================* * do_execrestart * *===========================================================================*/ -int do_execrestart() +int do_execrestart(void) { int proc_e, proc_n, result; struct mproc *rmp; - vir_bytes pc; + vir_bytes pc, ps_str; if (who_e != RS_PROC_NR) return EPERM; - proc_e= m_in.EXC_RS_PROC; + proc_e = m_in.EXC_RS_PROC; if (pm_isokendpt(proc_e, &proc_n) != OK) { panic("do_execrestart: got bad endpoint: %d", proc_e); } - rmp= &mproc[proc_n]; - result= m_in.EXC_RS_RESULT; - pc= (vir_bytes)m_in.EXC_RS_PC; + rmp = &mproc[proc_n]; + result = m_in.EXC_RS_RESULT; + pc = (vir_bytes)m_in.EXC_RS_PC; + ps_str = (vir_bytes)m_in.EXC_RS_PS_STR; - exec_restart(rmp, result, pc, rmp->mp_frame_addr); + exec_restart(rmp, result, pc, rmp->mp_frame_addr, ps_str); return OK; } @@ -153,11 +155,8 @@ int do_execrestart() /*===========================================================================* * exec_restart * *===========================================================================*/ -void exec_restart(rmp, result, pc, vfs_newsp) -struct mproc *rmp; -int result; -vir_bytes pc; -vir_bytes vfs_newsp; +void exec_restart(struct mproc *rmp, int result, vir_bytes pc, vir_bytes sp, + vir_bytes ps_str) { int r, sn; @@ -199,7 +198,7 @@ vir_bytes vfs_newsp; #endif /* USE_TRACE */ /* Call kernel to exec with SP and PC set by VFS. */ - r= sys_exec(rmp->mp_endpoint, (char *) vfs_newsp, rmp->mp_name, pc); + r = sys_exec(rmp->mp_endpoint, (char *) sp, rmp->mp_name, pc, ps_str); if (r != OK) panic("sys_exec failed: %d", r); } diff --git a/servers/pm/main.c b/servers/pm/main.c index ace611bf4..98103af26 100644 --- a/servers/pm/main.c +++ b/servers/pm/main.c @@ -434,7 +434,7 @@ static void handle_vfs_reply() case PM_EXEC_REPLY: exec_restart(rmp, m_in.PM_STATUS, (vir_bytes)m_in.PM_PC, - (vir_bytes)m_in.PM_NEWSP); + (vir_bytes)m_in.PM_NEWSP, (vir_bytes)m_in.PM_NEWPS_STR); break; diff --git a/servers/pm/proto.h b/servers/pm/proto.h index 0dc30709f..6ee81edf6 100644 --- a/servers/pm/proto.h +++ b/servers/pm/proto.h @@ -20,7 +20,8 @@ int do_brk(void); int do_exec(void); int do_newexec(void); int do_execrestart(void); -void exec_restart(struct mproc *rmp, int result, vir_bytes pc, vir_bytes sp); +void exec_restart(struct mproc *rmp, int result, vir_bytes pc, vir_bytes sp, + vir_bytes ps_str); /* forkexit.c */ int do_fork(void); diff --git a/servers/rs/exec.c b/servers/rs/exec.c index 942b30fe2..9e28d5a9e 100644 --- a/servers/rs/exec.c +++ b/servers/rs/exec.c @@ -1,14 +1,15 @@ #include "inc.h" #include +#include #include +#include #include static int do_exec(int proc_e, char *exec, size_t exec_len, char *progname, - char *frame, int frame_len); -static int exec_restart(int proc_e, int result, vir_bytes pc); + char *frame, int frame_len, vir_bytes ps_str); +static int exec_restart(int proc_e, int result, vir_bytes pc, vir_bytes ps_str); static int read_seg(struct exec_info *execi, off_t off, vir_bytes seg_addr, size_t seg_bytes); -static int exec_restart(int proc_e, int result, vir_bytes pc); /* Array of loaders for different object formats */ static struct exec_loaders { @@ -19,98 +20,51 @@ static struct exec_loaders { }; int srv_execve(int proc_e, char *exec, size_t exec_len, char **argv, - char **UNUSED(Xenvp)) + char **envp) { - char * const *ap; - char * const *ep; + size_t frame_size = 0; /* Size of the new initial stack. */ + int argc = 0; /* Argument count. */ + int envc = 0; /* Environment count */ + char overflow = 0; /* No overflow yet. */ char *frame; - char **vp; - char *sp, *progname; - size_t argc; - size_t frame_size; - size_t string_off; - size_t n; - int ov; + struct ps_strings *psp; + int vsp = 0; /* (virtual) Stack pointer in new address space. */ + + char *progname; int r; - /* Assumptions: size_t and char *, it's all the same thing. */ - - /* Create a stack image that only needs to be patched up slightly - * by the kernel to be used for the process to be executed. - */ - - ov= 0; /* No overflow yet. */ - frame_size= 0; /* Size of the new initial stack. */ - string_off= 0; /* Offset to start of the strings. */ - argc= 0; /* Argument count. */ - - for (ap= argv; *ap != NULL; ap++) { - n = sizeof(*ap) + strlen(*ap) + 1; - frame_size+= n; - if (frame_size < n) ov= 1; - string_off+= sizeof(*ap); - argc++; - } - - /* Add an argument count and two terminating nulls. */ - frame_size+= sizeof(argc) + sizeof(*ap) + sizeof(*ep); - string_off+= sizeof(argc) + sizeof(*ap) + sizeof(*ep); - - /* Align. */ - frame_size= (frame_size + sizeof(char *) - 1) & ~(sizeof(char *) - 1); + minix_stack_params(argv[0], argv, envp, &frame_size, &overflow, + &argc, &envc); /* The party is off if there is an overflow. */ - if (ov || frame_size < 3 * sizeof(char *)) { - errno= E2BIG; - return -1; - } - - /* Allocate space for the stack frame. */ - frame = (char *) malloc(frame_size); - if (!frame) { + if (overflow) { errno = E2BIG; return -1; } - /* Set arg count, init pointers to vector and string tables. */ - * (size_t *) frame = argc; - vp = (char **) (frame + sizeof(argc)); - sp = frame + string_off; - - /* Load the argument vector and strings. */ - for (ap= argv; *ap != NULL; ap++) { - *vp++= (char *) (sp - frame); - n= strlen(*ap) + 1; - memcpy(sp, *ap, n); - sp+= n; + /* Allocate space for the stack frame. */ + if ((frame = (char *) sbrk(frame_size)) == (char *) -1) { + errno = E2BIG; + return -1; } - *vp++= NULL; -#if 0 - /* Load the environment vector and strings. */ - for (ep= envp; *ep != NULL; ep++) { - *vp++= (char *) (sp - frame); - n= strlen(*ep) + 1; - memcpy(sp, *ep, n); - sp+= n; - } -#endif - *vp++= NULL; - - /* Padding. */ - while (sp < frame + frame_size) *sp++= 0; + minix_stack_fill(argv[0], argc, argv, envc, envp, frame_size, frame, + &vsp, &psp); (progname=strrchr(argv[0], '/')) ? progname++ : (progname=argv[0]); - r = do_exec(proc_e, exec, exec_len, progname, frame, frame_size); - /* Return the memory used for the frame and exit. */ - free(frame); + r = do_exec(proc_e, exec, exec_len, progname, frame, frame_size, + vsp + ((char *)psp - frame)); + + /* Failure, return the memory used for the frame and exit. */ + (void) sbrk(-frame_size); + return r; } static int do_exec(int proc_e, char *exec, size_t exec_len, char *progname, - char *frame, int frame_len) + char *frame, int frame_len, vir_bytes ps_str) { int r; vir_bytes vsp; @@ -153,35 +107,36 @@ static int do_exec(int proc_e, char *exec, size_t exec_len, char *progname, return r; /* Patch up stack and copy it from RS to new core image. */ - vsp = execi.stack_high; - vsp -= frame_len; - libexec_patch_ptr(frame, vsp); + vsp = execi.stack_high - frame_len; r = sys_datacopy(SELF, (vir_bytes) frame, proc_e, (vir_bytes) vsp, (phys_bytes)frame_len); if (r != OK) { printf("do_exec: copying out new stack failed: %d\n", r); - exec_restart(proc_e, r, execi.pc); + exec_restart(proc_e, r, execi.pc, ps_str); return r; } - return exec_restart(proc_e, OK, execi.pc); + return exec_restart(proc_e, OK, execi.pc, ps_str); } /*===========================================================================* * exec_restart * *===========================================================================*/ -static int exec_restart(int proc_e, int result, vir_bytes pc) +static int exec_restart(int proc_e, int result, vir_bytes pc, vir_bytes ps_str) { int r; message m; - m.m_type= EXEC_RESTART; - m.EXC_RS_PROC= proc_e; - m.EXC_RS_RESULT= result; - m.EXC_RS_PC= (void*)pc; - r= sendrec(PM_PROC_NR, &m); + m.m_type = EXEC_RESTART; + m.EXC_RS_PROC = proc_e; + m.EXC_RS_RESULT = result; + m.EXC_RS_PC = (void *)pc; + m.EXC_RS_PS_STR = (void *)ps_str; + + r = sendrec(PM_PROC_NR, &m); if (r != OK) return r; + return m.m_type; } diff --git a/servers/vfs/exec.c b/servers/vfs/exec.c index 925c82ad7..6f829ef13 100644 --- a/servers/vfs/exec.c +++ b/servers/vfs/exec.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include "fproc.h" #include "path.h" @@ -56,13 +57,13 @@ struct vfs_exec_info { static void lock_exec(void); static void unlock_exec(void); static int patch_stack(struct vnode *vp, char stack[ARG_MAX], - size_t *stk_bytes, char path[PATH_MAX]); + size_t *stk_bytes, char path[PATH_MAX], vir_bytes *vsp); 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); + vir_bytes *vsp, char replace); static void clo_exec(struct fproc *rfp); static int stack_prepare_elf(struct vfs_exec_info *execi, - char *curstack, size_t *frame_len, vir_bytes *vsp, int *extrabase); + char *curstack, size_t *frame_len, vir_bytes *vsp); static int map_header(struct vfs_exec_info *execi); static int read_seg(struct exec_info *execi, off_t off, vir_bytes seg_addr, size_t seg_bytes); @@ -71,7 +72,7 @@ static int read_seg(struct exec_info *execi, off_t off, vir_bytes seg_addr, size /* Array of loaders for different object file formats */ 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); + size_t *frame_len, vir_bytes *vsp); struct exec_loaders { libexec_exec_loadfunc_t load_object; /* load executable into memory */ stackhook_t setup_stack; /* prepare stack before argc and argv push */ @@ -214,16 +215,19 @@ static int vfs_memmap(struct exec_info *execi, *===========================================================================*/ 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 user_exec_flags) + vir_bytes *newsp, vir_bytes *UNUSED(ps_str), int user_exec_flags) + //vir_bytes *newsp, vir_bytes *ps_str, 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. + * + * ps_str is not currently used, but may be if the ps_strings structure has to + * be moved to another location. */ int r, slot; vir_bytes vsp; struct fproc *rfp; - int extrabase = 0; static char mbuf[ARG_MAX]; /* buffer for stack and zeroes */ struct vfs_exec_info execi; int i; @@ -234,8 +238,6 @@ int pm_exec(endpoint_t proc_e, vir_bytes path, size_t path_len, struct lookup resolve; struct fproc *vmfp = &fproc[VM_PROC_NR]; stackhook_t makestack = NULL; - static int n; - n++; struct filp *newfilp = NULL; lock_exec(); @@ -271,6 +273,10 @@ int pm_exec(endpoint_t proc_e, vir_bytes path, size_t path_len, FAILCHECK(r); } + /* Compute the current virtual stack pointer, has to be done before calling + * patch_stack, which needs it, and will adapt as required. */ + vsp = execi.args.stack_high - frame_len; + /* The default is to keep the original user and group IDs */ execi.args.new_uid = rfp->fp_effuid; execi.args.new_gid = rfp->fp_effgid; @@ -297,7 +303,8 @@ int pm_exec(endpoint_t proc_e, vir_bytes path, size_t path_len, * name into fullpath. */ FAILCHECK(fetch_name(path, path_len, fullpath)); - FAILCHECK(patch_stack(execi.vp, mbuf, &frame_len, fullpath)); + FAILCHECK(patch_stack(execi.vp, mbuf, &frame_len, fullpath, &vsp)); + strlcpy(finalexec, fullpath, PATH_MAX); strlcpy(firstexec, fullpath, PATH_MAX); Get_read_vp(execi, fullpath, 1, 0, &resolve, fp); @@ -324,8 +331,10 @@ int pm_exec(endpoint_t proc_e, vir_bytes path, size_t path_len, /* ld.so is linked at 0, but it can relocate itself; we * want it higher to trap NULL pointer dereferences. + * Let's put it below the stack, and reserve 10MB for ld.so. */ - execi.args.load_offset = 0x10000; + execi.args.load_offset = + execi.args.stack_high - execi.args.stack_size - 0xa00000; /* Remember it */ strlcpy(execi.execname, finalexec, PATH_MAX); @@ -389,11 +398,9 @@ int pm_exec(endpoint_t proc_e, vir_bytes path, size_t path_len, *pc = execi.args.pc; /* call a stack-setup function if this executable type wants it */ - vsp = execi.args.stack_high - frame_len; - if(makestack) FAILCHECK(makestack(&execi, mbuf, &frame_len, &vsp, &extrabase)); + if(makestack) FAILCHECK(makestack(&execi, mbuf, &frame_len, &vsp)); - /* Patch up stack and copy it from VFS to new core image. */ - libexec_patch_ptr(mbuf, vsp + extrabase); + /* Copy the stack from VFS to new core image. */ FAILCHECK(sys_datacopy(SELF, (vir_bytes) mbuf, proc_e, (vir_bytes) vsp, (phys_bytes)frame_len)); @@ -433,102 +440,118 @@ pm_execfinal: return(r); } -static int stack_prepare_elf(struct vfs_exec_info *execi, char *frame, size_t *framelen, - vir_bytes *newsp, int *extrabase) -{ - AuxInfo *a, *term; - Elf_Ehdr *elf_header; - int nulls; - char **mysp = (char **) frame, - **mysp_end = (char **) ((char *)frame + *framelen); +/* This is a copy-paste of the same macro in libc/sys-minix/stack_utils.c. Keep it + * synchronized. */ +#define STACK_MIN_SZ \ +( \ + sizeof(int) + sizeof(void *) * 2 + \ + sizeof(AuxInfo) * PMEF_AUXVECTORS + PMEF_EXECNAMELEN1 + \ + sizeof(struct ps_strings) \ +) - if(!execi->is_dyn) +static int stack_prepare_elf(struct vfs_exec_info *execi, char *frame, size_t *frame_size, + vir_bytes *vsp) +{ + AuxInfo *aux_vec, *aux_vec_end; + vir_bytes vap; /* Address in proc space of the first AuxVec. */ + Elf_Ehdr const * const elf_header = (Elf_Ehdr *) execi->args.hdr; + struct ps_strings const * const psp = (struct ps_strings *) + (frame + (*frame_size - sizeof(struct ps_strings))); + + size_t const execname_len = strlen(execi->execname); + + if (!execi->is_dyn) return OK; - assert(execi->args.hdr_len >= sizeof(*elf_header)); - elf_header = (Elf_Ehdr *) execi->args.hdr; + if (execi->args.hdr_len < sizeof(*elf_header)) { + printf("VFS: malformed ELF headers for exec\n"); + return ENOEXEC; + } - /* exec() promises stack space. Now find it. */ - mysp++; /* skip argc */ + if (*frame_size < STACK_MIN_SZ) { + printf("VFS: malformed stack for exec(), smaller than minimum" + " possible size.\n"); + return ENOEXEC; + } - /* 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++; + /* Find first Aux vector in the stack frame. */ + vap = (vir_bytes)(psp->ps_envstr + (psp->ps_nenvstr + 1)); + aux_vec = (AuxInfo *) (frame + (vap - *vsp)); + aux_vec_end = aux_vec + PMEF_AUXVECTORS; + + if (((char *)aux_vec < frame) || + ((char *)aux_vec > (frame + *frame_size))) { + printf("VFS: malformed stack for exec(), first AuxVector is" + " not on the stack.\n"); + return ENOEXEC; + } + + if (((char *)aux_vec_end < frame) || + ((char *)aux_vec_end > (frame + *frame_size))) { + printf("VFS: malformed stack for exec(), last AuxVector is" + " not on the stack.\n"); + return ENOEXEC; } /* 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. + * 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. + * 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. */ - 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; - *newsp -= 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++; } +#define AUXINFO(a, type, value) \ + do { \ + if (a < aux_vec_end) { \ + a->a_type = type; \ + a->a_v = value; \ + a++; \ + } else { \ + printf("VFS: No more room for ELF AuxVec type %d, skipping it for %s\n", type, execi->execname); \ + (aux_vec_end - 1)->a_type = AT_NULL; \ + (aux_vec_end - 1)->a_v = 0; \ + } \ + } while(0) + + AUXINFO(aux_vec, AT_BASE, execi->args.load_base); + AUXINFO(aux_vec, AT_ENTRY, execi->args.pc); + AUXINFO(aux_vec, AT_EXECFD, execi->elf_main_fd); #if 0 - AUXINFO(AT_PHENT, elf_header->e_phentsize); - AUXINFO(AT_PHNUM, elf_header->e_phnum); + AUXINFO(aux_vec, AT_PHDR, XXX ); /* should be &phdr[0] */ + AUXINFO(aux_vec, AT_PHENT, elf_header->e_phentsize); + AUXINFO(aux_vec, AT_PHNUM, elf_header->e_phnum); + + AUXINFO(aux_vec, AT_RUID, XXX); + AUXINFO(aux_vec, AT_RGID, XXX); #endif - 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); + AUXINFO(aux_vec, AT_EUID, execi->args.new_uid); + AUXINFO(aux_vec, AT_EGID, execi->args.new_gid); + AUXINFO(aux_vec, AT_PAGESZ, PAGE_SIZE); - /* This is where we add the AT_NULL */ - term = a; - - /* Always terminate with AT_NULL */ - AUXINFO(AT_NULL, 0); - - /* Empty space starts here, if any. */ - if((execi->userflags & PMEF_EXECNAMESPACE1) - && strlen(execi->execname) < PMEF_EXECNAMELEN1) { + if(execname_len < PMEF_EXECNAMELEN1) { char *spacestart; vir_bytes userp; - /* Make space for the real closing AT_NULL entry. */ - AUXINFO(AT_NULL, 0); - - /* Empty space starts here; we can put the name here. */ - spacestart = (char *) a; - strlcpy(spacestart, execi->execname, PATH_MAX); + /* Empty space starts after aux_vec table; we can put the name + * here. */ + spacestart = (char *) aux_vec + 2 * sizeof(AuxInfo); + strlcpy(spacestart, execi->execname, PMEF_EXECNAMELEN1); + memset(spacestart + execname_len, '\0', + PMEF_EXECNAMELEN1 - execname_len); /* What will the address of the string for the user be */ - userp = *newsp + (spacestart-frame); + userp = *vsp + (spacestart - frame); /* Move back to where the AT_NULL is */ - a = term; - AUXINFO(AT_SUN_EXECNAME, userp); - AUXINFO(AT_NULL, 0); + AUXINFO(aux_vec, AT_SUN_EXECNAME, userp); } + /* Always terminate with AT_NULL */ + AUXINFO(aux_vec, AT_NULL, 0); + return OK; } @@ -547,11 +570,12 @@ static int is_script(struct vfs_exec_info *execi) /*===========================================================================* * patch_stack * *===========================================================================*/ -static int patch_stack(vp, stack, stk_bytes, path) +static int patch_stack(vp, stack, stk_bytes, path, vsp) struct vnode *vp; /* pointer for open script file */ char stack[ARG_MAX]; /* pointer to stack image within VFS */ size_t *stk_bytes; /* size of initial stack */ char path[PATH_MAX]; /* path to script file */ +vir_bytes *vsp; { /* Patch the argument vector to include the path name of the script to be * interpreted, and all strings on the #! line. Returns the path name of @@ -565,13 +589,14 @@ char path[PATH_MAX]; /* path to script file */ char buf[_MAX_BLOCK_SIZE]; /* Make 'path' the new argv[0]. */ - if (!insert_arg(stack, stk_bytes, path, REPLACE)) return(ENOMEM); + if (!insert_arg(stack, stk_bytes, path, vsp, REPLACE)) return(ENOMEM); pos = 0; /* Read from the start of the file */ /* Issue request */ r = req_readwrite(vp->v_fs_e, vp->v_inode_nr, pos, READING, VFS_PROC_NR, (vir_bytes) buf, _MAX_BLOCK_SIZE, &new_pos, &cum_io); + if (r != OK) return(r); n = vp->v_size; @@ -600,7 +625,7 @@ char path[PATH_MAX]; /* path to script file */ while (sp > path && sp[-1] != ' ' && sp[-1] != '\t') --sp; interp = sp; - if (!insert_arg(stack, stk_bytes, sp, INSERT)) { + if (!insert_arg(stack, stk_bytes, sp, vsp, INSERT)) { printf("VFS: patch_stack: insert_arg failed\n"); return(ENOMEM); } @@ -609,71 +634,91 @@ char path[PATH_MAX]; /* path to script file */ if(!interp) return ENOEXEC; - /* Round *stk_bytes up to the size of a pointer for alignment contraints. */ - *stk_bytes= ((*stk_bytes + PTRSIZE - 1) / PTRSIZE) * PTRSIZE; - if (interp != path) memmove(path, interp, strlen(interp)+1); + return(OK); } /*===========================================================================* * insert_arg * *===========================================================================*/ -static int insert_arg( -char stack[ARG_MAX], /* pointer to stack image within PM */ -size_t *stk_bytes, /* size of initial stack */ -char *arg, /* argument to prepend/replace as new argv[0] */ -int replace -) +static int insert_arg(char stack[ARG_MAX], size_t *stk_bytes, char *arg, + vir_bytes *vsp, char replace) { -/* Patch the stack so that arg will become argv[0]. Be careful, the stack may - * be filled with garbage, although it normally looks like this: - * nargs argv[0] ... argv[nargs-1] NULL envp[0] ... NULL - * followed by the strings "pointed" to by the argv[i] and the envp[i]. The - * pointers are really offsets from the start of stack. - * Return true iff the operation succeeded. - */ - int offset; - vir_bytes a0, a1; - size_t old_bytes = *stk_bytes; + /* Patch the stack so that arg will become argv[0]. Be careful, the + * stack may be filled with garbage, although it normally looks like + * this: + * nargs argv[0] ... argv[nargs-1] NULL envp[0] ... NULL + * followed by the strings "pointed" to by the argv[i] and the envp[i]. + * The * pointers are in the new process address space. + * + * Return true iff the operation succeeded. + */ + struct ps_strings *psp; + int offset; + size_t old_bytes = *stk_bytes; - /* Prepending arg adds at least one string and a zero byte. */ - offset = strlen(arg) + 1; + int const arg_len = strlen(arg) + 1; - a0 = (int) ((char **) stack)[1]; /* argv[0] */ - if (a0 < 4 * PTRSIZE || a0 >= old_bytes) return(FALSE); + /* Offset to argv[0][0] in the stack frame. */ + int const a0 = (int)(((char **)stack)[1] - *vsp); - a1 = a0; /* a1 will point to the strings to be moved */ - if (replace) { - /* Move a1 to the end of argv[0][] (argv[1] if nargs > 1). */ - do { - if (a1 == old_bytes) return(FALSE); - --offset; - } while (stack[a1++] != 0); - } else { - offset += PTRSIZE; /* new argv[0] needs new pointer in argv[] */ - a0 += PTRSIZE; /* location of new argv[0][]. */ - } + /* Check that argv[0] points within the stack frame. */ + if ((a0 < 0) || (a0 >= old_bytes)) { + printf("vfs:: argv[0][] not within stack range!! %i\n", a0); + return FALSE; + } - /* stack will grow by offset bytes (or shrink by -offset bytes) */ - if ((*stk_bytes += offset) > ARG_MAX) return(FALSE); + if (!replace) { + /* Prepending arg adds one pointer, one string and a zero byte. */ + offset = arg_len + PTRSIZE; + } else { + /* replacing argv[0] with arg adds the difference in length of + * the two strings. Make sure we don't go beyond the stack size + * when computing the length of the current argv[0]. */ + offset = arg_len - strnlen(stack + a0, ARG_MAX - a0 - 1); + } - /* Reposition the strings by offset bytes */ - memmove(stack + a1 + offset, stack + a1, old_bytes - a1); + /* As ps_strings follows the strings, ensure the offset is word aligned. */ + offset = offset + (PTRSIZE - ((PTRSIZE + offset) % PTRSIZE)); - strlcpy(stack + a0, arg, PATH_MAX); /* Put arg in the new space. */ + /* The stack will grow (or shrink) by offset bytes. */ + if ((*stk_bytes += offset) > ARG_MAX) { + printf("vfs:: offset too big!! %d (max %d)\n", *stk_bytes, + ARG_MAX); + return FALSE; + } - if (!replace) { - /* Make space for a new argv[0]. */ - memmove(stack + 2 * PTRSIZE, stack + 1 * PTRSIZE, a0 - 2 * PTRSIZE); + /* Reposition the strings by offset bytes */ + memmove(stack + a0 + offset, stack + a0, old_bytes - a0); - ((char **) stack)[0]++; /* nargs++; */ - } - /* Now patch up argv[] and envp[] by offset. */ - libexec_patch_ptr(stack, (vir_bytes) offset); - ((char **) stack)[1] = (char *) a0; /* set argv[0] correctly */ - return(TRUE); + /* Put arg in the new space, leaving padding in front of it. */ + strlcpy(stack + a0 + offset - arg_len, arg, arg_len); + + if (!replace) { + /* Make space for a new argv[0]. */ + memmove(stack + 2 * PTRSIZE, + stack + 1 * PTRSIZE, a0 - 2 * PTRSIZE); + + ((char **) stack)[0]++; /* nargs++; */ + } + + /* set argv[0] correctly */ + ((char **) stack)[1] = (char *) a0 - arg_len + *vsp; + + /* Update stack pointer in the process address space. */ + *vsp -= offset; + + /* Update argv and envp in ps_strings */ + psp = (struct ps_strings *) (stack + *stk_bytes - sizeof(struct ps_strings)); + psp->ps_argvstr -= (offset / PTRSIZE); + if (!replace) { + psp->ps_nargvstr++; + } + psp->ps_envstr = psp->ps_argvstr + psp->ps_nargvstr + 1; + + return TRUE; } /*===========================================================================* diff --git a/servers/vfs/main.c b/servers/vfs/main.c index 8a9ab6e81..386afa131 100644 --- a/servers/vfs/main.c +++ b/servers/vfs/main.c @@ -845,24 +845,27 @@ static void service_pm_postponed(void) case PM_EXEC: { endpoint_t proc_e; - vir_bytes exec_path, stack_frame; + vir_bytes exec_path, stack_frame, ps_str; size_t exec_path_len, stack_frame_len; proc_e = job_m_in.PM_PROC; - exec_path = (vir_bytes) job_m_in.PM_PATH; - exec_path_len = (size_t) job_m_in.PM_PATH_LEN; - stack_frame = (vir_bytes) job_m_in.PM_FRAME; - stack_frame_len = (size_t) job_m_in.PM_FRAME_LEN; + exec_path = (vir_bytes)job_m_in.PM_PATH; + exec_path_len = (size_t)job_m_in.PM_PATH_LEN; + stack_frame = (vir_bytes)job_m_in.PM_FRAME; + stack_frame_len = (size_t)job_m_in.PM_FRAME_LEN; + ps_str = (vir_bytes)job_m_in.PM_PS_STR; r = pm_exec(proc_e, exec_path, exec_path_len, stack_frame, - stack_frame_len, &pc, &newsp, job_m_in.PM_EXECFLAGS); + stack_frame_len, &pc, &newsp, &ps_str, + job_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_PC = (void *)pc; m_out.PM_STATUS = r; - m_out.PM_NEWSP = (void *) newsp; + m_out.PM_NEWSP = (void *)newsp; + m_out.PM_NEWPS_STR = ps_str; } break; diff --git a/servers/vfs/proto.h b/servers/vfs/proto.h index 0dfc90dbd..919867c20 100644 --- a/servers/vfs/proto.h +++ b/servers/vfs/proto.h @@ -78,7 +78,8 @@ void write_elf_core_file(struct filp *f, int csig, char *exe_name); /* exec.c */ 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); + size_t frame_len, vir_bytes *pc, vir_bytes *newsp, vir_bytes *ps_str, + int flags); /* filedes.c */ void *do_filp_gc(void *arg); diff --git a/servers/vm/main.c b/servers/vm/main.c index 1cef6c7ad..c882cf068 100644 --- a/servers/vm/main.c +++ b/servers/vm/main.c @@ -17,6 +17,8 @@ #include #include +#include + #include #include #include @@ -41,6 +43,7 @@ extern int missing_spares; #include "kernel/proc.h" #include +#include /* Table of calls and a macro to test for being in range. */ struct { @@ -214,13 +217,13 @@ struct vm_exec_info { }; static int libexec_copy_physcopy(struct exec_info *execi, - off_t off, vir_bytes vaddr, size_t len) + off_t off, vir_bytes vaddr, size_t len) { vir_bytes end; struct vm_exec_info *ei = execi->opaque; end = ei->ip->start_addr + ei->ip->len; - assert(ei->ip->start_addr + off + len <= end); - return sys_physcopy(NONE, ei->ip->start_addr + off, + assert(ei->ip->start_addr + off + len <= end); + return sys_physcopy(NONE, ei->ip->start_addr + off, execi->proc_e, vaddr, len); } @@ -256,6 +259,18 @@ static void exec_bootproc(struct vmproc *vmp, struct boot_image *ip) struct exec_info *execi = &vmexeci.execi; char hdr[VM_PAGE_SIZE]; + size_t frame_size = 0; /* Size of the new initial stack. */ + int argc = 0; /* Argument count. */ + int envc = 0; /* Environment count */ + char overflow = 0; /* No overflow yet. */ + struct ps_strings *psp; + + int vsp = 0; /* (virtual) Stack pointer in new address space. */ + char *argv[] = { ip->proc_name, NULL }; + char *envp[] = { NULL }; + char *path = ip->proc_name; + char frame[VM_PAGE_SIZE]; + memset(&vmexeci, 0, sizeof(vmexeci)); if(pt_new(&vmp->vm_pt) != OK) @@ -268,34 +283,55 @@ static void exec_bootproc(struct vmproc *vmp, struct boot_image *ip) (vir_bytes) hdr, sizeof(hdr)) != OK) panic("can't look at boot proc header"); - execi->stack_high = kernel_boot_info.user_sp; - execi->stack_size = DEFAULT_STACK_LIMIT; - execi->proc_e = vmp->vm_endpoint; - execi->hdr = hdr; - execi->hdr_len = sizeof(hdr); - strlcpy(execi->progname, ip->proc_name, sizeof(execi->progname)); - execi->frame_len = 0; + execi->stack_high = kernel_boot_info.user_sp; + execi->stack_size = DEFAULT_STACK_LIMIT; + execi->proc_e = vmp->vm_endpoint; + execi->hdr = hdr; + execi->hdr_len = sizeof(hdr); + strlcpy(execi->progname, ip->proc_name, sizeof(execi->progname)); + execi->frame_len = 0; execi->opaque = &vmexeci; execi->filesize = ip->len; vmexeci.ip = ip; vmexeci.vmp = vmp; - /* callback functions and data */ - execi->copymem = libexec_copy_physcopy; - execi->clearproc = NULL; - execi->clearmem = libexec_clear_sys_memset; + /* callback functions and data */ + execi->copymem = libexec_copy_physcopy; + execi->clearproc = NULL; + execi->clearmem = libexec_clear_sys_memset; execi->allocmem_prealloc_junk = libexec_alloc_vm_prealloc; execi->allocmem_prealloc_cleared = libexec_alloc_vm_prealloc; - execi->allocmem_ondemand = libexec_alloc_vm_ondemand; + execi->allocmem_ondemand = libexec_alloc_vm_ondemand; - if(libexec_load_elf(execi) != OK) + if (libexec_load_elf(execi) != OK) panic("vm: boot process load of process %s (ep=%d) failed\n", - execi->progname,vmp->vm_endpoint); + execi->progname, vmp->vm_endpoint); - if(sys_exec(vmp->vm_endpoint, (char *) execi->stack_high - 12, - (char *) ip->proc_name, execi->pc) != OK) - panic("vm: boot process exec of process %s (ep=%d) failed\n", + /* Setup a minimal stack. */ + minix_stack_params(path, argv, envp, &frame_size, &overflow, &argc, + &envc); + + /* The party is off if there is an overflow, or it is too big for our + * pre-allocated space. */ + if(overflow || frame_size > sizeof(frame)) + panic("vm: could not alloc stack for boot process %s (ep=%d)\n", + execi->progname, vmp->vm_endpoint); + + minix_stack_fill(path, argc, argv, envc, envp, frame_size, frame, &vsp, + &psp); + + if(handle_memory(vmp, vsp, frame_size, 1, NULL, NULL, 0) != OK) + panic("vm: could not map stack for boot process %s (ep=%d)\n", + execi->progname, vmp->vm_endpoint); + + if(sys_datacopy(SELF, (vir_bytes)frame, vmp->vm_endpoint, vsp, frame_size) != OK) + panic("vm: could not copy stack for boot process %s (ep=%d)\n", + execi->progname, vmp->vm_endpoint); + + if(sys_exec(vmp->vm_endpoint, (char *)vsp, execi->progname, execi->pc, + vsp + ((int)psp - (int)frame)) != OK) + panic("vm: boot process exec of process %s (ep=%d) failed\n", execi->progname,vmp->vm_endpoint); /* make it runnable */ @@ -352,6 +388,11 @@ void init_vm(void) init_proc(VM_PROC_NR); pt_init(); + /* Acquire kernel ipc vectors that weren't available + * before VM had determined kernel mappings + */ + __minix_init(); + /* The kernel's freelist does not include boot-time modules; let * the allocator know that the total memory is bigger. */ @@ -450,15 +491,10 @@ void init_vm(void) /* Initialize the structures for queryexit */ init_query_exit(); - - /* Acquire kernel ipc vectors that weren't available - * before VM had determined kernel mappings - */ - __minix_init(); } /*===========================================================================* - * sef_cb_signal_handler * + * sef_cb_signal_handler * *===========================================================================*/ static void sef_cb_signal_handler(int signo) { @@ -482,7 +518,7 @@ static void sef_cb_signal_handler(int signo) } /*===========================================================================* - * map_service * + * map_service * *===========================================================================*/ static int map_service(struct rprocpub *rpub) { diff --git a/test/Makefile b/test/Makefile index 4bfbb5870..71e1501c6 100644 --- a/test/Makefile +++ b/test/Makefile @@ -61,12 +61,6 @@ MINIX_TESTS+= \ 62 .endif # ${MACHINE_ARCH} == "i386" -.if ${MACHINE_ARCH} == "earm" -# LSC Not yet supported on ARM -MKPIC:= no -LDSTATIC:= -static -.endif - .for t in ${MINIX_TESTS} PROGS+= test${t} .endfor