mirror of
				https://git.suyu.dev/suyu/suyu
				synced 2025-10-30 23:49:01 -05:00 
			
		
		
		
	Merge pull request #1472 from lioncash/san
svc: Add missing address range sanitizing checks to MapMemory/UnmapMemory
This commit is contained in:
		| @@ -22,6 +22,7 @@ enum { | ||||
|     HandleTableFull = 105, | ||||
|     InvalidMemoryState = 106, | ||||
|     InvalidMemoryPermissions = 108, | ||||
|     InvalidMemoryRange = 110, | ||||
|     InvalidThreadPriority = 112, | ||||
|     InvalidProcessorId = 113, | ||||
|     InvalidHandle = 114, | ||||
| @@ -56,6 +57,7 @@ constexpr ResultCode ERR_INVALID_ADDRESS(ErrorModule::Kernel, ErrCodes::InvalidA | ||||
| constexpr ResultCode ERR_INVALID_ADDRESS_STATE(ErrorModule::Kernel, ErrCodes::InvalidMemoryState); | ||||
| constexpr ResultCode ERR_INVALID_MEMORY_PERMISSIONS(ErrorModule::Kernel, | ||||
|                                                     ErrCodes::InvalidMemoryPermissions); | ||||
| constexpr ResultCode ERR_INVALID_MEMORY_RANGE(ErrorModule::Kernel, ErrCodes::InvalidMemoryRange); | ||||
| constexpr ResultCode ERR_INVALID_HANDLE(ErrorModule::Kernel, ErrCodes::InvalidHandle); | ||||
| constexpr ResultCode ERR_INVALID_PROCESSOR_ID(ErrorModule::Kernel, ErrCodes::InvalidProcessorId); | ||||
| constexpr ResultCode ERR_INVALID_SIZE(ErrorModule::Kernel, ErrCodes::InvalidSize); | ||||
|   | ||||
| @@ -39,6 +39,73 @@ namespace { | ||||
| constexpr bool Is4KBAligned(VAddr address) { | ||||
|     return (address & 0xFFF) == 0; | ||||
| } | ||||
|  | ||||
| // Checks if address + size is greater than the given address | ||||
| // This can return false if the size causes an overflow of a 64-bit type | ||||
| // or if the given size is zero. | ||||
| constexpr bool IsValidAddressRange(VAddr address, u64 size) { | ||||
|     return address + size > address; | ||||
| } | ||||
|  | ||||
| // Checks if a given address range lies within a larger address range. | ||||
| constexpr bool IsInsideAddressRange(VAddr address, u64 size, VAddr address_range_begin, | ||||
|                                     VAddr address_range_end) { | ||||
|     const VAddr end_address = address + size - 1; | ||||
|     return address_range_begin <= address && end_address <= address_range_end - 1; | ||||
| } | ||||
|  | ||||
| bool IsInsideAddressSpace(const VMManager& vm, VAddr address, u64 size) { | ||||
|     return IsInsideAddressRange(address, size, vm.GetAddressSpaceBaseAddress(), | ||||
|                                 vm.GetAddressSpaceEndAddress()); | ||||
| } | ||||
|  | ||||
| bool IsInsideNewMapRegion(const VMManager& vm, VAddr address, u64 size) { | ||||
|     return IsInsideAddressRange(address, size, vm.GetNewMapRegionBaseAddress(), | ||||
|                                 vm.GetNewMapRegionEndAddress()); | ||||
| } | ||||
|  | ||||
| // Helper function that performs the common sanity checks for svcMapMemory | ||||
| // and svcUnmapMemory. This is doable, as both functions perform their sanitizing | ||||
| // in the same order. | ||||
| ResultCode MapUnmapMemorySanityChecks(const VMManager& vm_manager, VAddr dst_addr, VAddr src_addr, | ||||
|                                       u64 size) { | ||||
|     if (!Is4KBAligned(dst_addr) || !Is4KBAligned(src_addr)) { | ||||
|         return ERR_INVALID_ADDRESS; | ||||
|     } | ||||
|  | ||||
|     if (size == 0 || !Is4KBAligned(size)) { | ||||
|         return ERR_INVALID_SIZE; | ||||
|     } | ||||
|  | ||||
|     if (!IsValidAddressRange(dst_addr, size)) { | ||||
|         return ERR_INVALID_ADDRESS_STATE; | ||||
|     } | ||||
|  | ||||
|     if (!IsValidAddressRange(src_addr, size)) { | ||||
|         return ERR_INVALID_ADDRESS_STATE; | ||||
|     } | ||||
|  | ||||
|     if (!IsInsideAddressSpace(vm_manager, src_addr, size)) { | ||||
|         return ERR_INVALID_ADDRESS_STATE; | ||||
|     } | ||||
|  | ||||
|     if (!IsInsideNewMapRegion(vm_manager, dst_addr, size)) { | ||||
|         return ERR_INVALID_MEMORY_RANGE; | ||||
|     } | ||||
|  | ||||
|     const VAddr dst_end_address = dst_addr + size; | ||||
|     if (dst_end_address > vm_manager.GetHeapRegionBaseAddress() && | ||||
|         dst_addr < vm_manager.GetHeapRegionEndAddress()) { | ||||
|         return ERR_INVALID_MEMORY_RANGE; | ||||
|     } | ||||
|  | ||||
|     if (dst_end_address > vm_manager.GetNewMapRegionBaseAddress() && | ||||
|         dst_addr < vm_manager.GetMapRegionEndAddress()) { | ||||
|         return ERR_INVALID_MEMORY_RANGE; | ||||
|     } | ||||
|  | ||||
|     return RESULT_SUCCESS; | ||||
| } | ||||
| } // Anonymous namespace | ||||
|  | ||||
| /// Set the process heap to a given Size. It can both extend and shrink the heap. | ||||
| @@ -69,15 +136,15 @@ static ResultCode MapMemory(VAddr dst_addr, VAddr src_addr, u64 size) { | ||||
|     LOG_TRACE(Kernel_SVC, "called, dst_addr=0x{:X}, src_addr=0x{:X}, size=0x{:X}", dst_addr, | ||||
|               src_addr, size); | ||||
|  | ||||
|     if (!Is4KBAligned(dst_addr) || !Is4KBAligned(src_addr)) { | ||||
|         return ERR_INVALID_ADDRESS; | ||||
|     auto* const current_process = Core::CurrentProcess(); | ||||
|     const auto& vm_manager = current_process->VMManager(); | ||||
|  | ||||
|     const auto result = MapUnmapMemorySanityChecks(vm_manager, dst_addr, src_addr, size); | ||||
|     if (result != RESULT_SUCCESS) { | ||||
|         return result; | ||||
|     } | ||||
|  | ||||
|     if (size == 0 || !Is4KBAligned(size)) { | ||||
|         return ERR_INVALID_SIZE; | ||||
|     } | ||||
|  | ||||
|     return Core::CurrentProcess()->MirrorMemory(dst_addr, src_addr, size); | ||||
|     return current_process->MirrorMemory(dst_addr, src_addr, size); | ||||
| } | ||||
|  | ||||
| /// Unmaps a region that was previously mapped with svcMapMemory | ||||
| @@ -85,15 +152,15 @@ static ResultCode UnmapMemory(VAddr dst_addr, VAddr src_addr, u64 size) { | ||||
|     LOG_TRACE(Kernel_SVC, "called, dst_addr=0x{:X}, src_addr=0x{:X}, size=0x{:X}", dst_addr, | ||||
|               src_addr, size); | ||||
|  | ||||
|     if (!Is4KBAligned(dst_addr) || !Is4KBAligned(src_addr)) { | ||||
|         return ERR_INVALID_ADDRESS; | ||||
|     auto* const current_process = Core::CurrentProcess(); | ||||
|     const auto& vm_manager = current_process->VMManager(); | ||||
|  | ||||
|     const auto result = MapUnmapMemorySanityChecks(vm_manager, dst_addr, src_addr, size); | ||||
|     if (result != RESULT_SUCCESS) { | ||||
|         return result; | ||||
|     } | ||||
|  | ||||
|     if (size == 0 || !Is4KBAligned(size)) { | ||||
|         return ERR_INVALID_SIZE; | ||||
|     } | ||||
|  | ||||
|     return Core::CurrentProcess()->UnmapMemory(dst_addr, src_addr, size); | ||||
|     return current_process->UnmapMemory(dst_addr, src_addr, size); | ||||
| } | ||||
|  | ||||
| /// Connect to an OS service given the port name, returns the handle to the port to out | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 bunnei
					bunnei