diff --git a/core/libs/prx/libkernel/DirectMemory/DirectMemory.cpp b/core/libs/prx/libkernel/DirectMemory/DirectMemory.cpp index 9eeb24861..8d1916f7b 100644 --- a/core/libs/prx/libkernel/DirectMemory/DirectMemory.cpp +++ b/core/libs/prx/libkernel/DirectMemory/DirectMemory.cpp @@ -921,6 +921,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 74beb7554..427a6d064 100644 --- a/core/libs/tests/GuestMemory.cpp +++ b/core/libs/tests/GuestMemory.cpp @@ -1698,12 +1698,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();