diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index d08b84bde7..d3971a25ee 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -578,6 +578,10 @@ static ResultCode MapSharedMemory(Handle shared_memory_handle, VAddr addr, u64 s return ERR_INVALID_SIZE; } + if (!IsValidAddressRange(addr, size)) { + return ERR_INVALID_ADDRESS_STATE; + } + const auto permissions_type = static_cast(permissions); if (permissions_type != MemoryPermission::Read && permissions_type != MemoryPermission::ReadWrite) { @@ -591,8 +595,14 @@ static ResultCode MapSharedMemory(Handle shared_memory_handle, VAddr addr, u64 s return ERR_INVALID_HANDLE; } - return shared_memory->Map(Core::CurrentProcess(), addr, permissions_type, - MemoryPermission::DontCare); + auto* const current_process = Core::CurrentProcess(); + const auto& vm_manager = current_process->VMManager(); + + if (!vm_manager.IsWithinASLRRegion(addr, size)) { + return ERR_INVALID_MEMORY_RANGE; + } + + return shared_memory->Map(current_process, addr, permissions_type, MemoryPermission::DontCare); } static ResultCode UnmapSharedMemory(Handle shared_memory_handle, VAddr addr, u64 size) { @@ -607,10 +617,24 @@ static ResultCode UnmapSharedMemory(Handle shared_memory_handle, VAddr addr, u64 return ERR_INVALID_SIZE; } + if (!IsValidAddressRange(addr, size)) { + return ERR_INVALID_ADDRESS_STATE; + } + auto& kernel = Core::System::GetInstance().Kernel(); auto shared_memory = kernel.HandleTable().Get(shared_memory_handle); + if (!shared_memory) { + return ERR_INVALID_HANDLE; + } - return shared_memory->Unmap(Core::CurrentProcess(), addr); + auto* const current_process = Core::CurrentProcess(); + const auto& vm_manager = current_process->VMManager(); + + if (!vm_manager.IsWithinASLRRegion(addr, size)) { + return ERR_INVALID_MEMORY_RANGE; + } + + return shared_memory->Unmap(current_process, addr); } /// Query process memory diff --git a/src/core/hle/kernel/vm_manager.cpp b/src/core/hle/kernel/vm_manager.cpp index 1e28ccbdaf..e1a34eef1f 100644 --- a/src/core/hle/kernel/vm_manager.cpp +++ b/src/core/hle/kernel/vm_manager.cpp @@ -507,6 +507,26 @@ u64 VMManager::GetASLRRegionSize() const { return aslr_region_end - aslr_region_base; } +bool VMManager::IsWithinASLRRegion(VAddr begin, u64 size) const { + const VAddr range_end = begin + size; + const VAddr aslr_start = GetASLRRegionBaseAddress(); + const VAddr aslr_end = GetASLRRegionEndAddress(); + + if (aslr_start > begin || begin > range_end || range_end - 1 > aslr_end - 1) { + return false; + } + + if (range_end > heap_region_base && heap_region_end > begin) { + return false; + } + + if (range_end > map_region_base && map_region_end > begin) { + return false; + } + + return true; +} + VAddr VMManager::GetCodeRegionBaseAddress() const { return code_region_base; } diff --git a/src/core/hle/kernel/vm_manager.h b/src/core/hle/kernel/vm_manager.h index 4accde6b38..84c890224c 100644 --- a/src/core/hle/kernel/vm_manager.h +++ b/src/core/hle/kernel/vm_manager.h @@ -211,6 +211,9 @@ public: /// Gets the end address of the ASLR region. VAddr GetASLRRegionEndAddress() const; + /// Determines whether or not the specified address range is within the ASLR region. + bool IsWithinASLRRegion(VAddr address, u64 size) const; + /// Gets the size of the ASLR region u64 GetASLRRegionSize() const;