From 773dcdd3a27c51437cf54239582f62c4af1a9e02 Mon Sep 17 00:00:00 2001 From: Bananymous Date: Thu, 12 Oct 2023 22:59:36 +0300 Subject: [PATCH] Kernel: Check whether ELF address space can be loaded Before reserving address space in SYS_EXEC verify that ELF address space is actually loadable. For example when trying to execute the kernel binary in userspace, binarys address space would overlap with current kernel address space. Now kernel won't crash anymore and will just send SIGKILL to the process calling exec*(). --- LibELF/LibELF/LoadableELF.cpp | 26 ++++++++++++++++++++++++++ LibELF/include/LibELF/LoadableELF.h | 2 ++ kernel/kernel/Process.cpp | 10 ++++++++++ 3 files changed, 38 insertions(+) diff --git a/LibELF/LibELF/LoadableELF.cpp b/LibELF/LibELF/LoadableELF.cpp index 7a580b3a0..9ca3a8bbf 100644 --- a/LibELF/LibELF/LoadableELF.cpp +++ b/LibELF/LibELF/LoadableELF.cpp @@ -27,6 +27,8 @@ namespace LibELF LoadableELF::~LoadableELF() { + if (!m_loaded) + return; for (const auto& program_header : m_program_headers) { switch (program_header.p_type) @@ -155,6 +157,29 @@ namespace LibELF return false; } + bool LoadableELF::is_address_space_free() const + { + for (const auto& program_header : m_program_headers) + { + switch (program_header.p_type) + { + case PT_NULL: + break; + case PT_LOAD: + { + vaddr_t page_vaddr = program_header.p_vaddr & PAGE_ADDR_MASK; + size_t pages = range_page_count(program_header.p_vaddr, program_header.p_memsz); + if (!m_page_table.is_range_free(page_vaddr, pages * PAGE_SIZE)) + return false; + break; + } + default: + ASSERT_NOT_REACHED(); + } + } + return true; + } + void LoadableELF::reserve_address_space() { for (const auto& program_header : m_program_headers) @@ -174,6 +199,7 @@ namespace LibELF ASSERT_NOT_REACHED(); } } + m_loaded = true; } BAN::ErrorOr LoadableELF::load_page_to_memory(vaddr_t address) diff --git a/LibELF/include/LibELF/LoadableELF.h b/LibELF/include/LibELF/LoadableELF.h index 1b3cc4ff4..d4733fa03 100644 --- a/LibELF/include/LibELF/LoadableELF.h +++ b/LibELF/include/LibELF/LoadableELF.h @@ -27,6 +27,7 @@ namespace LibELF Kernel::vaddr_t entry_point() const; bool contains(Kernel::vaddr_t address) const; + bool is_address_space_free() const; void reserve_address_space(); BAN::ErrorOr load_page_to_memory(Kernel::vaddr_t address); @@ -47,6 +48,7 @@ namespace LibELF BAN::Vector m_program_headers; size_t m_virtual_page_count = 0; size_t m_physical_page_count = 0; + bool m_loaded { false }; }; } \ No newline at end of file diff --git a/kernel/kernel/Process.cpp b/kernel/kernel/Process.cpp index acce6aef8..18ca60483 100644 --- a/kernel/kernel/Process.cpp +++ b/kernel/kernel/Process.cpp @@ -123,6 +123,11 @@ namespace Kernel TRY(process->m_cmdline.back().append(path)); process->m_loadable_elf = TRY(load_elf_for_exec(credentials, path, "/"sv, process->page_table())); + if (!process->m_loadable_elf->is_address_space_free()) + { + dprintln("Could not load ELF address space"); + return BAN::Error::from_errno(ENOEXEC); + } process->m_loadable_elf->reserve_address_space(); process->m_is_userspace = true; @@ -460,6 +465,11 @@ namespace Kernel m_loadable_elf.clear(); m_loadable_elf = TRY(load_elf_for_exec(m_credentials, executable_path, m_working_directory, page_table())); + if (!m_loadable_elf->is_address_space_free()) + { + dprintln("ELF has unloadable address space"); + MUST(sys_raise(SIGKILL)); + } m_loadable_elf->reserve_address_space(); m_userspace_info.entry = m_loadable_elf->entry_point();