From afb23ca35e0ba3327f94152f26bf2b7b9d2db6c1 Mon Sep 17 00:00:00 2001 From: Ariel Abreu Date: Wed, 27 Jul 2022 19:48:06 -0400 Subject: [PATCH] Change the way mldr accepts arguments This new way of accepting arguments allows mldr to work even when its argv0 is modified (e.g. by some other translation layer or an interpreter, or something like Valgrind) --- src/external/darlingserver | 2 +- src/kernel/emulation/linux/process/execve.c | 15 +++--- src/startup/mldr/mldr.c | 53 +++++++-------------- 3 files changed, 24 insertions(+), 46 deletions(-) diff --git a/src/external/darlingserver b/src/external/darlingserver index 2101f7a5a..7fc5c61a8 160000 --- a/src/external/darlingserver +++ b/src/external/darlingserver @@ -1 +1 @@ -Subproject commit 2101f7a5a5214eb918d0d87725e98236f1d75403 +Subproject commit 7fc5c61a80e7434fae12880e4abc8bc2cadebbd3 diff --git a/src/kernel/emulation/linux/process/execve.c b/src/kernel/emulation/linux/process/execve.c index 3787c5893..c806e980b 100644 --- a/src/kernel/emulation/linux/process/execve.c +++ b/src/kernel/emulation/linux/process/execve.c @@ -126,11 +126,12 @@ long sys_execve(const char* fname, const char** argvp, const char** envp) while (argvp[len++]); // Allocate a new argvp - modargvp = (const char**) __builtin_alloca(sizeof(void*) * (len+3)); + modargvp = (const char**) __builtin_alloca(sizeof(void*) * (len+4)); i = 0; modargvp[i++] = mldr_path; modargvp[i++] = vc.path; // expanded later + modargvp[i++] = interp; if (arg != NULL) modargvp[i++] = arg; modargvp[i] = fname; @@ -149,21 +150,17 @@ long sys_execve(const char* fname, const char** argvp, const char** envp) path_to_exec = mldr_path; } else if (is_macho) { const char** modargvp; - char *buf; int len = 0; // count original arguments while (argvp[len++]); // allocate a new argvp and argv0 - modargvp = (const char**) __builtin_alloca(sizeof(void*) * (len+1)); - buf = __builtin_alloca(strlen(mldr_path) + 2 + strlen(vc.path)); + modargvp = (const char**) __builtin_alloca(sizeof(void*) * (len+2)); - // set up the new argv0 (mldr path + "!" + executable path) - strcpy(buf, mldr_path); - strcat(buf, "!"); - strcat(buf, vc.path); - modargvp[0] = buf; + // set up the new argv0 and file path + modargvp[0] = mldr_path; + modargvp[1] = vc.path; // append original arguments for (int i = 1; i < len+1; i++) diff --git a/src/startup/mldr/mldr.c b/src/startup/mldr/mldr.c index a8bc5d806..486cde824 100644 --- a/src/startup/mldr/mldr.c +++ b/src/startup/mldr/mldr.c @@ -102,10 +102,10 @@ int main(int argc, char** argv, char** envp) { void** sp; int pushCount = 0; - char *filename, *p = NULL; + char *filename; size_t arg_strings_total_size_after = 0; - size_t orig_argv0_len = 0; - const char* orig_argv1 = NULL; + size_t orig_argv_removed_len = 0; + const char* orig_argv2 = NULL; mldr_load_results.kernfd = -1; mldr_load_results.argc = argc; @@ -116,32 +116,14 @@ int main(int argc, char** argv, char** envp) } mldr_load_results.envp = envp; - // sys_execve() passes the original file path appended to the mldr path in argv[0]. - if (argc > 0) - p = strchr(argv[0], '!'); - - if (argc <= 1) + if (argc <= 2) { - if (p == NULL) { - fprintf(stderr, "mldr is part of Darling. It is not to be executed directly.\n"); - return 1; - } - else - { - fprintf(stderr, "mldr: warning: Executing with no argv[0]. Continuing anyway, but this is probably a bug.\n"); - } + fprintf(stderr, "mldr is part of Darling. It is not to be executed directly.\n"); + return 1; } - if (p != NULL) - { - filename = (char*) __builtin_alloca(strlen(argv[0])+1); - strcpy(filename, p + 1); - } - else - { - filename = (char*) __builtin_alloca(strlen(argv[1])+1); - strcpy(filename, argv[1]); - } + filename = (char*) __builtin_alloca(strlen(argv[1])+1); + strcpy(filename, argv[1]); // allow any process to ptrace us // the only process we really care about being able to do this is the server, @@ -172,17 +154,20 @@ int main(int argc, char** argv, char** envp) } #endif - // adjust argv (remove mldr's argv[0]) + // adjust argv (remove mldr's argv[0] and target filename) // NOTE: this code assumes that the current argv array points to contiguous strings. // this is not necessarily true, although AFAIK this is always true on Linux. // also note: we do it this way (moving the string contents in addition to the pointers) // so that Linux sees our modified argv array without having to use PR_SET_MM_ARG_START // and PR_SET_MM_ARG_END (since those require CAP_SYS_RESOURCE) - --mldr_load_results.argc; + mldr_load_results.argc -= 2; - orig_argv0_len = strlen(mldr_load_results.argv[0]) + 1; - orig_argv1 = mldr_load_results.argv[1]; + for (size_t i = 0; i < 2; ++i) { + orig_argv_removed_len += strlen(mldr_load_results.argv[i]) + 1; + } + + orig_argv2 = mldr_load_results.argv[2]; for (size_t i = 0; i < mldr_load_results.argc; ++i) { mldr_load_results.argv[i] = mldr_load_results.argv[0] + arg_strings_total_size_after; @@ -190,12 +175,8 @@ int main(int argc, char** argv, char** envp) } mldr_load_results.argv[mldr_load_results.argc] = NULL; - memmove(mldr_load_results.argv[0], orig_argv1, arg_strings_total_size_after); - memset(mldr_load_results.argv[0] + arg_strings_total_size_after, 0, orig_argv0_len); - - if (p == NULL) { - vchroot_unexpand_interpreter(&mldr_load_results); - } + memmove(mldr_load_results.argv[0], orig_argv2, arg_strings_total_size_after); + memset(mldr_load_results.argv[0] + arg_strings_total_size_after, 0, orig_argv_removed_len); // adjust envp (remove special mldr variables) // NOTE: same as for argv; here we assume the envp strings are contiguous