Kernel: Support execute disable bit

We will now map executable memory explicitly as executable.
This commit is contained in:
Bananymous 2023-07-13 14:28:53 +03:00
parent bca7e9a1e8
commit 7d00c2670f
4 changed files with 38 additions and 3 deletions

View File

@ -1,5 +1,6 @@
#include <BAN/Errors.h>
#include <kernel/Arch.h>
#include <kernel/CPUID.h>
#include <kernel/LockGuard.h>
#include <kernel/Memory/kmalloc.h>
#include <kernel/Memory/PageTable.h>
@ -7,11 +8,15 @@
extern uint8_t g_kernel_start[];
extern uint8_t g_kernel_end[];
extern uint8_t g_kernel_execute_start[];
extern uint8_t g_kernel_execute_end[];
namespace Kernel
{
static PageTable* s_kernel = nullptr;
static PageTable* s_current = nullptr;
static bool s_has_nxe = false;
// Page Directories for kernel memory (KERNEL_OFFSET -> 0xFFFFFFFFFFFFFFFF)
static paddr_t s_global[(0xFFFFFFFFFFFFFFFF - KERNEL_OFFSET + 1) / (4096ull * 512ull * 512ull)] { };
@ -40,6 +45,17 @@ namespace Kernel
void PageTable::initialize()
{
if (CPUID::has_nxe())
{
asm volatile(
"movl $0xC0000080, %ecx;"
"rdmsr;"
"orl $0x800, %eax;"
"wrmsr"
);
s_has_nxe = true;
}
ASSERT(s_kernel == nullptr);
s_kernel = new PageTable();
ASSERT(s_kernel);
@ -78,6 +94,14 @@ namespace Kernel
// Map (0 -> phys_kernel_end) to (KERNEL_OFFSET -> virt_kernel_end)
map_range_at(0, KERNEL_OFFSET, (uintptr_t)g_kernel_end - KERNEL_OFFSET, Flags::ReadWrite | Flags::Present);
// Map executable kernel memory as executable
map_range_at(
V2P(g_kernel_execute_start),
(vaddr_t)g_kernel_execute_start,
g_kernel_execute_end - g_kernel_execute_start,
Flags::Execute | Flags::ReadWrite | Flags::Present
);
}
BAN::ErrorOr<PageTable*> PageTable::create_userspace()
@ -207,6 +231,10 @@ namespace Kernel
{
LockGuard _(m_lock);
uint64_t xd_bit = 0;
if (s_has_nxe && !(flags & Flags::Execute))
xd_bit = 1ull << 63;
if (vaddr && (vaddr >= KERNEL_OFFSET) != (this == s_kernel))
Kernel::panic("mapping {8H} to {8H}, kernel: {}", paddr, vaddr, this == s_kernel);
@ -248,7 +276,7 @@ namespace Kernel
}
uint64_t* pt = (uint64_t*)P2V(pd[pde] & PAGE_ADDR_MASK);
pt[pte] = paddr | flags;
pt[pte] = xd_bit | paddr | flags;
invalidate(canonicalize(vaddr));
}
@ -304,12 +332,14 @@ namespace Kernel
PageTable::flags_t PageTable::get_page_flags(vaddr_t addr) const
{
return get_page_data(addr) & PAGE_FLAG_MASK;
uint64_t page_data = get_page_data(addr);
return (page_data & (1ull << 63) ? Flags::Execute : 0) | (page_data & PAGE_FLAG_MASK);
}
paddr_t PageTable::physical_address_of(vaddr_t addr) const
{
return get_page_data(addr) & PAGE_ADDR_MASK;
uint64_t page_data = get_page_data(addr);
return (page_data & PAGE_ADDR_MASK) & ~(1ull << 63);
}
vaddr_t PageTable::get_free_page(vaddr_t first_address) const

View File

@ -9,12 +9,14 @@ SECTIONS
g_kernel_start = .;
.text ALIGN(4K) : AT(ADDR(.text) - KERNEL_OFFSET)
{
g_kernel_execute_start = .;
*(.multiboot)
*(.text)
}
.rodata ALIGN(4K) : AT(ADDR(.rodata) - KERNEL_OFFSET)
{
*(.rodata.*)
g_kernel_execute_end = .;
}
.data ALIGN(4K) : AT(ADDR(.data) - KERNEL_OFFSET)
{

View File

@ -16,6 +16,7 @@ namespace Kernel
Present = 1,
ReadWrite = 2,
UserSupervisor = 4,
Execute = 8,
};
public:

View File

@ -458,6 +458,8 @@ namespace Kernel
uint8_t flags = PageTable::Flags::UserSupervisor | PageTable::Flags::Present;
if (elf_program_header.p_flags & LibELF::PF_W)
flags |= PageTable::Flags::ReadWrite;
if (elf_program_header.p_flags & LibELF::PF_X)
flags |= PageTable::Flags::Execute;
size_t page_start = elf_program_header.p_vaddr / PAGE_SIZE;
size_t page_end = BAN::Math::div_round_up<size_t>(elf_program_header.p_vaddr + elf_program_header.p_memsz, PAGE_SIZE);