Merge pull request #3788 from xXPBSXx/fix/libkernel-mprotect-host-memory-v3

fix(libkernel): allow sceKernelMprotect on committed host memory outside the guest registry
This commit is contained in:
Adrià 2026-10-12 00:01:51 +02:00 committed by GitHub
commit dc70a66cbd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 23 additions and 0 deletions

View File

@ -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<void*>(pointer), bytes, nativeProtection) != 0) throw std::system_error(errno, std::generic_category(), "mprotect failed");
return 0;
}
#else
mutation.RegisterMainImage();
#endif

View File

@ -1698,12 +1698,31 @@ static void CheckAvailableDirectMemoryIsLargestFreeBlock() {
Require(sceKernelAvailableDirectMemorySize(top, top + window, 0, &start, &size) == 0);
Require(start == top && size == static_cast<std::size_t>(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<volatile unsigned char*>(host)[length - 1] = 7;
Require(static_cast<volatile unsigned char*>(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();