diff --git a/src/core/hle/kernel/errors.h b/src/core/hle/kernel/errors.h index ad39c8271b..2be2fad82f 100644 --- a/src/core/hle/kernel/errors.h +++ b/src/core/hle/kernel/errors.h @@ -17,6 +17,7 @@ enum { // Confirmed Switch OS error codes MaxConnectionsReached = 7, + InvalidSize = 101, InvalidAddress = 102, HandleTableFull = 105, InvalidMemoryState = 106, @@ -55,6 +56,7 @@ constexpr ResultCode ERR_INVALID_MEMORY_PERMISSIONS(ErrorModule::Kernel, ErrCodes::InvalidMemoryPermissions); 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); constexpr ResultCode ERR_INVALID_STATE(ErrorModule::Kernel, ErrCodes::InvalidState); constexpr ResultCode ERR_INVALID_THREAD_PRIORITY(ErrorModule::Kernel, ErrCodes::InvalidThreadPriority); diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 3c526304f8..c5c1697ee5 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -35,10 +35,21 @@ #include "core/hle/service/service.h" namespace Kernel { +namespace { +constexpr bool Is4KBAligned(VAddr address) { + return (address & 0xFFF) == 0; +} +} // Anonymous namespace /// Set the process heap to a given Size. It can both extend and shrink the heap. static ResultCode SetHeapSize(VAddr* heap_addr, u64 heap_size) { LOG_TRACE(Kernel_SVC, "called, heap_size=0x{:X}", heap_size); + + // Size must be a multiple of 0x200000 (2MB) and be equal to or less than 4GB. + if ((heap_size & 0xFFFFFFFE001FFFFF) != 0) { + return ERR_INVALID_SIZE; + } + auto& process = *Core::CurrentProcess(); CASCADE_RESULT(*heap_addr, process.HeapAllocate(Memory::HEAP_VADDR, heap_size, VMAPermission::ReadWrite)); @@ -56,6 +67,15 @@ static ResultCode SetMemoryAttribute(VAddr addr, u64 size, u32 state0, u32 state 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; + } + + if (size == 0 || !Is4KBAligned(size)) { + return ERR_INVALID_SIZE; + } + return Core::CurrentProcess()->MirrorMemory(dst_addr, src_addr, size); } @@ -63,6 +83,15 @@ static ResultCode MapMemory(VAddr dst_addr, VAddr src_addr, u64 size) { 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; + } + + if (size == 0 || !Is4KBAligned(size)) { + return ERR_INVALID_SIZE; + } + return Core::CurrentProcess()->UnmapMemory(dst_addr, src_addr, size); } @@ -415,35 +444,43 @@ static ResultCode MapSharedMemory(Handle shared_memory_handle, VAddr addr, u64 s "called, shared_memory_handle=0x{:X}, addr=0x{:X}, size=0x{:X}, permissions=0x{:08X}", shared_memory_handle, addr, size, permissions); + if (!Is4KBAligned(addr)) { + return ERR_INVALID_ADDRESS; + } + + if (size == 0 || !Is4KBAligned(size)) { + return ERR_INVALID_SIZE; + } + + const auto permissions_type = static_cast(permissions); + if (permissions_type != MemoryPermission::Read && + permissions_type != MemoryPermission::ReadWrite) { + LOG_ERROR(Kernel_SVC, "Invalid permissions=0x{:08X}", permissions); + return ERR_INVALID_MEMORY_PERMISSIONS; + } + auto& kernel = Core::System::GetInstance().Kernel(); auto shared_memory = kernel.HandleTable().Get(shared_memory_handle); if (!shared_memory) { return ERR_INVALID_HANDLE; } - MemoryPermission permissions_type = static_cast(permissions); - switch (permissions_type) { - case MemoryPermission::Read: - case MemoryPermission::Write: - case MemoryPermission::ReadWrite: - case MemoryPermission::Execute: - case MemoryPermission::ReadExecute: - case MemoryPermission::WriteExecute: - case MemoryPermission::ReadWriteExecute: - case MemoryPermission::DontCare: - return shared_memory->Map(Core::CurrentProcess().get(), addr, permissions_type, - MemoryPermission::DontCare); - default: - LOG_ERROR(Kernel_SVC, "unknown permissions=0x{:08X}", permissions); - } - - return RESULT_SUCCESS; + return shared_memory->Map(Core::CurrentProcess().get(), addr, permissions_type, + MemoryPermission::DontCare); } static ResultCode UnmapSharedMemory(Handle shared_memory_handle, VAddr addr, u64 size) { LOG_WARNING(Kernel_SVC, "called, shared_memory_handle=0x{:08X}, addr=0x{:X}, size=0x{:X}", shared_memory_handle, addr, size); + if (!Is4KBAligned(addr)) { + return ERR_INVALID_ADDRESS; + } + + if (size == 0 || !Is4KBAligned(size)) { + return ERR_INVALID_SIZE; + } + auto& kernel = Core::System::GetInstance().Kernel(); auto shared_memory = kernel.HandleTable().Get(shared_memory_handle); @@ -899,12 +936,28 @@ static ResultCode CreateSharedMemory(Handle* handle, u64 size, u32 local_permiss LOG_TRACE(Kernel_SVC, "called, size=0x{:X}, localPerms=0x{:08X}, remotePerms=0x{:08X}", size, local_permissions, remote_permissions); + // Size must be a multiple of 4KB and be less than or equal to + // approx. 8 GB (actually (1GB - 512B) * 8) + if (size == 0 || (size & 0xFFFFFFFE00000FFF) != 0) { + return ERR_INVALID_SIZE; + } + + const auto local_perms = static_cast(local_permissions); + if (local_perms != MemoryPermission::Read && local_perms != MemoryPermission::ReadWrite) { + return ERR_INVALID_MEMORY_PERMISSIONS; + } + + const auto remote_perms = static_cast(remote_permissions); + if (remote_perms != MemoryPermission::Read && remote_perms != MemoryPermission::ReadWrite && + remote_perms != MemoryPermission::DontCare) { + return ERR_INVALID_MEMORY_PERMISSIONS; + } + auto& kernel = Core::System::GetInstance().Kernel(); auto& handle_table = kernel.HandleTable(); auto shared_mem_handle = SharedMemory::Create(kernel, handle_table.Get(KernelHandle::CurrentProcess), size, - static_cast(local_permissions), - static_cast(remote_permissions)); + local_perms, remote_perms); CASCADE_RESULT(*handle, handle_table.Create(shared_mem_handle)); return RESULT_SUCCESS;