From c6c679ca0c771ffe5d7bf4d449a2505bee571755 Mon Sep 17 00:00:00 2001 From: Antonio Date: Mon, 5 Aug 2024 00:41:42 -0400 Subject: [PATCH] Fixed ORBIS_KERNEL_MAP_OP_TYPE_PROTECT for batchmap2 --- src/core/address_space.cpp | 24 +++++++++ src/core/address_space.h | 2 + .../libraries/kernel/memory_management.cpp | 36 ++++++++++++- src/core/memory.cpp | 54 +++++++++++++++++++ src/core/memory.h | 2 + 5 files changed, 116 insertions(+), 2 deletions(-) diff --git a/src/core/address_space.cpp b/src/core/address_space.cpp index c3e0d77a..16344211 100644 --- a/src/core/address_space.cpp +++ b/src/core/address_space.cpp @@ -14,6 +14,7 @@ #include #include #endif +#include "libraries/error_codes.h" #ifdef __APPLE__ // Reserve space for the system address space using a zerofill section. @@ -240,6 +241,8 @@ struct AddressSpace::Impl { } } + + HANDLE process{}; HANDLE backing_handle{}; u8* backing_base{}; @@ -462,4 +465,25 @@ void AddressSpace::Protect(VAddr virtual_addr, size_t size, MemoryPermission per return impl->Protect(virtual_addr, size, true, true, true); } +int AddressSpace::MProtect(VAddr addr, size_t size, int prot) { + + // Use conditional compilation to switch between mprotect and VirtualProtect + int result; +#ifdef _WIN32 + // Windows-specific API call + result = VirtualProtect(reinterpret_cast(addr), size, prot, nullptr); +#else + // POSIX-specific API call + result = ::mprotect(reinterpret_cast(addr), size, prot); +#endif + + if (result != 0) { + LOG_ERROR(Core, "Failed to change memory protection: {}", strerror(errno)); + return ORBIS_KERNEL_ERROR_EACCES; + } + + LOG_INFO(Core, "Changed protection on range {:#x}-{:#x} to {:#x}", addr, addr + size, prot); + return ORBIS_OK; +} + } // namespace Core diff --git a/src/core/address_space.h b/src/core/address_space.h index e2515902..1d2c67da 100644 --- a/src/core/address_space.h +++ b/src/core/address_space.h @@ -98,6 +98,8 @@ public: void Protect(VAddr virtual_addr, size_t size, MemoryPermission perms); + int MProtect(VAddr addr, size_t size, int prot); + private: struct Impl; std::unique_ptr impl; diff --git a/src/core/libraries/kernel/memory_management.cpp b/src/core/libraries/kernel/memory_management.cpp index e0509fb4..81874c1f 100644 --- a/src/core/libraries/kernel/memory_management.cpp +++ b/src/core/libraries/kernel/memory_management.cpp @@ -10,6 +10,8 @@ #include "core/libraries/kernel/memory_management.h" #include "core/linker.h" #include "core/memory.h" +#include "core/address_space.h" + namespace Libraries::Kernel { @@ -198,6 +200,22 @@ int PS4_SYSV_ABI sceKernelQueryMemoryProtection(void* addr, void** start, void** return memory->QueryProtection(std::bit_cast(addr), start, end, prot); } +int PS4_SYSV_ABI sceKernelMProtect(void* addr, size_t size, int prot) { + LOG_INFO(Kernel_Vmm, "called addr = {}, size = {:#x}, prot = {:#x}", fmt::ptr(addr), size, + prot); + Core::MemoryManager* memory_manager = Core::Memory::Instance(); + if (!memory_manager) { + LOG_ERROR(Kernel_Vmm, "Failed to get MemoryManager instance"); + return ORBIS_KERNEL_ERROR_EINVAL; + } + + int result = memory_manager->MProtect(std::bit_cast(addr), size, prot); + if (result != ORBIS_OK) { + LOG_ERROR(Kernel_Vmm, "MProtect failed with result {}", result); + } + return result; +} + int PS4_SYSV_ABI sceKernelDirectMemoryQuery(u64 offset, int flags, OrbisQueryInfo* query_info, size_t infoSize) { LOG_WARNING(Kernel_Vmm, "called offset = {:#x}, flags = {:#x}", offset, flags); @@ -256,14 +274,28 @@ s32 PS4_SYSV_ABI sceKernelBatchMap2(OrbisKernelBatchMapEntry* entries, int numEn if (result == 0) processed++; - } else if (entries[i].operation == 1) { + } else if (entries[i].operation == 1) { // UNMAP result = sceKernelMunmap(entries[i].start, entries[i].length); LOG_INFO(Kernel_Vmm, "BatchMap: entry = {}, operation = {}, len = {:#x}, result = {}", i, entries[i].operation, entries[i].length, result); if (result == 0) processed++; - } else { + } else if (entries[i].operation == 4) { // MPROTECT + result = + sceKernelMProtect(entries[i].start, entries[i].length, entries[i].protection); + LOG_INFO(Kernel_Vmm, + "BatchMap: entry = {}, operation = {}, len = {:#x}, result = {}", i, + entries[i].operation, entries[i].length, result); + if (result != ORBIS_OK) { + LOG_ERROR(Kernel_Vmm, "BatchMap: MProtect failed on entry {} with result {}", i, + result); + } + if (result == 0) { + processed++; + } + } + else { UNREACHABLE_MSG("called: Unimplemented Operation = {}", entries[i].operation); } } diff --git a/src/core/memory.cpp b/src/core/memory.cpp index f2607bff..ba6c6f6a 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -8,6 +8,11 @@ #include "core/libraries/kernel/memory_management.h" #include "core/memory.h" #include "video_core/renderer_vulkan/vk_instance.h" +#ifdef _WIN32 +#include +#else +#include +#endif namespace Core { @@ -261,6 +266,55 @@ int MemoryManager::QueryProtection(VAddr addr, void** start, void** end, u32* pr return ORBIS_OK; } +int MemoryManager::MProtect(VAddr addr, size_t size, int prot) { + std::scoped_lock lk{mutex}; + + // Find the virtual memory area that contains the specified address range. + auto it = FindVMA(addr); + if (it == vma_map.end() || !it->second.Contains(addr, size)) { + LOG_ERROR(Core, "Address range not mapped"); + return ORBIS_KERNEL_ERROR_EINVAL; + } + + VirtualMemoryArea& vma = it->second; + if (vma.type == VMAType::Free) { + LOG_ERROR(Core, "Cannot change protection on free memory region"); + return ORBIS_KERNEL_ERROR_EINVAL; + } + +// Check if the new protection flags are valid. + if ((static_cast(prot) & + ~(static_cast(MemoryProt::NoAccess) | static_cast(MemoryProt::CpuRead) | + static_cast(MemoryProt::CpuReadWrite) | static_cast(MemoryProt::GpuRead) | + static_cast(MemoryProt::GpuWrite) | static_cast(MemoryProt::GpuReadWrite))) != + 0) { + LOG_ERROR(Core, "Invalid protection flags, prot: {:#x}, GpuWrite: {:#x}", + static_cast(prot), static_cast(MemoryProt::GpuWrite)); + return ORBIS_KERNEL_ERROR_EINVAL; + } + + // Change the protection on the specified address range. + vma.prot = static_cast(prot); + + // Use the Protect function from the AddressSpace class. + Core::MemoryPermission perms; + if ((static_cast(prot) & static_cast(MemoryProt::CpuRead)) != 0) + perms |= Core::MemoryPermission::Read; + if ((static_cast(prot) & static_cast(MemoryProt::CpuReadWrite)) != 0) + perms |= Core::MemoryPermission::ReadWrite; + if ((static_cast(prot) & static_cast(MemoryProt::GpuRead)) != 0) + perms |= Core::MemoryPermission::Read; + if ((static_cast(prot) & static_cast(MemoryProt::GpuWrite)) != 0) + perms |= Core::MemoryPermission::Write; + if ((static_cast(prot) & static_cast(MemoryProt::GpuReadWrite)) != 0) + perms |= Core::MemoryPermission::ReadWrite; // Add this line + impl.Protect(addr, size, perms); + + LOG_INFO(Core, "Changed protection on range {:#x}-{:#x} to {:#x}", addr, addr + size, prot); + return ORBIS_OK; +} + + int MemoryManager::VirtualQuery(VAddr addr, int flags, Libraries::Kernel::OrbisVirtualQueryInfo* info) { std::scoped_lock lk{mutex}; diff --git a/src/core/memory.h b/src/core/memory.h index ff4af5cd..0122deed 100644 --- a/src/core/memory.h +++ b/src/core/memory.h @@ -165,6 +165,8 @@ public: int QueryProtection(VAddr addr, void** start, void** end, u32* prot); + int MProtect(VAddr addr, size_t size, int prot); + int VirtualQuery(VAddr addr, int flags, Libraries::Kernel::OrbisVirtualQueryInfo* info); int DirectMemoryQuery(PAddr addr, bool find_next, Libraries::Kernel::OrbisQueryInfo* out_info);