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++]);
// 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++)

View File

@ -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