diff --git a/kernel/include/kernel/Process.h b/kernel/include/kernel/Process.h index 3db255dc..566619b8 100644 --- a/kernel/include/kernel/Process.h +++ b/kernel/include/kernel/Process.h @@ -220,7 +220,7 @@ namespace Kernel // Returns error if page could not be allocated // Returns true if the page was allocated successfully // Return false if access was page violation (segfault) - BAN::ErrorOr allocate_page_for_demand_paging(vaddr_t addr, bool wants_write); + BAN::ErrorOr allocate_page_for_demand_paging(vaddr_t addr, bool wants_write, bool wants_exec); // FIXME: remove this API BAN::ErrorOr absolute_path_of(BAN::StringView) const; diff --git a/kernel/kernel/IDT.cpp b/kernel/kernel/IDT.cpp index dbaaaab0..103c93dd 100644 --- a/kernel/kernel/IDT.cpp +++ b/kernel/kernel/IDT.cpp @@ -214,7 +214,7 @@ namespace Kernel page_fault_error.raw = error; Processor::set_interrupt_state(InterruptState::Enabled); - auto result = Process::current().allocate_page_for_demand_paging(regs->cr2, page_fault_error.write); + auto result = Process::current().allocate_page_for_demand_paging(regs->cr2, page_fault_error.write, page_fault_error.instruction); Processor::set_interrupt_state(InterruptState::Disabled); if (!result.is_error() && result.value()) diff --git a/kernel/kernel/Process.cpp b/kernel/kernel/Process.cpp index ac424de5..4e3bd20b 100644 --- a/kernel/kernel/Process.cpp +++ b/kernel/kernel/Process.cpp @@ -981,24 +981,32 @@ namespace Kernel return {}; } - BAN::ErrorOr Process::allocate_page_for_demand_paging(vaddr_t address, bool wants_write) + BAN::ErrorOr Process::allocate_page_for_demand_paging(vaddr_t address, bool wants_write, bool wants_exec) { ASSERT(&Process::current() == this); LockGuard _(m_process_lock); - if (Thread::current().userspace_stack().contains(address)) { - TRY(Thread::current().userspace_stack().allocate_page_for_demand_paging(address)); - return true; + // NOTE: page can be already allocated by another thread! + + PageTable::flags_t wanted_flags = PageTable::Flags::UserSupervisor | PageTable::Flags::Present; + if (wants_write) + wanted_flags |= PageTable::Flags::ReadWrite; + if (wants_exec) + wanted_flags |= PageTable::Flags::Execute; + if ((m_page_table->get_page_flags(address & PAGE_ADDR_MASK) & wanted_flags) == wanted_flags) + return true; } + if (Thread::current().userspace_stack().contains(address)) + return Thread::current().userspace_stack().allocate_page_for_demand_paging(address); + for (auto& region : m_mapped_regions) { if (!region->contains(address)) continue; - TRY(region->allocate_page_containing(address, wants_write)); - return true; + return region->allocate_page_containing(address, wants_write); } return false; @@ -3112,7 +3120,7 @@ unauthorized_access: const vaddr_t current = page_start + i * PAGE_SIZE; if (page_table().get_page_flags(current) & PageTable::Flags::Present) continue; - TRY(Process::allocate_page_for_demand_paging(current, needs_write)); + TRY(Process::allocate_page_for_demand_paging(current, needs_write, false)); } return {};