ladybird/Userland/DynamicLoader/main.cpp
Daniel Bertalan f18e7659a6 DynamicLoader: Ensure that backtrace computation stops at _start
If we don't set FP and LR to 0, the Kernel might not stop generating
backtraces when it reaches `_start`'s stack frame, and might continue by
reading garbage memory instead. This leads to a kernel panic, as SafeMem
access faults aren't handled properly in the AArch64 kernel yet.

We might want to ensure that the kernel zeroes out all registers when a
new process is created.
2023-04-23 14:30:59 +02:00

119 lines
3.5 KiB
C++

/*
* Copyright (c) 2020, Itamar S. <itamar8910@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibELF/AuxiliaryVector.h>
#include <LibELF/DynamicLinker.h>
#include <LibELF/Relocation.h>
#include <sys/internals.h>
#include <unistd.h>
char* __static_environ[] = { nullptr }; // We don't get the environment without some libc workarounds..
static void init_libc()
{
environ = __static_environ;
__environ_is_malloced = false;
__stdio_is_initialized = false;
// Initialise the copy of libc included statically in Loader.so,
// initialisation of the dynamic libc.so is done by the DynamicLinker
__libc_init();
}
static void perform_self_relocations(auxv_t* auxvp)
{
// We need to relocate ourselves.
// (these relocations seem to be generated because of our vtables)
FlatPtr base_address = 0;
bool found_base_address = false;
for (; auxvp->a_type != AT_NULL; ++auxvp) {
if (auxvp->a_type == ELF::AuxiliaryValue::BaseAddress) {
base_address = auxvp->a_un.a_val;
found_base_address = true;
}
}
VERIFY(found_base_address);
if (!ELF::perform_relative_relocations(base_address))
exit(1);
}
static void display_help()
{
char const message[] =
R"(You have invoked `Loader.so'. This is the helper program for programs that
use shared libraries. Special directives embedded in executables tell the
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.
)";
fprintf(stderr, "%s", message);
}
extern "C" {
// The compiler expects a previous declaration
void _start(int, char**, char**) __attribute__((used));
void _entry(int, char**, char**) __attribute__((used));
NAKED void _start(int, char**, char**)
{
#if ARCH(AARCH64)
// Make sure backtrace computation stops here by setting FP and LR to 0.
// FIXME: The kernel should ensure that registers are zeroed on program start
asm(
"mov x29, 0\n"
"mov x30, 0\n"
"bl _entry\n");
#else
asm(
"push $0\n"
"jmp _entry@plt\n");
#endif
}
void _entry(int argc, char** argv, char** envp)
{
char** env;
for (env = envp; *env; ++env) {
}
auxv_t* auxvp = (auxv_t*)++env;
perform_self_relocations(auxvp);
init_libc();
int main_program_fd = -1;
DeprecatedString main_program_path;
bool is_secure = false;
for (; auxvp->a_type != AT_NULL; ++auxvp) {
if (auxvp->a_type == ELF::AuxiliaryValue::ExecFileDescriptor) {
main_program_fd = auxvp->a_un.a_val;
}
if (auxvp->a_type == ELF::AuxiliaryValue::ExecFilename) {
main_program_path = (char const*)auxvp->a_un.a_ptr;
}
if (auxvp->a_type == ELF::AuxiliaryValue::Secure) {
is_secure = auxvp->a_un.a_val == 1;
}
}
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);
}
VERIFY(main_program_fd >= 0);
VERIFY(!main_program_path.is_empty());
ELF::DynamicLinker::linker_main(move(main_program_path), main_program_fd, is_secure, argc, argv, envp);
VERIFY_NOT_REACHED();
}
}