From 9a6cc0dc2d943ddbe2308073c0d8e484c51fa4c9 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 7a580b3a0e..9ca3a8bbfd 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 1b3cc4ff40..d4733fa032 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 acce6aef83..18ca60483a 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();