Merge pull request #1472 from lioncash/san
svc: Add missing address range sanitizing checks to MapMemory/UnmapMemory
This commit is contained in:
		
						commit
						3fd26b7147
					
				@ -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
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user