Finalize arg, env, aux migration (1/3) (CXX) (BB)
authorKevin Klues <klueska@cs.berkeley.edu>
Mon, 13 Jul 2015 06:23:20 +0000 (23:23 -0700)
committerBarret Rhoden <brho@cs.berkeley.edu>
Tue, 14 Jul 2015 14:33:16 +0000 (10:33 -0400)
The next 3 commits break up the last steps of migrating our arg, env,
and aux vectors to be passed on the stack instead of in procinfo.  This
now makes us compatible with the SYSV ABI, and thus much less reliant on
sysdep customizations in glibc. (of which we probably missed a bunch we
didn't even realize before).

This commit focuses on the final changes to the kernel internals that
allow us to properly pass this information on the stack. The
populate_stack() function in elf.c now properly fills out the chunk of
the stack responsible for passing this information instead of populating
procinfo. We also needed to fix some stack alignment stuff in
proc_ctx_init() now that we are relying on the stack to contain specific
content. The comments in process64.c outline what this change was.

kern/arch/x86/process64.c
kern/src/elf.c
kern/src/umem.c

index ace62d1..bb15ae5 100644 (file)
@@ -83,12 +83,16 @@ void proc_init_ctx(struct user_context *ctx, uint32_t vcoreid, uintptr_t entryp,
        /* zero the entire structure for any type, prevent potential disclosure */
        memset(ctx, 0, sizeof(struct user_context));
        ctx->type = ROS_SW_CTX;
-       /* Stack pointers in a fresh stackframe need to be such that adding or
-        * subtracting 8 will result in 16 byte alignment (AMD64 ABI).  The reason
-        * is so that input arguments (on the stack) are 16 byte aligned.  The
-        * extra 8 bytes is the retaddr, pushed on the stack.  Compilers know they
-        * can subtract 8 to get 16 byte alignment for instructions like movaps. */
-       sw_tf->tf_rsp = ROUNDDOWN(stack_top, 16) - 8;
+       /* Stack pointers in a fresh stack frame need to be 16 byte aligned
+        * (AMD64 ABI). If we call this function from within load_elf(), it
+        * should already be aligned properly, but we round again here for good
+        * measure. We used to subtract an extra 8 bytes here to allow us to
+        * write our _start() function in C instead of assembly. This was
+        * necessary to account for a preamble inserted the compiler which
+        * assumed a return address was pushed on the stack. Now that we properly
+        * pass our arguments on the stack, we will have to rewrite our _start()
+        * function in assembly to handle things properly. */
+       sw_tf->tf_rsp = ROUNDDOWN(stack_top, 16);
        sw_tf->tf_rip = entryp;
        sw_tf->tf_rbp = 0;      /* for potential backtraces */
        sw_tf->tf_mxcsr = 0x00001f80;   /* x86 default mxcsr */
index 35ce191..2967d15 100644 (file)
@@ -78,26 +78,39 @@ static uintptr_t populate_stack(struct proc *p, int argc, char *argv[],
                return offset;
        }
 
-       /* Get the size of the env and arg strings. */ 
+       /* Start tracking the size of the buffer necessary to hold all of our data
+        * on the stack. Preallocate space for argc, argv, envp, and auxv in this
+        * buffer. */
        int bufsize = 0;
+       bufsize += 1 * sizeof(size_t);
+       bufsize += (auxc + 1) * sizeof(elf_aux_t);
+       bufsize += (envc + 1) * sizeof(char**);
+       bufsize += (argc + 1) * sizeof(char**);
+
+       /* Add in the size of the env and arg strings. */
        int arg_lens[argc];
        int env_lens[envc];
        bufsize += get_lens(argc, argv, arg_lens);
        bufsize += get_lens(envc, envp, env_lens);
 
+       /* Adjust bufsize so that our buffer will ultimately be 16 byte aligned. */
+       bufsize = ROUNDUP(bufsize, 16);
+
        /* Set up pointers to all of the appropriate data regions we map to. */
-       char **new_argv = (char**)(((procinfo_t*)UINFO)->argp);
+       size_t *new_argc = (size_t*)(USTACKTOP - bufsize);
+       char **new_argv = (char**)(new_argc + 1);
        char **new_envp = new_argv + argc + 1;
        elf_aux_t *new_auxv = (elf_aux_t*)(new_envp + envc + 1);
-       char *new_argbuf = ((procinfo_t*)UINFO)->argbuf;
+       char *new_argbuf = (char*)(new_auxv + auxc + 1);
 
        /* Verify that all data associated with our argv, envp, and auxv arrays
         * (and any corresponding strings they point to) will fit in the space
         * alloted. */
-       int psize = argc+1 + envc+1 + sizeof(elf_aux_t)/sizeof(char**)*(auxc+1);
-       if (psize > PROCINFO_MAX_ARGP)
+       if (bufsize > ARG_MAX)
                return 0;
-       if (bufsize > PROCINFO_ARGBUF_SIZE)
+
+       /* Map argc into its final location. */
+       if (memcpy_to_user(p, new_argc, &argc, sizeof(size_t)))
                return 0;
 
        /* Map all data for argv and envp into its final location. */
@@ -116,7 +129,7 @@ static uintptr_t populate_stack(struct proc *p, int argc, char *argv[],
        if (memcpy_to_user(p, new_auxv + auxc, &null_aux, sizeof(elf_aux_t)))
                return 0;
 
-       return USTACKTOP;
+       return USTACKTOP - bufsize;
 }
 
 /* We need the writable flag for ld.  Even though the elf header says it wants
index 6815001..87f4e3a 100644 (file)
@@ -116,12 +116,7 @@ int memcpy_to_user(struct proc *p, void *va, const void *src, size_t len)
                pte = pgdir_walk(p->env_pgdir, start + i * PGSIZE, 0);
                if (!pte_walk_okay(pte))
                        return -EFAULT;
-               /* Temporarily change the permissions here to 'ur' instead of 'urw'
-                * for testing our temporary method of mapping args/envs/aux info
-                * into user-space.  We still map this into procinfo (which is
-                * read-only), but will soon map it to the stack (which is
-                * read-write), so these permissions can change back to normal. */
-               if (pte_is_present(pte) && !pte_has_perm_ur(pte))
+               if (pte_is_present(pte) && !pte_has_perm_urw(pte))
                        return -EFAULT;
                if (!pte_is_present(pte))
                        if (handle_page_fault(p, (uintptr_t)start + i * PGSIZE, PROT_WRITE))