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,
|
HandleTableFull = 105,
|
||||||
InvalidMemoryState = 106,
|
InvalidMemoryState = 106,
|
||||||
InvalidMemoryPermissions = 108,
|
InvalidMemoryPermissions = 108,
|
||||||
|
InvalidMemoryRange = 110,
|
||||||
InvalidThreadPriority = 112,
|
InvalidThreadPriority = 112,
|
||||||
InvalidProcessorId = 113,
|
InvalidProcessorId = 113,
|
||||||
InvalidHandle = 114,
|
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_ADDRESS_STATE(ErrorModule::Kernel, ErrCodes::InvalidMemoryState);
|
||||||
constexpr ResultCode ERR_INVALID_MEMORY_PERMISSIONS(ErrorModule::Kernel,
|
constexpr ResultCode ERR_INVALID_MEMORY_PERMISSIONS(ErrorModule::Kernel,
|
||||||
ErrCodes::InvalidMemoryPermissions);
|
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_HANDLE(ErrorModule::Kernel, ErrCodes::InvalidHandle);
|
||||||
constexpr ResultCode ERR_INVALID_PROCESSOR_ID(ErrorModule::Kernel, ErrCodes::InvalidProcessorId);
|
constexpr ResultCode ERR_INVALID_PROCESSOR_ID(ErrorModule::Kernel, ErrCodes::InvalidProcessorId);
|
||||||
constexpr ResultCode ERR_INVALID_SIZE(ErrorModule::Kernel, ErrCodes::InvalidSize);
|
constexpr ResultCode ERR_INVALID_SIZE(ErrorModule::Kernel, ErrCodes::InvalidSize);
|
||||||
|
|
|
@ -39,6 +39,73 @@ namespace {
|
||||||
constexpr bool Is4KBAligned(VAddr address) {
|
constexpr bool Is4KBAligned(VAddr address) {
|
||||||
return (address & 0xFFF) == 0;
|
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
|
} // Anonymous namespace
|
||||||
|
|
||||||
/// Set the process heap to a given Size. It can both extend and shrink the heap.
|
/// 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,
|
LOG_TRACE(Kernel_SVC, "called, dst_addr=0x{:X}, src_addr=0x{:X}, size=0x{:X}", dst_addr,
|
||||||
src_addr, size);
|
src_addr, size);
|
||||||
|
|
||||||
if (!Is4KBAligned(dst_addr) || !Is4KBAligned(src_addr)) {
|
auto* const current_process = Core::CurrentProcess();
|
||||||
return ERR_INVALID_ADDRESS;
|
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 current_process->MirrorMemory(dst_addr, src_addr, size);
|
||||||
return ERR_INVALID_SIZE;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Core::CurrentProcess()->MirrorMemory(dst_addr, src_addr, size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Unmaps a region that was previously mapped with svcMapMemory
|
/// 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,
|
LOG_TRACE(Kernel_SVC, "called, dst_addr=0x{:X}, src_addr=0x{:X}, size=0x{:X}", dst_addr,
|
||||||
src_addr, size);
|
src_addr, size);
|
||||||
|
|
||||||
if (!Is4KBAligned(dst_addr) || !Is4KBAligned(src_addr)) {
|
auto* const current_process = Core::CurrentProcess();
|
||||||
return ERR_INVALID_ADDRESS;
|
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 current_process->UnmapMemory(dst_addr, src_addr, size);
|
||||||
return ERR_INVALID_SIZE;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Core::CurrentProcess()->UnmapMemory(dst_addr, src_addr, size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Connect to an OS service given the port name, returns the handle to the port to out
|
/// Connect to an OS service given the port name, returns the handle to the port to out
|
||||||
|
|
Reference in New Issue