From 81169ee6e68df436a328cc7325607b7f1af19dab Mon Sep 17 00:00:00 2001 From: Liav A Date: Fri, 8 Sep 2023 20:30:35 +0300 Subject: [PATCH] DynamicLoader: Add an option to explicitly run an ELF executable binary If the user runs /usr/lib/Loader.so and pass a second string to argv, we will try to run it as if it was running that program without invoking the dynamic loader explicitly. --- Userland/DynamicLoader/main.cpp | 54 ++++++++++++++++++++++++++++----- 1 file changed, 47 insertions(+), 7 deletions(-) diff --git a/Userland/DynamicLoader/main.cpp b/Userland/DynamicLoader/main.cpp index 2a82b64304..03ae1f27df 100644 --- a/Userland/DynamicLoader/main.cpp +++ b/Userland/DynamicLoader/main.cpp @@ -4,10 +4,14 @@ * SPDX-License-Identifier: BSD-2-Clause */ +#include +#include #include #include #include +#include #include +#include #include char* __static_environ[] = { nullptr }; // We don't get the environment without some libc workarounds.. @@ -49,8 +53,8 @@ kernel to load this program. This helper program loads the shared libraries needed by the program, prepares the program to run, and runs it. You do not need to invoke -this helper program directly. -)"; +this helper program directly. If you still want to run a program with the loader, +run: /usr/lib/Loader.so [ELF_BINARY])"; fprintf(stderr, "%s", message); } @@ -76,6 +80,30 @@ NAKED void _start(int, char**, char**) #endif } +static ErrorOr open_executable(char const* path) +{ + int rc = open(path, O_RDONLY | O_EXEC); + if (rc < 0) + return Error::from_errno(errno); + int checked_fd = rc; + ArmedScopeGuard close_on_failure([checked_fd] { + close(checked_fd); + }); + + struct stat executable_stat = {}; + rc = fstat(checked_fd, &executable_stat); + if (rc < 0) + return Error::from_errno(errno); + if (!S_ISREG(executable_stat.st_mode)) { + if (S_ISDIR(executable_stat.st_mode)) + return Error::from_errno(EISDIR); + return Error::from_errno(EINVAL); + } + + close_on_failure.disarm(); + return checked_fd; +} + void _entry(int argc, char** argv, char** envp) { char** env; @@ -103,11 +131,23 @@ void _entry(int argc, char** argv, char** envp) if (main_program_path == "/usr/lib/Loader.so"sv) { // We've been invoked directly as an executable rather than as the - // ELF interpreter for some other binary. In the future we may want - // to support launching a program directly from the dynamic loader - // like ld.so on Linux. - display_help(); - _exit(1); + // ELF interpreter for some other binary. The second argv string should + // be the path to the ELF executable, and if we don't have enough strings in argv + // (argc < 2), just fail with message to stderr about this. + + if (argc < 2) { + display_help(); + _exit(1); + } + auto error_or_fd = open_executable(argv[1]); + if (error_or_fd.is_error()) { + warnln("Loader.so: Loading {} failed: {}", argv[1], strerror(error_or_fd.error().code())); + _exit(1); + } + main_program_fd = error_or_fd.release_value(); + main_program_path = argv[1]; + argv++; + argc--; } VERIFY(main_program_fd >= 0);