From 35ae8742a965a5851d010089e30a866d52255db2 Mon Sep 17 00:00:00 2001 From: kjhq Date: Wed, 7 Oct 2026 10:41:01 +0000 Subject: [PATCH] feat(libkernel): implement POSIX mprotect mprotect changes the protection of guest memory through the same path as sceKernelMprotect and reports failures through errno: EINVAL for a null or overflowing range or a range the allocation tracker rejects, ENOMEM when allocation fails. A zero length succeeds. Co-Authored-By: Claude Opus 5.5 --- .../libkernel/DirectMemory/PosixMemory.cpp | 19 +++++++++++++++++++ core/libs/tests/GuestMemory.cpp | 15 +++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/core/libs/prx/libkernel/DirectMemory/PosixMemory.cpp b/core/libs/prx/libkernel/DirectMemory/PosixMemory.cpp index e3d2f1796..bac216bbc 100644 --- a/core/libs/prx/libkernel/DirectMemory/PosixMemory.cpp +++ b/core/libs/prx/libkernel/DirectMemory/PosixMemory.cpp @@ -78,4 +78,23 @@ int APS5_VABI munmap_nid_postfix(void* address, std::size_t length) noexcept { } } +int APS5_VABI mprotect_nid_postfix(void* address, std::size_t length, int protection) noexcept { + const auto failed = [](int error) { + SetError(error); + return -1; + }; + const auto start = reinterpret_cast(address); + if (length == 0) return 0; + if (start == 0 || length > std::numeric_limits::max() - start) + return failed(GuestInvalid); + try { + if (DoMprotect(address, length, protection) != 0) return failed(GuestInvalid); + return 0; + } catch (const std::bad_alloc&) { + return failed(GuestNoMemory); + } catch (const std::exception&) { + return failed(GuestInvalid); + } +} + } diff --git a/core/libs/tests/GuestMemory.cpp b/core/libs/tests/GuestMemory.cpp index 27908100c..e400e7e0a 100644 --- a/core/libs/tests/GuestMemory.cpp +++ b/core/libs/tests/GuestMemory.cpp @@ -36,6 +36,7 @@ extern "C" { void* APS5_VABI mmap_nid_postfix(void*, std::size_t, int, int, int, std::int64_t) noexcept; int APS5_VABI munmap_nid_postfix(void*, std::size_t) noexcept; +int APS5_VABI mprotect_nid_postfix(void*, std::size_t, int) noexcept; int* APS5_VABI __error_nid_postfix(); int APS5_VABI sceKernelMapNamedFlexibleMemory(void**, std::size_t, int, int, const char*); int APS5_VABI sceKernelMapNamedFlexibleMemoryInternal(void**, std::size_t, int, int, const char*); @@ -1099,6 +1100,20 @@ int main() { const auto range = mutation.Find(memory); Require(range.bytes == page * 3 && range.readable && range.writable); } + Require(mprotect_nid_postfix(memory, 0, 1) == 0); + Require(mprotect_nid_postfix(nullptr, page, 1) == -1 && *__error_nid_postfix() == 22); + Require(mprotect_nid_postfix(memory + 1, 1, 1) == 0); + { + GuestAllocations::Mutation mutation; + const auto range = mutation.Find(memory); + Require(range.readable && !range.writable); + } + Require(memory[0] == 42); + Require(mprotect_nid_postfix(memory, page, 3) == 0); + { + GuestAllocations::Mutation mutation; + Require(mutation.Find(memory).writable); + } Require(munmap_nid_postfix(memory + 1, page) == -1 && *__error_nid_postfix() == 22); Require(munmap_nid_postfix(memory, 0) == -1 && *__error_nid_postfix() == 22); Require(memory[0] == 42);