From 33830aa65ac58a03a91de9ac4fc8d91fe28f6d4e Mon Sep 17 00:00:00 2001 From: Lioncash Date: Wed, 17 Oct 2018 22:39:21 -0400 Subject: [PATCH] svc: Add missing sanitizing checks for MapSharedMemory/UnmapSharedMemory Now that the changes clarifying the address spaces has been merged, we can wrap the checks that the kernel performs when mapping shared memory (and other forms of memory) into its own helper function and then use those within MapSharedMemory and UnmapSharedMemory to complete the sanitizing checks that are supposed to be done. --- src/core/hle/kernel/svc.cpp | 30 +++++++++++++++++++++++++++--- src/core/hle/kernel/vm_manager.cpp | 20 ++++++++++++++++++++ src/core/hle/kernel/vm_manager.h | 3 +++ 3 files changed, 50 insertions(+), 3 deletions(-) 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;