Kernel: Allow loading PIEs

This is initial work towards implementing dynamic loader and shared
library support.
This commit is contained in:
Bananymous 2024-08-27 16:55:20 +03:00
parent 2c520391eb
commit 5121d0d934
2 changed files with 123 additions and 134 deletions

View File

@ -1,6 +1,7 @@
#include <BAN/ScopeGuard.h> #include <BAN/ScopeGuard.h>
#include <kernel/Memory/Heap.h>
#include <kernel/Lock/LockGuard.h> #include <kernel/Lock/LockGuard.h>
#include <kernel/Memory/Heap.h>
#include <kernel/Random.h>
#include <LibELF/LoadableELF.h> #include <LibELF/LoadableELF.h>
#include <LibELF/Values.h> #include <LibELF/Values.h>
@ -96,10 +97,10 @@ namespace LibELF
return BAN::Error::from_errno(EINVAL); return BAN::Error::from_errno(EINVAL);
} }
if (m_file_header.e_type != ET_EXEC) if (m_file_header.e_type != ET_EXEC && m_file_header.e_type != ET_DYN)
{ {
dprintln("Only executable files are supported"); dprintln("Unsupported file header type {}", m_file_header.e_type);
return BAN::Error::from_errno(EINVAL); return BAN::Error::from_errno(ENOTSUP);
} }
if (m_file_header.e_version != EV_CURRENT) if (m_file_header.e_version != EV_CURRENT)
@ -110,24 +111,36 @@ namespace LibELF
ASSERT(m_file_header.e_phentsize <= sizeof(ElfNativeProgramHeader)); ASSERT(m_file_header.e_phentsize <= sizeof(ElfNativeProgramHeader));
TRY(m_program_headers.resize(m_file_header.e_phnum)); BAN::Vector<uint8_t> pheader_buffer;
TRY(pheader_buffer.resize(m_file_header.e_phnum * m_file_header.e_phentsize));
TRY(m_inode->read(m_file_header.e_phoff, BAN::ByteSpan(pheader_buffer.span())));
const vaddr_t dyn_base = (m_file_header.e_type == ET_DYN) ? 0x40000000 + (Random::get_u32() & 0x3FFFF000) : 0;
m_file_header.e_entry += dyn_base;
for (size_t i = 0; i < m_file_header.e_phnum; i++) for (size_t i = 0; i < m_file_header.e_phnum; i++)
{ {
TRY(m_inode->read(m_file_header.e_phoff + m_file_header.e_phentsize * i, BAN::ByteSpan::from(m_program_headers[i]))); const auto& pheader = *reinterpret_cast<ElfNativeProgramHeader*>(pheader_buffer.data() + i * m_file_header.e_phentsize);
const auto& pheader = m_program_headers[i];
if (pheader.p_type != PT_NULL && pheader.p_type != PT_LOAD)
{
dprintln("Unsupported program header type {}", pheader.p_type);
return BAN::Error::from_errno(ENOTSUP);
}
if (pheader.p_memsz < pheader.p_filesz) if (pheader.p_memsz < pheader.p_filesz)
{ {
dprintln("Invalid program header"); dprintln("Invalid program header");
return BAN::Error::from_errno(EINVAL); return BAN::Error::from_errno(EINVAL);
} }
switch (pheader.p_type)
{
case PT_NULL:
case PT_DYNAMIC:
break;
case PT_LOAD:
TRY(m_program_headers.push_back(pheader));
m_program_headers.back().p_vaddr += dyn_base;
m_virtual_page_count += BAN::Math::div_round_up<size_t>((pheader.p_vaddr % PAGE_SIZE) + pheader.p_memsz, PAGE_SIZE); m_virtual_page_count += BAN::Math::div_round_up<size_t>((pheader.p_vaddr % PAGE_SIZE) + pheader.p_memsz, PAGE_SIZE);
break;
default:
dprintln("Unsupported program header type {}", pheader.p_type);
return BAN::Error::from_errno(ENOTSUP);
}
} }
return {}; return {};
@ -142,17 +155,9 @@ namespace LibELF
{ {
for (const auto& program_header : m_program_headers) for (const auto& program_header : m_program_headers)
{ {
switch (program_header.p_type) ASSERT(program_header.p_type == PT_LOAD);
{
case PT_NULL:
continue;
case PT_LOAD:
if (program_header.p_vaddr <= address && address < program_header.p_vaddr + program_header.p_memsz) if (program_header.p_vaddr <= address && address < program_header.p_vaddr + program_header.p_memsz)
return true; return true;
break;
default:
ASSERT_NOT_REACHED();
}
} }
return false; return false;
} }
@ -161,21 +166,11 @@ namespace LibELF
{ {
for (const auto& program_header : m_program_headers) for (const auto& program_header : m_program_headers)
{ {
switch (program_header.p_type) ASSERT(program_header.p_type == PT_LOAD);
{ const vaddr_t page_vaddr = program_header.p_vaddr & PAGE_ADDR_MASK;
case PT_NULL: const size_t pages = range_page_count(program_header.p_vaddr, program_header.p_memsz);
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)) if (!m_page_table.is_range_free(page_vaddr, pages * PAGE_SIZE))
return false; return false;
break;
}
default:
ASSERT_NOT_REACHED();
}
} }
return true; return true;
} }
@ -184,21 +179,12 @@ namespace LibELF
{ {
for (const auto& program_header : m_program_headers) for (const auto& program_header : m_program_headers)
{ {
switch (program_header.p_type) ASSERT(program_header.p_type == PT_LOAD);
{ const vaddr_t page_vaddr = program_header.p_vaddr & PAGE_ADDR_MASK;
case PT_NULL: const size_t pages = range_page_count(program_header.p_vaddr, program_header.p_memsz);
break; if (!m_page_table.reserve_range(page_vaddr, pages * PAGE_SIZE))
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);
ASSERT(m_page_table.reserve_range(page_vaddr, pages * PAGE_SIZE));
break;
}
default:
ASSERT_NOT_REACHED(); ASSERT_NOT_REACHED();
} }
}
m_loaded = true; m_loaded = true;
} }
@ -214,12 +200,8 @@ namespace LibELF
{ {
for (const auto& program_header : m_program_headers) for (const auto& program_header : m_program_headers)
{ {
switch (program_header.p_type) ASSERT(program_header.p_type == PT_LOAD);
{
case PT_NULL:
break;
case PT_LOAD:
{
if (!(program_header.p_vaddr <= address && address < program_header.p_vaddr + program_header.p_memsz)) if (!(program_header.p_vaddr <= address && address < program_header.p_vaddr + program_header.p_memsz))
continue; continue;
@ -229,8 +211,8 @@ namespace LibELF
if (program_header.p_flags & LibELF::PF_X) if (program_header.p_flags & LibELF::PF_X)
flags |= PageTable::Flags::Execute; flags |= PageTable::Flags::Execute;
vaddr_t vaddr = address & PAGE_ADDR_MASK; const vaddr_t vaddr = address & PAGE_ADDR_MASK;
paddr_t paddr = Heap::get().take_free_page(); const paddr_t paddr = Heap::get().take_free_page();
if (paddr == 0) if (paddr == 0)
return BAN::Error::from_errno(ENOMEM); return BAN::Error::from_errno(ENOMEM);
@ -259,13 +241,8 @@ namespace LibELF
return {}; return {};
} }
default:
ASSERT_NOT_REACHED(); ASSERT_NOT_REACHED();
} }
}
ASSERT_NOT_REACHED();
}
BAN::ErrorOr<BAN::UniqPtr<LoadableELF>> LoadableELF::clone(Kernel::PageTable& new_page_table) BAN::ErrorOr<BAN::UniqPtr<LoadableELF>> LoadableELF::clone(Kernel::PageTable& new_page_table)
{ {
@ -283,12 +260,8 @@ namespace LibELF
for (const auto& program_header : m_program_headers) for (const auto& program_header : m_program_headers)
{ {
switch (program_header.p_type) ASSERT(program_header.p_type == PT_LOAD);
{
case PT_NULL:
break;
case PT_LOAD:
{
if (!(program_header.p_flags & LibELF::PF_W)) if (!(program_header.p_flags & LibELF::PF_W))
continue; continue;
@ -317,12 +290,6 @@ namespace LibELF
new_page_table.map_page_at(paddr, start + i * PAGE_SIZE, flags); new_page_table.map_page_at(paddr, start + i * PAGE_SIZE, flags);
elf->m_physical_page_count++; elf->m_physical_page_count++;
} }
break;
}
default:
ASSERT_NOT_REACHED();
}
} }
return elf; return elf;

View File

@ -80,6 +80,16 @@ namespace LibELF
Elf32Word p_align; Elf32Word p_align;
}; };
struct Elf32Dynamic
{
Elf32Sword d_tag;
union
{
Elf32Word d_val;
Elf32Addr d_ptr;
} d_un;
};
using Elf64Addr = uint64_t; using Elf64Addr = uint64_t;
using Elf64Off = uint64_t; using Elf64Off = uint64_t;
using Elf64Half = uint16_t; using Elf64Half = uint16_t;
@ -155,6 +165,16 @@ namespace LibELF
Elf64Xword p_align; Elf64Xword p_align;
}; };
struct Elf64Dynamic
{
Elf64Sxword d_tag;
union
{
Elf64Xword d_val;
Elf64Addr d_ptr;
} d_un;
};
#if ARCH(i686) #if ARCH(i686)
using ElfNativeAddr = Elf32Addr; using ElfNativeAddr = Elf32Addr;
using ElfNativeOff = Elf32Off; using ElfNativeOff = Elf32Off;
@ -167,6 +187,7 @@ namespace LibELF
using ElfNativeRelocation = Elf32Relocation; using ElfNativeRelocation = Elf32Relocation;
using ElfNativeRelocationA = Elf32RelocationA; using ElfNativeRelocationA = Elf32RelocationA;
using ElfNativeProgramHeader = Elf32ProgramHeader; using ElfNativeProgramHeader = Elf32ProgramHeader;
using ElfNativeDynamic = Elf32Dynamic;
#elif ARCH(x86_64) #elif ARCH(x86_64)
using ElfNativeAddr = Elf64Addr; using ElfNativeAddr = Elf64Addr;
using ElfNativeOff = Elf64Off; using ElfNativeOff = Elf64Off;
@ -181,6 +202,7 @@ namespace LibELF
using ElfNativeRelocation = Elf64Relocation; using ElfNativeRelocation = Elf64Relocation;
using ElfNativeRelocationA = Elf64RelocationA; using ElfNativeRelocationA = Elf64RelocationA;
using ElfNativeProgramHeader = Elf64ProgramHeader; using ElfNativeProgramHeader = Elf64ProgramHeader;
using ElfNativeDynamic = Elf64Dynamic;
#endif #endif
} }