From 22ebd754d3ea5477d6b203e797f1b7bc18c4678f Mon Sep 17 00:00:00 2001 From: Gunnar Beutner Date: Mon, 10 May 2021 16:16:05 +0200 Subject: [PATCH] Kernel: Fix loading ELF images without PT_INTERP Previously we'd try to load ELF images which did not have an interpreter set with an incorrect load offset of 0, i.e. way outside of the part of the address space where we'd expect either the dynamic loader or the user's executable to reside. This fixes the problem by using get_load_offset for both executables which have an interpreter set and those which don't. Notably this allows us to actually successfully execute the Loader.so binary: courage:~ $ /usr/lib/Loader.so 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. courage:~ $ --- Kernel/Syscalls/execve.cpp | 70 ++++++++++++++++++++------------------ 1 file changed, 37 insertions(+), 33 deletions(-) diff --git a/Kernel/Syscalls/execve.cpp b/Kernel/Syscalls/execve.cpp index 9d2924d9ac6..f8917ede367 100644 --- a/Kernel/Syscalls/execve.cpp +++ b/Kernel/Syscalls/execve.cpp @@ -187,18 +187,18 @@ static KResultOr get_required_load_range(FileDescription& pro return range; }; -static KResultOr get_interpreter_load_offset(const Elf32_Ehdr& main_program_header, FileDescription& main_program_description, FileDescription& interpreter_description) +static KResultOr get_load_offset(const Elf32_Ehdr& main_program_header, FileDescription& main_program_description, FileDescription* interpreter_description) { - constexpr FlatPtr interpreter_load_range_start = 0x08000000; - constexpr FlatPtr interpreter_load_range_size = 65536 * PAGE_SIZE; // 2**16 * PAGE_SIZE = 256MB - constexpr FlatPtr minimum_interpreter_load_offset_randomization_size = 10 * MiB; + constexpr FlatPtr load_range_start = 0x08000000; + constexpr FlatPtr load_range_size = 65536 * PAGE_SIZE; // 2**16 * PAGE_SIZE = 256MB + constexpr FlatPtr minimum_load_offset_randomization_size = 10 * MiB; auto random_load_offset_in_range([](auto start, auto size) { return page_round_down(start + get_good_random() % size); }); if (main_program_header.e_type == ET_DYN) { - return random_load_offset_in_range(interpreter_load_range_start, interpreter_load_range_size); + return random_load_offset_in_range(load_range_start, load_range_size); } if (main_program_header.e_type != ET_EXEC) @@ -210,29 +210,33 @@ static KResultOr get_interpreter_load_offset(const Elf32_Ehdr& main_pro auto main_program_load_range = main_program_load_range_result.value(); - auto interpreter_load_range_result = get_required_load_range(interpreter_description); - if (interpreter_load_range_result.is_error()) - return interpreter_load_range_result.error(); - - auto interpreter_size_in_memory = interpreter_load_range_result.value().end - interpreter_load_range_result.value().start; - auto interpreter_load_range_end = interpreter_load_range_start + interpreter_load_range_size - interpreter_size_in_memory; - - // No intersection - if (main_program_load_range.end < interpreter_load_range_start || main_program_load_range.start > interpreter_load_range_end) - return random_load_offset_in_range(interpreter_load_range_start, interpreter_load_range_size); - - RequiredLoadRange first_available_part = { interpreter_load_range_start, main_program_load_range.start }; - RequiredLoadRange second_available_part = { main_program_load_range.end, interpreter_load_range_end }; - RequiredLoadRange selected_range {}; - // Select larger part - if (first_available_part.end - first_available_part.start > second_available_part.end - second_available_part.start) - selected_range = first_available_part; - else - selected_range = second_available_part; - // If main program is too big and leaves us without enough space for adequate loader randmoization - if (selected_range.end - selected_range.start < minimum_interpreter_load_offset_randomization_size) + if (interpreter_description) { + auto interpreter_load_range_result = get_required_load_range(*interpreter_description); + if (interpreter_load_range_result.is_error()) + return interpreter_load_range_result.error(); + + auto interpreter_size_in_memory = interpreter_load_range_result.value().end - interpreter_load_range_result.value().start; + auto interpreter_load_range_end = load_range_start + load_range_size - interpreter_size_in_memory; + + // No intersection + if (main_program_load_range.end < load_range_start || main_program_load_range.start > interpreter_load_range_end) + return random_load_offset_in_range(load_range_start, load_range_size); + + RequiredLoadRange first_available_part = { load_range_start, main_program_load_range.start }; + RequiredLoadRange second_available_part = { main_program_load_range.end, interpreter_load_range_end }; + + // Select larger part + if (first_available_part.end - first_available_part.start > second_available_part.end - second_available_part.start) + selected_range = first_available_part; + else + selected_range = second_available_part; + } else + selected_range = main_program_load_range; + + // If main program is too big and leaves us without enough space for adequate loader randomization + if (selected_range.end - selected_range.start < minimum_load_offset_randomization_size) return E2BIG; return random_load_offset_in_range(selected_range.start, selected_range.end - selected_range.start); @@ -437,8 +441,13 @@ KResultOr Process::load(NonnullRefPtr main_program_ MemoryManager::enter_process_paging_scope(*this); }); + auto load_offset = get_load_offset(main_program_header, main_program_description, interpreter_description); + if (load_offset.is_error()) { + return load_offset.error(); + } + if (interpreter_description.is_null()) { - auto result = load_elf_object(new_space.release_nonnull(), main_program_description, FlatPtr { 0 }, ShouldAllocateTls::Yes, ShouldAllowSyscalls::No); + auto result = load_elf_object(new_space.release_nonnull(), main_program_description, load_offset.value(), ShouldAllocateTls::Yes, ShouldAllowSyscalls::No); if (result.is_error()) return result.error(); @@ -449,12 +458,7 @@ KResultOr Process::load(NonnullRefPtr main_program_ return result; } - auto interpreter_load_offset = get_interpreter_load_offset(main_program_header, main_program_description, *interpreter_description); - if (interpreter_load_offset.is_error()) { - return interpreter_load_offset.error(); - } - - auto interpreter_load_result = load_elf_object(new_space.release_nonnull(), *interpreter_description, interpreter_load_offset.value(), ShouldAllocateTls::No, ShouldAllowSyscalls::Yes); + auto interpreter_load_result = load_elf_object(new_space.release_nonnull(), *interpreter_description, load_offset.value(), ShouldAllocateTls::No, ShouldAllowSyscalls::Yes); if (interpreter_load_result.is_error()) return interpreter_load_result.error();