From 747e8de96a180060474a06838fca4701b87f8a9a Mon Sep 17 00:00:00 2001 From: William Marlow Date: Sat, 2 Jan 2021 21:31:01 +0000 Subject: [PATCH] Kernel+Loader.so: Allow dynamic executables without an interpreter Commit a3a9016701e487a5ca92d83b8cff179a190cdeb2 removed the PT_INTERP header from Loader.so which cleaned up some kernel code in execve. Unfortunately it prevents Loader.so from being run as an executable --- Kernel/Process.h | 6 +++--- Kernel/Syscalls/execve.cpp | 33 ++++++++++++++++++++++----------- Userland/DynamicLoader/main.cpp | 5 +++-- 3 files changed, 28 insertions(+), 16 deletions(-) diff --git a/Kernel/Process.h b/Kernel/Process.h index 54a6c2f08a..2f2945be30 100644 --- a/Kernel/Process.h +++ b/Kernel/Process.h @@ -429,7 +429,7 @@ public: Yes, }; - KResultOr load(NonnullRefPtr main_program_description, RefPtr interpreter_description); + KResultOr load(NonnullRefPtr main_program_description, RefPtr interpreter_description, bool is_dynamic); KResultOr load_elf_object(FileDescription& object_description, FlatPtr load_offset, ShouldAllocateTls); bool is_superuser() const @@ -519,10 +519,10 @@ private: void kill_threads_except_self(); void kill_all_threads(); - int do_exec(NonnullRefPtr main_program_description, Vector arguments, Vector environment, RefPtr interpreter_description, Thread*& new_main_thread, u32& prev_flags); + int do_exec(NonnullRefPtr main_program_description, Vector arguments, Vector environment, RefPtr interpreter_description, Thread*& new_main_thread, u32& prev_flags, bool is_dynamic); ssize_t do_write(FileDescription&, const UserOrKernelBuffer&, size_t); - KResultOr> find_elf_interpreter_for_executable(const String& path, char (&first_page)[PAGE_SIZE], int nread, size_t file_size); + KResultOr> find_elf_interpreter_for_executable(const String& path, char (&first_page)[PAGE_SIZE], int nread, size_t file_size); int alloc_fd(int first_candidate_fd = 0); void disown_all_shared_buffers(); diff --git a/Kernel/Syscalls/execve.cpp b/Kernel/Syscalls/execve.cpp index 3af99441e4..fc182ec2d4 100644 --- a/Kernel/Syscalls/execve.cpp +++ b/Kernel/Syscalls/execve.cpp @@ -276,7 +276,7 @@ KResultOr Process::load_elf_object(FileDescription& object_ }; } -KResultOr Process::load(NonnullRefPtr main_program_description, RefPtr interpreter_description) +KResultOr Process::load(NonnullRefPtr main_program_description, RefPtr interpreter_description, bool is_dynamic) { RefPtr old_page_directory; NonnullOwnPtrVector old_regions; @@ -308,7 +308,7 @@ KResultOr Process::load(NonnullRefPtr main m_regions = move(old_regions); }); - if (!interpreter_description) { + if (!is_dynamic) { auto result = load_elf_object(main_program_description, FlatPtr { 0 }, ShouldAllocateTls::Yes); if (result.is_error()) return result.error(); @@ -321,7 +321,8 @@ KResultOr Process::load(NonnullRefPtr main FlatPtr random_offset = get_good_random() * PAGE_SIZE; FlatPtr interpreter_load_offset = 0x08000000 + random_offset; - auto interpreter_load_result = load_elf_object(*interpreter_description, interpreter_load_offset, ShouldAllocateTls::No); + auto interpreter_load_result = load_elf_object((interpreter_description) ? *interpreter_description : *main_program_description, interpreter_load_offset, ShouldAllocateTls::No); + if (interpreter_load_result.is_error()) return interpreter_load_result.error(); @@ -334,7 +335,7 @@ KResultOr Process::load(NonnullRefPtr main return interpreter_load_result; } -int Process::do_exec(NonnullRefPtr main_program_description, Vector arguments, Vector environment, RefPtr interpreter_description, Thread*& new_main_thread, u32& prev_flags) +int Process::do_exec(NonnullRefPtr main_program_description, Vector arguments, Vector environment, RefPtr interpreter_description, Thread*& new_main_thread, u32& prev_flags, bool is_dynamic) { ASSERT(is_user_process()); ASSERT(!Processor::current().in_critical()); @@ -393,7 +394,7 @@ int Process::do_exec(NonnullRefPtr main_program_description, Ve } } - auto load_result_or_error = load(main_program_description, interpreter_description); + auto load_result_or_error = load(main_program_description, interpreter_description, is_dynamic); if (load_result_or_error.is_error()) { dbgln("do_exec({}): Failed to load main program or interpreter", path); return load_result_or_error.error(); @@ -582,7 +583,7 @@ static KResultOr> find_shebang_interpreter_for_executable(const c return KResult(-ENOEXEC); } -KResultOr> Process::find_elf_interpreter_for_executable(const String& path, char (&first_page)[PAGE_SIZE], int nread, size_t file_size) +KResultOr> Process::find_elf_interpreter_for_executable(const String& path, char (&first_page)[PAGE_SIZE], int nread, size_t file_size) { if (nread < (int)sizeof(Elf32_Ehdr)) return KResult(-ENOEXEC); @@ -651,11 +652,17 @@ KResultOr> Process::find_elf_interpreter_for_exec return interpreter_description; } - if (elf_header->e_type != ET_EXEC) { + if (elf_header->e_type == ET_REL) { // We can't exec an ET_REL, that's just an object file from the compiler - // If it's ET_DYN with no PT_INTERP, then we can't load it properly either return KResult(-ENOEXEC); } + if (elf_header->e_type == ET_DYN) { + // If it's ET_DYN with no PT_INTERP, then it's a dynamic executable responsible + // for its own relocation (i.e. it's /usr/lib/Loader.so) + if (path != "/usr/lib/Loader.so") + dbgln("exec({}): WARNING - Dynamic ELF executable without a PT_INTERP header, and isn't /usr/lib/Loader.so"); + return nullptr; + } // No interpreter, but, path refers to a valid elf image return KResult(KSuccess); @@ -709,18 +716,22 @@ int Process::exec(String path, Vector arguments, Vector environm // #2) ELF32 for i386 auto elf_result = find_elf_interpreter_for_executable(path, first_page, nread_or_error.value(), metadata.size); + // Assume a static ELF executable by default RefPtr interpreter_description; + bool is_dynamic = false; // We're getting either an interpreter, an error, or KSuccess (i.e. no interpreter but file checks out) - if (!elf_result.is_error()) + if (!elf_result.is_error()) { + // It's a dynamic ELF executable, with or without an interpreter. Do not allocate TLS interpreter_description = elf_result.value(); - else if (elf_result.error().is_error()) + is_dynamic = true; + } else if (elf_result.error().is_error()) return elf_result.error(); // The bulk of exec() is done by do_exec(), which ensures that all locals // are cleaned up by the time we yield-teleport below. Thread* new_main_thread = nullptr; u32 prev_flags = 0; - int rc = do_exec(move(description), move(arguments), move(environment), move(interpreter_description), new_main_thread, prev_flags); + int rc = do_exec(move(description), move(arguments), move(environment), move(interpreter_description), new_main_thread, prev_flags, is_dynamic); m_exec_tid = 0; diff --git a/Userland/DynamicLoader/main.cpp b/Userland/DynamicLoader/main.cpp index e3a7352a54..0131e65960 100644 --- a/Userland/DynamicLoader/main.cpp +++ b/Userland/DynamicLoader/main.cpp @@ -143,8 +143,6 @@ void _start(int argc, char** argv, char** envp) main_program_name = (const char*)auxvp->a_un.a_ptr; } } - ASSERT(main_program_fd >= 0); - ASSERT(!main_program_name.is_null()); if (main_program_name == "/usr/lib/Loader.so") { // We've been invoked directly as an executable rather than as the @@ -155,6 +153,9 @@ void _start(int argc, char** argv, char** envp) _exit(1); } + ASSERT(main_program_fd >= 0); + ASSERT(!main_program_name.is_empty()); + ELF::DynamicLinker::linker_main(move(main_program_name), main_program_fd, argc, argv, envp); ASSERT_NOT_REACHED(); }