From 04638bf77620a17eecc41f402281b5eae8249102 Mon Sep 17 00:00:00 2001 From: krishalivaibhav Date: Sun, 25 Oct 2026 12:58:27 +0530 Subject: [PATCH] fix(libkernel): refuse mlock on unreadable and unmapped pages on macOS Linux mlock fails with ENOMEM on PROT_NONE or unmapped pages, such as reservations. macOS mlock succeeds there without pinning anything, so check the host region protections first. A page needs read or execute permission, as in FreeBSD's vm_map_wire_locked. Co-authored-by: Himansh Raj Co-Authored-By: Claude Opus 5.5 --- .../libs/prx/libkernel/DirectMemory/Export.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/core/libs/prx/libkernel/DirectMemory/Export.cpp b/core/libs/prx/libkernel/DirectMemory/Export.cpp index 93101cb207..7956c65198 100644 --- a/core/libs/prx/libkernel/DirectMemory/Export.cpp +++ b/core/libs/prx/libkernel/DirectMemory/Export.cpp @@ -21,6 +21,10 @@ #include #include #include +#ifdef __APPLE__ +#include +#include +#endif #endif #include #include @@ -678,6 +682,20 @@ int UnlockHostPages(std::uintptr_t start, std::uintptr_t end) { int LockHostPages(std::uintptr_t start, std::uintptr_t end) { auto* const address = reinterpret_cast(start); const std::size_t bytes = end - start; +#ifdef __APPLE__ + for (mach_vm_address_t cursor = start; cursor < end;) { + mach_vm_address_t region = cursor; + mach_vm_size_t size = 0; + vm_region_basic_info_data_64_t info{}; + mach_msg_type_number_t count = VM_REGION_BASIC_INFO_COUNT_64; + mach_port_t object = MACH_PORT_NULL; + const kern_return_t status = mach_vm_region(mach_task_self(), ®ion, &size, VM_REGION_BASIC_INFO_64, reinterpret_cast(&info), &count, &object); + if (status == KERN_INVALID_ADDRESS) return SCE_KERNEL_ERROR_ENOMEM; + if (status != KERN_SUCCESS) throw std::runtime_error("mach_vm_region failed"); + if (region > cursor || (info.protection & (VM_PROT_READ | VM_PROT_EXECUTE)) == 0) return SCE_KERNEL_ERROR_ENOMEM; + cursor = region + size; + } +#endif if (::mlock(address, bytes) == 0) { RecordLockedRange(start, end); return 0;