From a68bc9dfdcddd66259f4a27b4b389b29e7f039dd Mon Sep 17 00:00:00 2001 From: xXPBSXx <20614131+xXPBSXx@users.noreply.github.com> Date: Sun, 11 Oct 2026 00:59:26 +0200 Subject: [PATCH] fix(libkernel): allow sceKernelMprotect on committed host memory outside the guest registry Thread stacks are host-private memory; the call threw instead of setting the native protection. Co-Authored-By: Claude Sonnet 5.5 --- .../libkernel/DirectMemory/DirectMemory.cpp | 4 ++++ core/libs/tests/GuestMemory.cpp | 19 +++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/core/libs/prx/libkernel/DirectMemory/DirectMemory.cpp b/core/libs/prx/libkernel/DirectMemory/DirectMemory.cpp index 1fae6ec14..a31561d9b 100644 --- a/core/libs/prx/libkernel/DirectMemory/DirectMemory.cpp +++ b/core/libs/prx/libkernel/DirectMemory/DirectMemory.cpp @@ -882,6 +882,10 @@ int DoMprotect(const void* addr, size_t len, int prot) { else if (IsGuestModuleImage(memory.AllocationBase)) mutation.RegisterImage(memory.AllocationBase); else throw std::invalid_argument("Memory protection of a foreign image is not supported"); } + if (memory.Type == MEM_PRIVATE && memory.State == MEM_COMMIT && memory.RegionSize >= bytes && !mutation.Overlaps(pointer, bytes)) { + if (mprotect(const_cast(pointer), bytes, nativeProtection) != 0) throw std::system_error(errno, std::generic_category(), "mprotect failed"); + return 0; + } #else mutation.RegisterMainImage(); #endif diff --git a/core/libs/tests/GuestMemory.cpp b/core/libs/tests/GuestMemory.cpp index bfab22098..8a60050dd 100644 --- a/core/libs/tests/GuestMemory.cpp +++ b/core/libs/tests/GuestMemory.cpp @@ -1671,12 +1671,31 @@ static void CheckAvailableDirectMemoryIsLargestFreeBlock() { Require(sceKernelAvailableDirectMemorySize(top, top + window, 0, &start, &size) == 0); Require(start == top && size == static_cast(window)); } +#ifdef _WIN32 +static void CheckMprotectOfHostMemoryOutsideTheGuestRegistry() { + constexpr std::size_t length = 0x40000; + void* host = VirtualAlloc(nullptr, length, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); + Require(host != nullptr); + Require(sceKernelMprotect(host, length, 0x3) == 0); + static_cast(host)[length - 1] = 7; + Require(static_cast(host)[length - 1] == 7); + Require(sceKernelMprotect(host, length, 0x1) == 0); + MEMORY_BASIC_INFORMATION info{}; + Require(VirtualQuery(host, &info, sizeof(info)) == sizeof(info) && info.Protect == PAGE_READONLY); + Require(sceKernelMprotect(host, length, 0x3) == 0); + Require(VirtualQuery(host, &info, sizeof(info)) == sizeof(info) && info.Protect == PAGE_READWRITE); + Require(VirtualFree(host, 0, MEM_RELEASE) != 0); +} +#endif int main() { #ifdef _WIN32 _putenv_s("APS5_PIN_WAIT_MS", "1000"); #endif CheckAvailableDirectMemoryIsLargestFreeBlock(); +#ifdef _WIN32 + CheckMprotectOfHostMemoryOutsideTheGuestRegistry(); +#endif CheckVirtualQuerySplitFlexibleRanges(); CheckVirtualQueryForNonReadableGuestRange(); CheckReleaseFlexibleMemory();