mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-25 09:00:22 +00:00
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.
This commit is contained in:
parent
a3073824a9
commit
81169ee6e6
Notes:
sideshowbarker
2024-07-17 22:01:16 +09:00
Author: https://github.com/supercomputer7 Commit: https://github.com/SerenityOS/serenity/commit/81169ee6e6 Pull-request: https://github.com/SerenityOS/serenity/pull/20988 Reviewed-by: https://github.com/ADKaster Reviewed-by: https://github.com/BertalanD ✅ Reviewed-by: https://github.com/kleinesfilmroellchen ✅
1 changed files with 47 additions and 7 deletions
|
@ -4,10 +4,14 @@
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <AK/ScopeGuard.h>
|
||||||
|
#include <Kernel/API/POSIX/sys/stat.h>
|
||||||
#include <LibELF/AuxiliaryVector.h>
|
#include <LibELF/AuxiliaryVector.h>
|
||||||
#include <LibELF/DynamicLinker.h>
|
#include <LibELF/DynamicLinker.h>
|
||||||
#include <LibELF/Relocation.h>
|
#include <LibELF/Relocation.h>
|
||||||
|
#include <fcntl.h>
|
||||||
#include <sys/internals.h>
|
#include <sys/internals.h>
|
||||||
|
#include <syscall.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
char* __static_environ[] = { nullptr }; // We don't get the environment without some libc workarounds..
|
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,
|
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
|
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);
|
fprintf(stderr, "%s", message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,6 +80,30 @@ NAKED void _start(int, char**, char**)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ErrorOr<int> 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)
|
void _entry(int argc, char** argv, char** envp)
|
||||||
{
|
{
|
||||||
char** env;
|
char** env;
|
||||||
|
@ -103,11 +131,23 @@ void _entry(int argc, char** argv, char** envp)
|
||||||
|
|
||||||
if (main_program_path == "/usr/lib/Loader.so"sv) {
|
if (main_program_path == "/usr/lib/Loader.so"sv) {
|
||||||
// We've been invoked directly as an executable rather than as the
|
// We've been invoked directly as an executable rather than as the
|
||||||
// ELF interpreter for some other binary. In the future we may want
|
// ELF interpreter for some other binary. The second argv string should
|
||||||
// to support launching a program directly from the dynamic loader
|
// be the path to the ELF executable, and if we don't have enough strings in argv
|
||||||
// like ld.so on Linux.
|
// (argc < 2), just fail with message to stderr about this.
|
||||||
display_help();
|
|
||||||
_exit(1);
|
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);
|
VERIFY(main_program_fd >= 0);
|
||||||
|
|
Loading…
Reference in a new issue