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)
This commit is contained in:
Ariel Abreu 2022-07-27 19:48:06 -04:00
parent e385bb9d98
commit afb23ca35e
No known key found for this signature in database
GPG Key ID: 8031B538781E183F
3 changed files with 24 additions and 46 deletions

@ -1 +1 @@
Subproject commit 2101f7a5a5214eb918d0d87725e98236f1d75403 Subproject commit 7fc5c61a80e7434fae12880e4abc8bc2cadebbd3

View File

@ -126,11 +126,12 @@ long sys_execve(const char* fname, const char** argvp, const char** envp)
while (argvp[len++]); while (argvp[len++]);
// Allocate a new argvp // Allocate a new argvp
modargvp = (const char**) __builtin_alloca(sizeof(void*) * (len+3)); modargvp = (const char**) __builtin_alloca(sizeof(void*) * (len+4));
i = 0; i = 0;
modargvp[i++] = mldr_path; modargvp[i++] = mldr_path;
modargvp[i++] = vc.path; // expanded later modargvp[i++] = vc.path; // expanded later
modargvp[i++] = interp;
if (arg != NULL) if (arg != NULL)
modargvp[i++] = arg; modargvp[i++] = arg;
modargvp[i] = fname; modargvp[i] = fname;
@ -149,21 +150,17 @@ long sys_execve(const char* fname, const char** argvp, const char** envp)
path_to_exec = mldr_path; path_to_exec = mldr_path;
} else if (is_macho) { } else if (is_macho) {
const char** modargvp; const char** modargvp;
char *buf;
int len = 0; int len = 0;
// count original arguments // count original arguments
while (argvp[len++]); while (argvp[len++]);
// allocate a new argvp and argv0 // allocate a new argvp and argv0
modargvp = (const char**) __builtin_alloca(sizeof(void*) * (len+1)); modargvp = (const char**) __builtin_alloca(sizeof(void*) * (len+2));
buf = __builtin_alloca(strlen(mldr_path) + 2 + strlen(vc.path));
// set up the new argv0 (mldr path + "!" + executable path) // set up the new argv0 and file path
strcpy(buf, mldr_path); modargvp[0] = mldr_path;
strcat(buf, "!"); modargvp[1] = vc.path;
strcat(buf, vc.path);
modargvp[0] = buf;
// append original arguments // append original arguments
for (int i = 1; i < len+1; i++) for (int i = 1; i < len+1; i++)

View File

@ -102,10 +102,10 @@ int main(int argc, char** argv, char** envp)
{ {
void** sp; void** sp;
int pushCount = 0; int pushCount = 0;
char *filename, *p = NULL; char *filename;
size_t arg_strings_total_size_after = 0; size_t arg_strings_total_size_after = 0;
size_t orig_argv0_len = 0; size_t orig_argv_removed_len = 0;
const char* orig_argv1 = NULL; const char* orig_argv2 = NULL;
mldr_load_results.kernfd = -1; mldr_load_results.kernfd = -1;
mldr_load_results.argc = argc; mldr_load_results.argc = argc;
@ -116,32 +116,14 @@ int main(int argc, char** argv, char** envp)
} }
mldr_load_results.envp = envp; mldr_load_results.envp = envp;
// sys_execve() passes the original file path appended to the mldr path in argv[0]. if (argc <= 2)
if (argc > 0)
p = strchr(argv[0], '!');
if (argc <= 1)
{ {
if (p == NULL) { fprintf(stderr, "mldr is part of Darling. It is not to be executed directly.\n");
fprintf(stderr, "mldr is part of Darling. It is not to be executed directly.\n"); return 1;
return 1;
}
else
{
fprintf(stderr, "mldr: warning: Executing with no argv[0]. Continuing anyway, but this is probably a bug.\n");
}
} }
if (p != NULL) filename = (char*) __builtin_alloca(strlen(argv[1])+1);
{ strcpy(filename, argv[1]);
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]);
}
// allow any process to ptrace us // allow any process to ptrace us
// the only process we really care about being able to do this is the server, // 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 #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. // 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. // 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) // 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 // 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) // 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; for (size_t i = 0; i < 2; ++i) {
orig_argv1 = mldr_load_results.argv[1]; 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) { 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; 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; mldr_load_results.argv[mldr_load_results.argc] = NULL;
memmove(mldr_load_results.argv[0], orig_argv1, arg_strings_total_size_after); 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_argv0_len); memset(mldr_load_results.argv[0] + arg_strings_total_size_after, 0, orig_argv_removed_len);
if (p == NULL) {
vchroot_unexpand_interpreter(&mldr_load_results);
}
// adjust envp (remove special mldr variables) // adjust envp (remove special mldr variables)
// NOTE: same as for argv; here we assume the envp strings are contiguous // NOTE: same as for argv; here we assume the envp strings are contiguous