diff --git a/Kernel/Process.h b/Kernel/Process.h index bc57a6c7c4..5a0485265d 100644 --- a/Kernel/Process.h +++ b/Kernel/Process.h @@ -391,7 +391,6 @@ public: int exec(String path, Vector arguments, Vector environment, int recusion_depth = 0); KResultOr load(NonnullRefPtr main_program_description, RefPtr interpreter_description, const Elf32_Ehdr& main_program_header); - KResultOr get_interpreter_load_offset(const Elf32_Ehdr& main_program_header, FileDescription& main_program_description, FileDescription& interpreter_description); bool is_superuser() const { diff --git a/Kernel/Syscalls/execve.cpp b/Kernel/Syscalls/execve.cpp index 0c74582bef..61a0ffd11a 100644 --- a/Kernel/Syscalls/execve.cpp +++ b/Kernel/Syscalls/execve.cpp @@ -153,6 +153,98 @@ static KResultOr make_userspace_stack_for_main_thread(Region& region, V return new_esp; } +struct RequiredLoadRange { + FlatPtr start { 0 }; + FlatPtr end { 0 }; +}; + +static KResultOr get_required_load_range(FileDescription& program_description) +{ + auto& inode = *(program_description.inode()); + auto vmobject = SharedInodeVMObject::create_with_inode(inode); + + size_t executable_size = inode.size(); + + auto region = MM.allocate_kernel_region_with_vmobject(*vmobject, PAGE_ROUND_UP(executable_size), "ELF memory range calculation", Region::Access::Read); + if (!region) { + dbgln("Could not allocate memory for ELF"); + return ENOMEM; + } + + auto elf_image = ELF::Image(region->vaddr().as_ptr(), executable_size); + if (!elf_image.is_valid()) { + return EINVAL; + } + + RequiredLoadRange range {}; + elf_image.for_each_program_header([&range](const auto& pheader) { + if (pheader.type() != PT_LOAD) + return IterationDecision::Continue; + + auto region_start = (FlatPtr)pheader.vaddr().as_ptr(); + auto region_end = region_start + pheader.size_in_memory(); + if (range.start == 0 || region_start < range.start) + range.start = region_start; + if (range.end == 0 || region_end > range.end) + range.end = region_end; + return IterationDecision::Continue; + }); + + ASSERT(range.end > range.start); + return range; +}; + +static KResultOr get_interpreter_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; + + 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); + } + + if (main_program_header.e_type != ET_EXEC) + return -EINVAL; + + auto main_program_load_range_result = get_required_load_range(main_program_description); + if (main_program_load_range_result.is_error()) + return main_program_load_range_result.error(); + + 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) + return -E2BIG; + + return random_load_offset_in_range(selected_range.start, selected_range.end - selected_range.start); +} + enum class ShouldAllocateTls { No, Yes, @@ -364,98 +456,6 @@ KResultOr Process::load(NonnullRefPtr main_program_ return interpreter_load_result; } -struct RequiredLoadRange { - FlatPtr start { 0 }; - FlatPtr end { 0 }; -}; - -static KResultOr get_required_load_range(FileDescription& program_description) -{ - auto& inode = *(program_description.inode()); - auto vmobject = SharedInodeVMObject::create_with_inode(inode); - - size_t executable_size = inode.size(); - - auto region = MM.allocate_kernel_region_with_vmobject(*vmobject, PAGE_ROUND_UP(executable_size), "ELF memory range calculation", Region::Access::Read); - if (!region) { - dbgln("Could not allocate memory for ELF"); - return ENOMEM; - } - - auto elf_image = ELF::Image(region->vaddr().as_ptr(), executable_size); - if (!elf_image.is_valid()) { - return EINVAL; - } - - RequiredLoadRange range {}; - elf_image.for_each_program_header([&range](const auto& pheader) { - if (pheader.type() != PT_LOAD) - return IterationDecision::Continue; - - auto region_start = (FlatPtr)pheader.vaddr().as_ptr(); - auto region_end = region_start + pheader.size_in_memory(); - if (range.start == 0 || region_start < range.start) - range.start = region_start; - if (range.end == 0 || region_end > range.end) - range.end = region_end; - return IterationDecision::Continue; - }); - - ASSERT(range.end > range.start); - return range; -}; - -KResultOr Process::get_interpreter_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; - - 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); - } - - if (main_program_header.e_type != ET_EXEC) - return -EINVAL; - - auto main_program_load_range_result = get_required_load_range(main_program_description); - if (main_program_load_range_result.is_error()) - return main_program_load_range_result.error(); - - 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) - return -E2BIG; - - return random_load_offset_in_range(selected_range.start, selected_range.end - selected_range.start); -} - int Process::do_exec(NonnullRefPtr main_program_description, Vector arguments, Vector environment, RefPtr interpreter_description, Thread*& new_main_thread, u32& prev_flags, const Elf32_Ehdr& main_program_header) { ASSERT(is_user_process());