diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt index 8d5d0938..d25bdd89 100644 --- a/kernel/CMakeLists.txt +++ b/kernel/CMakeLists.txt @@ -22,6 +22,7 @@ set(KERNEL_SOURCES kernel/Device/NullDevice.cpp kernel/Device/RandomDevice.cpp kernel/Device/ZeroDevice.cpp + kernel/ELF.cpp kernel/Errors.cpp kernel/FS/DevFS/FileSystem.cpp kernel/FS/Ext2/FileSystem.cpp @@ -151,10 +152,6 @@ set(KLIBC_SOURCES klibc/string.cpp ) -set(LIBELF_SOURCES - ../userspace/libraries/LibELF/LibELF/LoadableELF.cpp -) - set(LIBFONT_SOURCES ../userspace/libraries/LibFont/Font.cpp ../userspace/libraries/LibFont/PSF.cpp @@ -169,7 +166,6 @@ set(KERNEL_SOURCES ${KERNEL_SOURCES} ${BAN_SOURCES} ${KLIBC_SOURCES} - ${LIBELF_SOURCES} ${LIBFONT_SOURCES} ${LIBINPUT_SOURCE} ) diff --git a/kernel/include/kernel/Process.h b/kernel/include/kernel/Process.h index 512aed9a..c1567aa7 100644 --- a/kernel/include/kernel/Process.h +++ b/kernel/include/kernel/Process.h @@ -22,8 +22,6 @@ #include #include -namespace LibELF { class LoadableELF; } - namespace Kernel { @@ -269,7 +267,6 @@ namespace Kernel OpenFileDescriptorSet m_open_file_descriptors; - BAN::UniqPtr m_loadable_elf; BAN::Vector> m_mapped_regions; pid_t m_sid; diff --git a/kernel/kernel/Process.cpp b/kernel/kernel/Process.cpp index a4170ae2..0db597ba 100644 --- a/kernel/kernel/Process.cpp +++ b/kernel/kernel/Process.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -121,13 +122,8 @@ namespace Kernel auto absolute_path = TRY(process->absolute_path_of(path)); auto executable_inode = TRY(VirtualFileSystem::get().file_from_absolute_path(process->m_credentials, absolute_path, O_EXEC)).inode; - process->m_loadable_elf = TRY(LibELF::LoadableELF::load_from_inode(process->page_table(), process->m_credentials, executable_inode)); - 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(); + auto executable = TRY(ELF::load_from_inode(executable_inode, process->m_credentials, process->page_table())); + process->m_mapped_regions = BAN::move(executable.regions); char** argv = nullptr; { @@ -154,8 +150,21 @@ namespace Kernel MUST(process->m_mapped_regions.push_back(BAN::move(argv_region))); } + if (executable_inode->mode().mode & +Inode::Mode::ISUID) + process->m_credentials.set_euid(executable_inode->uid()); + if (executable_inode->mode().mode & +Inode::Mode::ISGID) + process->m_credentials.set_egid(executable_inode->gid()); + + if (executable.has_interpreter) + { + VirtualFileSystem::File file; + TRY(file.canonical_path.append("")); + file.inode = executable_inode; + process->m_userspace_info.file_fd = TRY(process->m_open_file_descriptors.open(BAN::move(file), O_RDONLY)); + } + process->m_is_userspace = true; - process->m_userspace_info.entry = process->m_loadable_elf->entry_point(); + process->m_userspace_info.entry = executable.entry_point; process->m_userspace_info.argc = 1; process->m_userspace_info.argv = argv; process->m_userspace_info.envp = nullptr; @@ -185,7 +194,6 @@ namespace Kernel { ASSERT(m_threads.empty()); ASSERT(m_mapped_regions.empty()); - ASSERT(!m_loadable_elf); ASSERT(&PageTable::current() != m_page_table.ptr()); } @@ -216,7 +224,6 @@ namespace Kernel // NOTE: We must unmap ranges while the page table is still alive m_mapped_regions.clear(); - m_loadable_elf.clear(); } bool Process::on_thread_exit(Thread& thread) @@ -302,11 +309,6 @@ namespace Kernel meminfo.virt_pages += region->virtual_page_count(); meminfo.phys_pages += region->physical_page_count(); } - if (m_loadable_elf) - { - meminfo.virt_pages += m_loadable_elf->virtual_page_count(); - meminfo.phys_pages += m_loadable_elf->physical_page_count(); - } } size_t bytes = BAN::Math::min(sizeof(proc_meminfo_t) - offset, buffer.size()); @@ -424,15 +426,12 @@ namespace Kernel for (auto& mapped_region : m_mapped_regions) MUST(mapped_regions.push_back(TRY(mapped_region->clone(*page_table)))); - auto loadable_elf = TRY(m_loadable_elf->clone(*page_table)); - Process* forked = create_process(m_credentials, m_pid, m_sid, m_pgrp); forked->m_controlling_terminal = m_controlling_terminal; forked->m_working_directory = BAN::move(working_directory); forked->m_page_table = BAN::move(page_table); forked->m_open_file_descriptors = BAN::move(open_file_descriptors); forked->m_mapped_regions = BAN::move(mapped_regions); - forked->m_loadable_elf = BAN::move(loadable_elf); forked->m_is_userspace = m_is_userspace; forked->m_userspace_info = m_userspace_info; forked->m_has_called_exec = false; @@ -461,7 +460,6 @@ namespace Kernel auto absolute_path = TRY(absolute_path_of(path)); auto executable_inode = TRY(VirtualFileSystem::get().file_from_absolute_path(m_credentials, absolute_path, O_EXEC)).inode; - auto loadable_elf = TRY(LibELF::LoadableELF::load_from_inode(page_table(), m_credentials, executable_inode)); BAN::Vector str_argv; for (int i = 0; argv && argv[i]; i++) @@ -479,29 +477,24 @@ namespace Kernel TRY(str_envp.emplace_back(envp[i])); } - BAN::String executable_path; - TRY(executable_path.append(path)); - m_open_file_descriptors.close_cloexec(); m_mapped_regions.clear(); - m_loadable_elf = BAN::move(loadable_elf); - if (!m_loadable_elf->is_address_space_free()) - { - dprintln("ELF has unloadable address space"); - MUST(sys_kill(pid(), SIGKILL)); - // NOTE: signal will only execute after return from syscall - return BAN::Error::from_errno(EINTR); - } - m_loadable_elf->reserve_address_space(); - m_loadable_elf->update_suid_sgid(m_credentials); - m_userspace_info.entry = m_loadable_elf->entry_point(); - if (m_loadable_elf->has_interpreter()) + auto executable = TRY(ELF::load_from_inode(executable_inode, m_credentials, page_table())); + m_mapped_regions = BAN::move(executable.regions); + + if (executable_inode->mode().mode & +Inode::Mode::ISUID) + m_credentials.set_euid(executable_inode->uid()); + if (executable_inode->mode().mode & +Inode::Mode::ISGID) + m_credentials.set_egid(executable_inode->gid()); + + m_userspace_info.entry = executable.entry_point; + if (executable.has_interpreter) { VirtualFileSystem::File file; TRY(file.canonical_path.append("")); - file.inode = m_loadable_elf->executable(); + file.inode = executable_inode; m_userspace_info.file_fd = TRY(m_open_file_descriptors.open(BAN::move(file), O_RDONLY)); } @@ -845,12 +838,6 @@ namespace Kernel return true; } - if (m_loadable_elf && m_loadable_elf->contains(address)) - { - TRY(m_loadable_elf->load_page_to_memory(address)); - return true; - } - return false; } @@ -2387,10 +2374,6 @@ namespace Kernel return {}; } - // FIXME: elf should use MemoryRegions instead of mapping executables itself - if (m_loadable_elf->contains(vaddr)) - return {}; - unauthorized_access: dwarnln("process {}, thread {} attempted to make an invalid pointer access to 0x{H}->0x{H}", pid(), Thread::current().tid(), vaddr, vaddr + size); Debug::dump_stack_trace(); diff --git a/userspace/libraries/LibELF/LibELF/ELF.cpp b/userspace/libraries/LibELF/LibELF/ELF.cpp deleted file mode 100644 index 566826cd..00000000 --- a/userspace/libraries/LibELF/LibELF/ELF.cpp +++ /dev/null @@ -1,405 +0,0 @@ -#include -#include -#include - -#ifdef __is_kernel -#include -#include -#endif - -#include - -#define ELF_PRINT_HEADERS 0 - -#ifdef __is_kernel -extern uint8_t g_kernel_end[]; -using namespace Kernel; -#endif - -namespace LibELF -{ - -#ifdef __is_kernel - BAN::ErrorOr> ELF::load_from_file(BAN::RefPtr inode) - { - BAN::Vector buffer; - TRY(buffer.resize(inode->size())); - - TRY(inode->read(0, buffer.data(), inode->size())); - - ELF* elf_ptr = new ELF(BAN::move(buffer)); - if (elf_ptr == nullptr) - return BAN::Error::from_errno(ENOMEM); - - auto elf = BAN::UniqPtr::adopt(elf_ptr); - TRY(elf->load()); - - return BAN::move(elf); - } -#else - BAN::ErrorOr ELF::load_from_file(BAN::StringView file_path) - { - ELF* elf = nullptr; - - { - BAN::Vector data; - - int fd = TRY(Kernel::Process::current().open(file_path, O_RDONLY)); - BAN::ScopeGuard _([fd] { MUST(Kernel::Process::current().close(fd)); }); - - struct stat st; - TRY(Kernel::Process::current().fstat(fd, &st)); - - TRY(data.resize(st.st_size)); - - TRY(Kernel::Process::current().read(fd, data.data(), data.size())); - - elf = new ELF(BAN::move(data)); - ASSERT(elf); - } - - if (auto res = elf->load(); res.is_error()) - { - delete elf; - return res.error(); - } - - return elf; - } -#endif - - BAN::ErrorOr ELF::load() - { - if (m_data.size() < EI_NIDENT) - { - dprintln("Too small ELF file"); - return BAN::Error::from_errno(EINVAL); - } - - if (m_data[EI_MAG0] != ELFMAG0 || - m_data[EI_MAG1] != ELFMAG1 || - m_data[EI_MAG2] != ELFMAG2 || - m_data[EI_MAG3] != ELFMAG3) - { - dprintln("Invalid ELF header"); - return BAN::Error::from_errno(EINVAL); - } - - if (m_data[EI_DATA] != ELFDATA2LSB) - { - dprintln("Only little-endian is supported"); - return BAN::Error::from_errno(EINVAL); - } - - if (m_data[EI_VERSION] != EV_CURRENT) - { - dprintln("Invalid ELF version"); - return BAN::Error::from_errno(EINVAL); - } - - if (m_data[EI_CLASS] == ELFCLASS64) - { - if (m_data.size() <= sizeof(Elf64FileHeader)) - { - dprintln("Too small ELF file"); - return BAN::Error::from_errno(EINVAL); - } - - auto& header = file_header64(); - if (!parse_elf64_file_header(header)) - return BAN::Error::from_errno(EINVAL); - - for (size_t i = 0; i < header.e_phnum; i++) - { - auto& program_header = program_header64(i); - if (!parse_elf64_program_header(program_header)) - return BAN::Error::from_errno(EINVAL); - } - - for (size_t i = 1; i < header.e_shnum; i++) - { - auto& section_header = section_header64(i); - if (!parse_elf64_section_header(section_header)) - return BAN::Error::from_errno(EINVAL); - } - } - else if (m_data[EI_CLASS] == ELFCLASS32) - { - if (m_data.size() <= sizeof(Elf32FileHeader)) - { - dprintln("Too small ELF file"); - return BAN::Error::from_errno(EINVAL); - } - - auto& header = file_header32(); - if (!parse_elf32_file_header(header)) - return BAN::Error::from_errno(EINVAL); - - for (size_t i = 0; i < header.e_phnum; i++) - { - auto& program_header = program_header32(i); - if (!parse_elf32_program_header(program_header)) - return BAN::Error::from_errno(EINVAL); - } - - for (size_t i = 1; i < header.e_shnum; i++) - { - auto& section_header = section_header32(i); - if (!parse_elf32_section_header(section_header)) - return BAN::Error::from_errno(EINVAL); - } - } - - return {}; - } - - bool ELF::is_x86_32() const { return m_data[EI_CLASS] == ELFCLASS32; } - bool ELF::is_x86_64() const { return m_data[EI_CLASS] == ELFCLASS64; } - - /* - - 64 bit ELF - - */ - - const char* ELF::lookup_section_name64(uint32_t offset) const - { - return lookup_string64(file_header64().e_shstrndx, offset); - } - - const char* ELF::lookup_string64(size_t table_index, uint32_t offset) const - { - if (table_index == SHN_UNDEF) - return nullptr; - auto& section_header = section_header64(table_index); - return (const char*)m_data.data() + section_header.sh_offset + offset; - } - - bool ELF::parse_elf64_file_header(const Elf64FileHeader& header) - { - if (header.e_type != ET_EXEC) - { - dprintln("Only executable files are supported"); - return false; - } - - if (header.e_version != EV_CURRENT) - { - dprintln("Invalid ELF version"); - return false; - } - - return true; - } - - bool ELF::parse_elf64_program_header(const Elf64ProgramHeader& header) - { -#if ELF_PRINT_HEADERS - dprintln("program header"); - dprintln(" type {H}", header.p_type); - dprintln(" flags {H}", header.p_flags); - dprintln(" offset {H}", header.p_offset); - dprintln(" vaddr {H}", header.p_vaddr); - dprintln(" paddr {H}", header.p_paddr); - dprintln(" filesz {}", header.p_filesz); - dprintln(" memsz {}", header.p_memsz); - dprintln(" align {}", header.p_align); -#endif - (void)header; - return true; - } - - bool ELF::parse_elf64_section_header(const Elf64SectionHeader& header) - { -#if ELF_PRINT_HEADERS - if (auto* name = lookup_section_name64(header.sh_name)) - dprintln("{}", name); - - switch (header.sh_type) - { - case SHT_NULL: - dprintln(" SHT_NULL"); - break; - case SHT_PROGBITS: - dprintln(" SHT_PROGBITS"); - break; - case SHT_SYMTAB: - for (size_t i = 1; i < header.sh_size / header.sh_entsize; i++) - { - auto& symbol = ((const Elf64Symbol*)(m_data.data() + header.sh_offset))[i]; - if (auto* name = lookup_string64(header.sh_link, symbol.st_name)) - dprintln(" {}", name); - } - break; - case SHT_STRTAB: - dprintln(" SHT_STRTAB"); - break; - case SHT_RELA: - dprintln(" SHT_RELA"); - break; - case SHT_NOBITS: - dprintln(" SHT_NOBITS"); - break; - case SHT_REL: - dprintln(" SHT_REL"); - break; - case SHT_SHLIB: - dprintln(" SHT_SHLIB"); - break; - case SHT_DYNSYM: - dprintln(" SHT_DYNSYM"); - break; - default: - ASSERT(false); - } -#endif - (void)header; - return true; - } - - const Elf64FileHeader& ELF::file_header64() const - { - ASSERT(is_x86_64()); - return *(const Elf64FileHeader*)m_data.data(); - } - - const Elf64ProgramHeader& ELF::program_header64(size_t index) const - { - ASSERT(is_x86_64()); - const auto& file_header = file_header64(); - ASSERT(index < file_header.e_phnum); - return *(const Elf64ProgramHeader*)(m_data.data() + file_header.e_phoff + file_header.e_phentsize * index); - } - - const Elf64SectionHeader& ELF::section_header64(size_t index) const - { - ASSERT(is_x86_64()); - const auto& file_header = file_header64(); - ASSERT(index < file_header.e_shnum); - return *(const Elf64SectionHeader*)(m_data.data() + file_header.e_shoff + file_header.e_shentsize * index); - } - - /* - - 32 bit ELF - - */ - - const char* ELF::lookup_section_name32(uint32_t offset) const - { - return lookup_string32(file_header32().e_shstrndx, offset); - } - - const char* ELF::lookup_string32(size_t table_index, uint32_t offset) const - { - if (table_index == SHN_UNDEF) - return nullptr; - auto& section_header = section_header32(table_index); - return (const char*)m_data.data() + section_header.sh_offset + offset; - } - - bool ELF::parse_elf32_file_header(const Elf32FileHeader& header) - { - if (header.e_type != ET_EXEC) - { - dprintln("Only executable files are supported"); - return false; - } - - if (header.e_version != EV_CURRENT) - { - dprintln("Invalid ELF version"); - return false; - } - - return true; - } - - bool ELF::parse_elf32_program_header(const Elf32ProgramHeader& header) - { -#if ELF_PRINT_HEADERS - dprintln("program header"); - dprintln(" type {H}", header.p_type); - dprintln(" flags {H}", header.p_flags); - dprintln(" offset {H}", header.p_offset); - dprintln(" vaddr {H}", header.p_vaddr); - dprintln(" paddr {H}", header.p_paddr); - dprintln(" filesz {}", header.p_filesz); - dprintln(" memsz {}", header.p_memsz); - dprintln(" align {}", header.p_align); -#endif - (void)header; - return true; - } - - bool ELF::parse_elf32_section_header(const Elf32SectionHeader& header) - { -#if ELF_PRINT_HEADERS - if (auto* name = lookup_section_name32(header.sh_name)) - dprintln("{}", name); - - switch (header.sh_type) - { - case SHT_NULL: - dprintln(" SHT_NULL"); - break; - case SHT_PROGBITS: - dprintln(" SHT_PROGBITS"); - break; - case SHT_SYMTAB: - for (size_t i = 1; i < header.sh_size / header.sh_entsize; i++) - { - auto& symbol = ((const Elf32Symbol*)(m_data.data() + header.sh_offset))[i]; - if (auto* name = lookup_string32(header.sh_link, symbol.st_name)) - dprintln(" {}", name); - } - break; - case SHT_STRTAB: - dprintln(" SHT_STRTAB"); - break; - case SHT_RELA: - dprintln(" SHT_RELA"); - break; - case SHT_NOBITS: - dprintln(" SHT_NOBITS"); - break; - case SHT_REL: - dprintln(" SHT_REL"); - break; - case SHT_SHLIB: - dprintln(" SHT_SHLIB"); - break; - case SHT_DYNSYM: - dprintln(" SHT_DYNSYM"); - break; - default: - ASSERT(false); - } -#endif - (void)header; - return true; - } - - const Elf32FileHeader& ELF::file_header32() const - { - ASSERT(is_x86_32()); - return *(const Elf32FileHeader*)m_data.data(); - } - - const Elf32ProgramHeader& ELF::program_header32(size_t index) const - { - ASSERT(is_x86_32()); - const auto& file_header = file_header32(); - ASSERT(index < file_header.e_phnum); - return *(const Elf32ProgramHeader*)(m_data.data() + file_header.e_phoff + file_header.e_phentsize * index); - } - - const Elf32SectionHeader& ELF::section_header32(size_t index) const - { - ASSERT(is_x86_32()); - const auto& file_header = file_header32(); - ASSERT(index < file_header.e_shnum); - return *(const Elf32SectionHeader*)(m_data.data() + file_header.e_shoff + file_header.e_shentsize * index); - } - -} diff --git a/userspace/libraries/LibELF/LibELF/LoadableELF.cpp b/userspace/libraries/LibELF/LibELF/LoadableELF.cpp deleted file mode 100644 index fdc3d4c4..00000000 --- a/userspace/libraries/LibELF/LibELF/LoadableELF.cpp +++ /dev/null @@ -1,422 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include - -namespace LibELF -{ - - using namespace Kernel; - - BAN::ErrorOr> LoadableELF::load_from_inode(PageTable& page_table, const Credentials& credentials, BAN::RefPtr inode) - { - auto elf = TRY(BAN::UniqPtr::create(page_table)); - TRY(elf->initialize(credentials, inode)); - return elf; - } - - LoadableELF::LoadableELF(PageTable& page_table) - : m_page_table(page_table) - { - } - - LoadableELF::~LoadableELF() - { - if (!m_is_loaded) - return; - - for (const auto& header : m_program_headers) - { - ASSERT(header.p_type == PT_LOAD); - - const vaddr_t vaddr = header.p_vaddr & PAGE_ADDR_MASK; - const size_t pages = range_page_count(header.p_vaddr, header.p_memsz); - for (size_t i = 0; i < pages; i++) - if (paddr_t paddr = m_page_table.physical_address_of(vaddr + i * PAGE_SIZE)) - Heap::get().release_page(paddr); - m_page_table.unmap_range(vaddr, pages * PAGE_SIZE); - } - } - - static BAN::ErrorOr read_and_validate_file_header(BAN::RefPtr inode) - { - if ((size_t)inode->size() < sizeof(ElfNativeFileHeader)) - { - dprintln("File is too small to be ELF"); - return BAN::Error::from_errno(ENOEXEC); - } - - ElfNativeFileHeader file_header; - - size_t nread = TRY(inode->read(0, BAN::ByteSpan::from(file_header))); - ASSERT(nread == sizeof(file_header)); - - if (file_header.e_ident[EI_MAG0] != ELFMAG0 || - file_header.e_ident[EI_MAG1] != ELFMAG1 || - file_header.e_ident[EI_MAG2] != ELFMAG2 || - file_header.e_ident[EI_MAG3] != ELFMAG3) - { - dprintln("Not an ELF file"); - return BAN::Error::from_errno(ENOEXEC); - } - - if (file_header.e_ident[EI_DATA] != ELFDATA2LSB) - { - dprintln("Not in little-endian"); - return BAN::Error::from_errno(ENOEXEC); - } - - if (file_header.e_ident[EI_VERSION] != EV_CURRENT) - { - dprintln("Unsupported version {}", file_header.e_ident[EI_VERSION]); - return BAN::Error::from_errno(ENOEXEC); - } - -#if ARCH(i686) - if (file_header.e_ident[EI_CLASS] != ELFCLASS32) -#elif ARCH(x86_64) - if (file_header.e_ident[EI_CLASS] != ELFCLASS64) -#endif - { - dprintln("Not in native format"); - return BAN::Error::from_errno(EINVAL); - } - - if (file_header.e_type != ET_EXEC && file_header.e_type != ET_DYN) - { - dprintln("Unsupported file header type {}", file_header.e_type); - return BAN::Error::from_errno(ENOTSUP); - } - - if (file_header.e_version != EV_CURRENT) - { - dprintln("Unsupported version {}", file_header.e_version); - return BAN::Error::from_errno(EINVAL); - } - - if (file_header.e_phentsize < sizeof(ElfNativeProgramHeader)) - { - dprintln("Too small program header size ({} bytes)", file_header.e_phentsize); - return BAN::Error::from_errno(EINVAL); - } - - return file_header; - } - - BAN::ErrorOr LoadableELF::load_elf_file(const Credentials& credentials, BAN::RefPtr inode) const - { - auto file_header = TRY(read_and_validate_file_header(inode)); - - BAN::Vector pheader_buffer; - TRY(pheader_buffer.resize(file_header.e_phnum * file_header.e_phentsize)); - TRY(inode->read(file_header.e_phoff, BAN::ByteSpan(pheader_buffer.span()))); - - BAN::Vector program_headers; - BAN::RefPtr interp; - - for (size_t i = 0; i < file_header.e_phnum; i++) - { - const auto& pheader = *reinterpret_cast(pheader_buffer.data() + i * file_header.e_phentsize); - if (pheader.p_memsz < pheader.p_filesz) - { - dprintln("Invalid program header, memsz less than filesz"); - return BAN::Error::from_errno(EINVAL); - } - - switch (pheader.p_type) - { - case PT_LOAD: - for (const auto& program_header : program_headers) - { - const vaddr_t a1 = program_header.p_vaddr & PAGE_ADDR_MASK; - const vaddr_t b1 = pheader.p_vaddr & PAGE_ADDR_MASK; - const vaddr_t a2 = (program_header.p_vaddr + program_header.p_memsz + PAGE_SIZE - 1) & PAGE_ADDR_MASK; - const vaddr_t b2 = (pheader.p_vaddr + pheader.p_memsz + PAGE_SIZE - 1) & PAGE_ADDR_MASK; - if (a1 < b2 && b1 < a2) - { - dwarnln("Overlapping LOAD segments"); - return BAN::Error::from_errno(EINVAL); - } - } - TRY(program_headers.push_back(pheader)); - break; - case PT_INTERP: - { - BAN::Vector buffer; - TRY(buffer.resize(pheader.p_memsz, 0)); - TRY(inode->read(pheader.p_offset, BAN::ByteSpan(buffer.data(), pheader.p_filesz))); - - BAN::StringView path(reinterpret_cast(buffer.data())); - interp = TRY(VirtualFileSystem::get().file_from_absolute_path(credentials, path, O_EXEC)).inode; - break; - } - default: - break; - } - } - - return LoadResult { - .inode = inode, - .interp = interp, - .file_header = file_header, - .program_headers = BAN::move(program_headers) - }; - } - - static bool do_program_headers_overlap(BAN::Span pheaders1, BAN::Span pheaders2, vaddr_t base2) - { - for (const auto& pheader1 : pheaders1) - { - for (const auto& pheader2 : pheaders2) - { - const vaddr_t s1 = pheader1.p_vaddr & PAGE_ADDR_MASK; - const vaddr_t e1 = (pheader1.p_vaddr + pheader1.p_memsz + PAGE_SIZE - 1) & PAGE_ADDR_MASK; - - const vaddr_t s2 = pheader2.p_vaddr & PAGE_ADDR_MASK; - const vaddr_t e2 = (pheader2.p_vaddr + pheader2.p_memsz + PAGE_SIZE - 1) & PAGE_ADDR_MASK; - - if (s1 < e2 + base2 && s2 + base2 < e1) - return true; - } - } - - return false; - } - - BAN::ErrorOr LoadableELF::initialize(const Credentials& credentials, BAN::RefPtr inode) - { - const auto generate_random_dynamic_base = - []() -> vaddr_t - { - // 1 MiB -> 2 GiB + 1 MiB - return (Random::get_u32() & 0x7FFFF000) + 0x100000; - }; - - - auto executable_load_result = TRY(load_elf_file(credentials, inode)); - - m_executable = executable_load_result.inode; - m_interpreter = executable_load_result.interp; - - vaddr_t dynamic_base = 0; - - if (m_interpreter) - { - auto interp_load_result = TRY(load_elf_file(credentials, m_interpreter)); - if (interp_load_result.interp) - { - dwarnln("ELF interpreter has an interpreter"); - return BAN::Error::from_errno(EINVAL); - } - - if (executable_load_result.file_header.e_type == ET_EXEC) - { - if (interp_load_result.file_header.e_type == ET_EXEC) - { - const bool has_overlap = do_program_headers_overlap( - executable_load_result.program_headers.span(), - interp_load_result.program_headers.span(), - 0 - ); - - if (has_overlap) - { - dwarnln("Executable and interpreter LOAD segments overlap"); - return BAN::Error::from_errno(EINVAL); - } - } - else - { - for (int attempt = 0; attempt < 100; attempt++) - { - const vaddr_t test_dynamic_base = generate_random_dynamic_base(); - const bool has_overlap = do_program_headers_overlap( - executable_load_result.program_headers.span(), - interp_load_result.program_headers.span(), - test_dynamic_base - ); - if (has_overlap) - continue; - dynamic_base = test_dynamic_base; - break; - } - - if (dynamic_base == 0) - { - dwarnln("Could not find space to load interpreter"); - return BAN::Error::from_errno(EINVAL); - } - } - } - - m_file_header = interp_load_result.file_header; - m_program_headers = BAN::move(interp_load_result.program_headers); - } - else - { - m_file_header = executable_load_result.file_header; - m_program_headers = BAN::move(executable_load_result.program_headers); - } - - if (m_file_header.e_type == ET_DYN && dynamic_base == 0) - dynamic_base = generate_random_dynamic_base(); - - if (dynamic_base) - { - m_file_header.e_entry += dynamic_base; - for (auto& program_header : m_program_headers) - program_header.p_vaddr += dynamic_base; - } - - return {}; - } - - bool LoadableELF::contains(vaddr_t address) const - { - for (const auto& program_header : m_program_headers) - if (program_header.p_vaddr <= address && address < program_header.p_vaddr + program_header.p_memsz) - return true; - return false; - } - - bool LoadableELF::is_address_space_free() const - { - for (const auto& program_header : m_program_headers) - { - ASSERT(program_header.p_type == PT_LOAD); - const vaddr_t page_vaddr = program_header.p_vaddr & PAGE_ADDR_MASK; - const 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; - } - return true; - } - - void LoadableELF::reserve_address_space() - { - for (const auto& program_header : m_program_headers) - { - ASSERT(program_header.p_type == PT_LOAD); - const vaddr_t page_vaddr = program_header.p_vaddr & PAGE_ADDR_MASK; - const size_t pages = range_page_count(program_header.p_vaddr, program_header.p_memsz); - if (!m_page_table.reserve_range(page_vaddr, pages * PAGE_SIZE)) - ASSERT_NOT_REACHED(); - m_virtual_page_count += pages; - } - m_is_loaded = true; - } - - void LoadableELF::update_suid_sgid(Kernel::Credentials& credentials) - { - if (m_executable->mode().mode & +Inode::Mode::ISUID) - credentials.set_euid(m_executable->uid()); - if (m_executable->mode().mode & +Inode::Mode::ISGID) - credentials.set_egid(m_executable->gid()); - } - - BAN::ErrorOr LoadableELF::load_page_to_memory(vaddr_t address) - { - auto inode = has_interpreter() ? m_interpreter : m_executable; - - // FIXME: use MemoryBackedRegion/FileBackedRegion instead of manually mapping and allocating pages - - for (const auto& program_header : m_program_headers) - { - ASSERT(program_header.p_type == PT_LOAD); - if (!(program_header.p_vaddr <= address && address < program_header.p_vaddr + program_header.p_memsz)) - continue; - - PageTable::flags_t flags = PageTable::Flags::UserSupervisor | PageTable::Flags::Present; - if (program_header.p_flags & LibELF::PF_W) - flags |= PageTable::Flags::ReadWrite; - if (program_header.p_flags & LibELF::PF_X) - flags |= PageTable::Flags::Execute; - - const vaddr_t vaddr = address & PAGE_ADDR_MASK; - const paddr_t paddr = Heap::get().take_free_page(); - if (paddr == 0) - return BAN::Error::from_errno(ENOMEM); - - // Temporarily map page as RW so kernel can write to it - m_page_table.map_page_at(paddr, vaddr, PageTable::Flags::ReadWrite | PageTable::Flags::Present); - m_physical_page_count++; - - memset((void*)vaddr, 0x00, PAGE_SIZE); - - if (vaddr / PAGE_SIZE < BAN::Math::div_round_up(program_header.p_vaddr + program_header.p_filesz, PAGE_SIZE)) - { - size_t vaddr_offset = 0; - if (vaddr < program_header.p_vaddr) - vaddr_offset = program_header.p_vaddr - vaddr; - - size_t file_offset = 0; - if (vaddr > program_header.p_vaddr) - file_offset = vaddr - program_header.p_vaddr; - - size_t bytes = BAN::Math::min(PAGE_SIZE - vaddr_offset, program_header.p_filesz - file_offset); - TRY(inode->read(program_header.p_offset + file_offset, { (uint8_t*)vaddr + vaddr_offset, bytes })); - } - - // Map page with the correct flags - m_page_table.map_page_at(paddr, vaddr, flags); - - return {}; - } - - ASSERT_NOT_REACHED(); - } - - BAN::ErrorOr> LoadableELF::clone(Kernel::PageTable& new_page_table) - { - auto elf = TRY(BAN::UniqPtr::create(new_page_table)); - - elf->m_executable = m_executable; - elf->m_interpreter = m_interpreter; - elf->m_file_header = m_file_header; - TRY(elf->m_program_headers.reserve(m_program_headers.size())); - for (const auto& program_header : m_program_headers) - MUST(elf->m_program_headers.emplace_back(program_header)); - - elf->reserve_address_space(); - - for (const auto& program_header : m_program_headers) - { - ASSERT(program_header.p_type == PT_LOAD); - if (!(program_header.p_flags & LibELF::PF_W)) - continue; - - PageTable::flags_t flags = PageTable::Flags::UserSupervisor | PageTable::Flags::Present; - if (program_header.p_flags & LibELF::PF_W) - flags |= PageTable::Flags::ReadWrite; - if (program_header.p_flags & LibELF::PF_X) - flags |= PageTable::Flags::Execute; - - vaddr_t start = program_header.p_vaddr & PAGE_ADDR_MASK; - size_t pages = range_page_count(program_header.p_vaddr, program_header.p_memsz); - - for (size_t i = 0; i < pages; i++) - { - if (m_page_table.physical_address_of(start + i * PAGE_SIZE) == 0) - continue; - - paddr_t paddr = Heap::get().take_free_page(); - if (paddr == 0) - return BAN::Error::from_errno(ENOMEM); - - PageTable::with_fast_page(paddr, [&] { - memcpy(PageTable::fast_page_as_ptr(), (void*)(start + i * PAGE_SIZE), PAGE_SIZE); - }); - - new_page_table.map_page_at(paddr, start + i * PAGE_SIZE, flags); - elf->m_physical_page_count++; - } - } - - return elf; - } - -} diff --git a/userspace/libraries/LibELF/include/LibELF/ELF.h b/userspace/libraries/LibELF/include/LibELF/ELF.h deleted file mode 100644 index a3eea008..00000000 --- a/userspace/libraries/LibELF/include/LibELF/ELF.h +++ /dev/null @@ -1,89 +0,0 @@ -#pragma once - -#ifdef __is_kernel -#include -#include -#endif - -#include -#include -#include -#include -#include "Types.h" - -namespace LibELF -{ - - class ELF - { - public: -#ifdef __is_kernel - static BAN::ErrorOr> load_from_file(BAN::RefPtr); -#else - static BAN::ErrorOr> load_from_file(BAN::StringView); -#endif - - const Elf64FileHeader& file_header64() const; - const Elf64ProgramHeader& program_header64(size_t) const; - const Elf64SectionHeader& section_header64(size_t) const; - const char* lookup_section_name64(uint32_t) const; - const char* lookup_string64(size_t, uint32_t) const; -#if ARCH(x86_64) - const Elf64FileHeader& file_header_native() const { return file_header64(); } - const Elf64ProgramHeader& program_header_native(size_t index) const { return program_header64(index); } - const Elf64SectionHeader& section_header_native(size_t index) const { return section_header64(index); } - const char* lookup_section_name_native(uint32_t offset) const { return lookup_section_name64(offset); } - const char* lookup_string_native(size_t table_index, uint32_t offset) const { return lookup_string64(table_index, offset); } - bool is_native() const { return is_x86_64(); } -#endif - - const Elf32FileHeader& file_header32() const; - const Elf32ProgramHeader& program_header32(size_t) const; - const Elf32SectionHeader& section_header32(size_t) const; - const char* lookup_section_name32(uint32_t) const; - const char* lookup_string32(size_t, uint32_t) const; -#if ARCH(i686) - const Elf32FileHeader& file_header_native() const { return file_header32(); } - const Elf32ProgramHeader& program_header_native(size_t index) const { return program_header32(index); } - const Elf32SectionHeader& section_header_native(size_t index) const { return section_header32(index); } - const char* lookup_section_name_native(uint32_t offset) const { return lookup_section_name32(offset); } - const char* lookup_string_native(size_t table_index, uint32_t offset) const { return lookup_string32(table_index, offset); } - bool is_native() const { return is_x86_32(); } -#endif - - const uint8_t* data() const { return m_data.data(); } - - bool is_x86_32() const; - bool is_x86_64() const; - - private: -//#ifdef __is_kernel -// ELF(BAN::UniqPtr&& storage, size_t size) -// : m_storage(BAN::move(storage)) -// , m_data((const uint8_t*)m_storage->vaddr(), size) -// {} -//#else - ELF(BAN::Vector&& data) - : m_data(BAN::move(data)) - {} -//#endif - BAN::ErrorOr load(); - - bool parse_elf64_file_header(const Elf64FileHeader&); - bool parse_elf64_program_header(const Elf64ProgramHeader&); - bool parse_elf64_section_header(const Elf64SectionHeader&); - - bool parse_elf32_file_header(const Elf32FileHeader&); - bool parse_elf32_program_header(const Elf32ProgramHeader&); - bool parse_elf32_section_header(const Elf32SectionHeader&); - - private: -//#ifdef __is_kernel -// BAN::UniqPtr m_storage; -// BAN::Span m_data; -//#else - const BAN::Vector m_data; -//#endif - }; - -} diff --git a/userspace/libraries/LibELF/include/LibELF/LoadableELF.h b/userspace/libraries/LibELF/include/LibELF/LoadableELF.h deleted file mode 100644 index 527289fe..00000000 --- a/userspace/libraries/LibELF/include/LibELF/LoadableELF.h +++ /dev/null @@ -1,74 +0,0 @@ -#pragma once - -#ifndef __is_kernel -#error "This is kernel only header" -#endif - -#include -#include - -#include -#include -#include - -#include - -namespace LibELF -{ - - class LoadableELF - { - BAN_NON_COPYABLE(LoadableELF); - BAN_NON_MOVABLE(LoadableELF); - - public: - static BAN::ErrorOr> load_from_inode(Kernel::PageTable&, const Kernel::Credentials&, BAN::RefPtr); - ~LoadableELF(); - - Kernel::vaddr_t entry_point() const { return m_file_header.e_entry; } - - bool has_interpreter() const { return !!m_interpreter; } - BAN::RefPtr executable() { return m_executable; } - - bool contains(Kernel::vaddr_t address) const; - bool is_address_space_free() const; - void reserve_address_space(); - - void update_suid_sgid(Kernel::Credentials&); - - BAN::ErrorOr load_page_to_memory(Kernel::vaddr_t address); - - BAN::ErrorOr> clone(Kernel::PageTable&); - - size_t virtual_page_count() const { return m_virtual_page_count; } - size_t physical_page_count() const { return m_physical_page_count; } - - private: - struct LoadResult - { - BAN::RefPtr inode; - BAN::RefPtr interp; - ElfNativeFileHeader file_header; - BAN::Vector program_headers; - }; - - private: - LoadableELF(Kernel::PageTable&); - BAN::ErrorOr initialize(const Kernel::Credentials&, BAN::RefPtr); - BAN::ErrorOr load_elf_file(const Kernel::Credentials&, BAN::RefPtr) const; - - private: - BAN::RefPtr m_executable; - BAN::RefPtr m_interpreter; - ElfNativeFileHeader m_file_header; - BAN::Vector m_program_headers; - - Kernel::PageTable& m_page_table; - size_t m_virtual_page_count { 0 }; - size_t m_physical_page_count { 0 }; - bool m_is_loaded { false }; - - friend class BAN::UniqPtr; - }; - -}