diff options
author | dzwdz | 2022-08-09 18:29:25 +0200 |
---|---|---|
committer | dzwdz | 2022-08-09 18:29:25 +0200 |
commit | 9438c2fdaf4e75c9218a5fde84f121a7a0abb457 (patch) | |
tree | 4ed0de6a19d2180198d939c042237aa43e751c3a /src/user/lib | |
parent | d51413be236c09f3946d390327595adc109fcf66 (diff) |
user/libc: preserve cwd through exec()
Diffstat (limited to 'src/user/lib')
-rw-r--r-- | src/user/lib/crt0.s | 5 | ||||
-rw-r--r-- | src/user/lib/elfload.c | 46 | ||||
-rw-r--r-- | src/user/lib/include/unistd.h | 6 | ||||
-rw-r--r-- | src/user/lib/stdlib.c | 33 |
4 files changed, 62 insertions, 28 deletions
diff --git a/src/user/lib/crt0.s b/src/user/lib/crt0.s index dd9ab1b..3548264 100644 --- a/src/user/lib/crt0.s +++ b/src/user/lib/crt0.s @@ -8,7 +8,10 @@ _start: call elf_selfreloc mov %rbp, %rsp - /* pushed by _freejmp */ + + pop %rdi + call __setinitialcwd + pop %rdi pop %rsi pop %rdx diff --git a/src/user/lib/elfload.c b/src/user/lib/elfload.c index 7c84f45..b4987f4 100644 --- a/src/user/lib/elfload.c +++ b/src/user/lib/elfload.c @@ -5,6 +5,7 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <unistd.h> #include <user/lib/elf.h> #include <user/lib/elfload.h> @@ -68,36 +69,47 @@ static size_t elf_spread(const void *elf) { * also sets up main's stack */ void _freejmp_chstack(void *entry, void *low, size_t len, char **argv, char **envp, void *stack); // elfload.s _Noreturn void execbuf_chstack(void *stack, void __user *buf, size_t len); -void _freejmp(void *entry, void *low, size_t len, char **argv, char **envp) { - void *stack = (void*)~0; - size_t *stack_w; +void _freejmp(void *entry, void *low, size_t imglen, char **argv, char **envp) { + size_t len; + union {void *b; void **ptr; uintptr_t *n;} stack; + stack.b = (void*)~0; /* default stack location */ + void *cwd; + + /* push cwd */ + len = absolutepath(NULL, NULL, 0); + stack.b -= len; + cwd = stack.b; + getcwd(cwd, len); + + /* push argv */ int argc = 0; if (argv) { - size_t len; for (int i = 0; argv[i]; i++) { - len = strlen(argv[i]) + 1; // including the null byte - stack -= len; - memcpy(stack, argv[i], len); - argv[i] = stack; + len = strlen(argv[i]) + 1; + stack.b -= len; + memcpy(stack.b, argv[i], len); + argv[i] = stack.b; argc++; } len = sizeof(char*) * argc; - stack -= len; - memcpy(stack, argv, len); - argv = stack; + stack.b -= len; + memcpy(stack.b, argv, len); + argv = stack.b; } - stack_w = stack; - *--stack_w = (uintptr_t)envp; - *--stack_w = (uintptr_t)argv; - *--stack_w = argc; - uintptr_t high = (uintptr_t)low + len; + *--(stack.ptr) = envp; + *--(stack.ptr) = argv; + *--(stack.n) = argc; + + *--(stack.ptr) = cwd; + + uintptr_t high = (uintptr_t)low + imglen; uint64_t buf[] = { EXECBUF_SYSCALL, _SYSCALL_MEMFLAG, 0, (uintptr_t)low, 0, 0, 0, EXECBUF_SYSCALL, _SYSCALL_MEMFLAG, high, ~0 - 0xF000 - high, 0, 0, 0, EXECBUF_JMP, (uintptr_t)entry, }; - execbuf_chstack(stack_w, buf, sizeof buf); + execbuf_chstack(stack.b, buf, sizeof buf); } static void *elf_loadmem(struct Elf64_Ehdr *ehdr) { diff --git a/src/user/lib/include/unistd.h b/src/user/lib/include/unistd.h index aedca1b..2b75a13 100644 --- a/src/user/lib/include/unistd.h +++ b/src/user/lib/include/unistd.h @@ -10,8 +10,12 @@ int execv(const char *path, char *const argv[]); int chdir(const char *path); char *getcwd(char *buf, size_t size); /* Converts a relative path to an absolute one, simplifying it if possible. - * If in == NULL - return the length of cwd (without a trailing slash) + * If in == NULL - return the length of cwd. Doesn't include the trailing slash, + * except for the root dir. Includes the null byte. * If size isn't enough to fit the path, returns the amount of bytes needed to fit * it, including the null byte. * @return 0 on failure, length of the path otherwise */ size_t absolutepath(char *out, const char *in, size_t size); + +// TODO put in an internal libc header +void __setinitialcwd(const char *c); diff --git a/src/user/lib/stdlib.c b/src/user/lib/stdlib.c index 566eb3e..a5d2d9b 100644 --- a/src/user/lib/stdlib.c +++ b/src/user/lib/stdlib.c @@ -53,9 +53,19 @@ _Noreturn void abort(void) { } +static const char *__initialcwd; static char *cwd = NULL, *cwd2 = NULL; static size_t cwdcapacity = 0; +static const char *getrealcwd(void) { + /* __initialcwd can't just be initialized with "/" because ld has seemingly + * started to revolt against humanity and not process half the relocations + * it sees. */ + if (cwd) return cwd; + if (__initialcwd) return __initialcwd; + return "/"; +} + int chdir(const char *path) { handle_t h; char *tmp; @@ -66,12 +76,12 @@ int chdir(const char *path) { cwd = realloc(cwd, len); cwd2 = realloc(cwd2, len); } else { - cwd = malloc(len); - cwd[0] = '/'; - cwd[1] = '\0'; - cwd2 = malloc(len); - cwd2[0] = '/'; - cwd2[1] = '\0'; + size_t initlen = strlen(__initialcwd) + 1; + if (len < initlen) + len = initlen; + cwd = malloc(initlen); + cwd2 = malloc(initlen); + memcpy(cwd, __initialcwd, initlen); } } absolutepath(cwd2, path, cwdcapacity); @@ -95,16 +105,17 @@ int chdir(const char *path) { } char *getcwd(char *buf, size_t size) { - const char *realcwd = cwd ? cwd : "/"; + const char *realcwd = getrealcwd(); // TODO bounds checking memcpy(buf, realcwd, strlen(realcwd) + 1); return buf; } size_t absolutepath(char *out, const char *in, size_t size) { - const char *realcwd = cwd ? cwd : "/"; + const char *realcwd = getrealcwd(); size_t len, pos = 0; - if (!in) return strlen(realcwd); + _klogf("realcwd == %x\n", (long)__initialcwd); + if (!in) return strlen(realcwd) + 1; if (!(in[0] == '/')) { len = strlen(realcwd); @@ -133,3 +144,7 @@ size_t absolutepath(char *out, const char *in, size_t size) { return pos; } + +void __setinitialcwd(const char *s) { + __initialcwd = s; +} |