diff options
| author | 2018-09-17 10:11:26 -0400 | |
|---|---|---|
| committer | 2018-09-17 10:11:26 -0400 | |
| commit | e6367ab955b8ced2acfe1b191f812e1b442fe2ae (patch) | |
| tree | 65ebdbeae1198e9c22760d64e3982ddd8bf209c8 | |
| parent | Merge pull request #1320 from lioncash/name (diff) | |
| parent | kernel/svc: Sanitize creation of shared memory via svcCreateSharedMemory() (diff) | |
| download | yuzu-e6367ab955b8ced2acfe1b191f812e1b442fe2ae.tar.gz yuzu-e6367ab955b8ced2acfe1b191f812e1b442fe2ae.tar.xz yuzu-e6367ab955b8ced2acfe1b191f812e1b442fe2ae.zip | |
Merge pull request #1315 from lioncash/size
kernel/svc: Handle a few error cases within memory-related functions
| -rw-r--r-- | src/core/hle/kernel/errors.h | 2 | ||||
| -rw-r--r-- | src/core/hle/kernel/svc.cpp | 91 |
2 files changed, 74 insertions, 19 deletions
diff --git a/src/core/hle/kernel/errors.h b/src/core/hle/kernel/errors.h index ad39c8271..2be2fad82 100644 --- a/src/core/hle/kernel/errors.h +++ b/src/core/hle/kernel/errors.h | |||
| @@ -17,6 +17,7 @@ enum { | |||
| 17 | 17 | ||
| 18 | // Confirmed Switch OS error codes | 18 | // Confirmed Switch OS error codes |
| 19 | MaxConnectionsReached = 7, | 19 | MaxConnectionsReached = 7, |
| 20 | InvalidSize = 101, | ||
| 20 | InvalidAddress = 102, | 21 | InvalidAddress = 102, |
| 21 | HandleTableFull = 105, | 22 | HandleTableFull = 105, |
| 22 | InvalidMemoryState = 106, | 23 | InvalidMemoryState = 106, |
| @@ -55,6 +56,7 @@ constexpr ResultCode ERR_INVALID_MEMORY_PERMISSIONS(ErrorModule::Kernel, | |||
| 55 | ErrCodes::InvalidMemoryPermissions); | 56 | ErrCodes::InvalidMemoryPermissions); |
| 56 | constexpr ResultCode ERR_INVALID_HANDLE(ErrorModule::Kernel, ErrCodes::InvalidHandle); | 57 | constexpr ResultCode ERR_INVALID_HANDLE(ErrorModule::Kernel, ErrCodes::InvalidHandle); |
| 57 | constexpr ResultCode ERR_INVALID_PROCESSOR_ID(ErrorModule::Kernel, ErrCodes::InvalidProcessorId); | 58 | constexpr ResultCode ERR_INVALID_PROCESSOR_ID(ErrorModule::Kernel, ErrCodes::InvalidProcessorId); |
| 59 | constexpr ResultCode ERR_INVALID_SIZE(ErrorModule::Kernel, ErrCodes::InvalidSize); | ||
| 58 | constexpr ResultCode ERR_INVALID_STATE(ErrorModule::Kernel, ErrCodes::InvalidState); | 60 | constexpr ResultCode ERR_INVALID_STATE(ErrorModule::Kernel, ErrCodes::InvalidState); |
| 59 | constexpr ResultCode ERR_INVALID_THREAD_PRIORITY(ErrorModule::Kernel, | 61 | constexpr ResultCode ERR_INVALID_THREAD_PRIORITY(ErrorModule::Kernel, |
| 60 | ErrCodes::InvalidThreadPriority); | 62 | ErrCodes::InvalidThreadPriority); |
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 3c526304f..c5c1697ee 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp | |||
| @@ -35,10 +35,21 @@ | |||
| 35 | #include "core/hle/service/service.h" | 35 | #include "core/hle/service/service.h" |
| 36 | 36 | ||
| 37 | namespace Kernel { | 37 | namespace Kernel { |
| 38 | namespace { | ||
| 39 | constexpr bool Is4KBAligned(VAddr address) { | ||
| 40 | return (address & 0xFFF) == 0; | ||
| 41 | } | ||
| 42 | } // Anonymous namespace | ||
| 38 | 43 | ||
| 39 | /// Set the process heap to a given Size. It can both extend and shrink the heap. | 44 | /// Set the process heap to a given Size. It can both extend and shrink the heap. |
| 40 | static ResultCode SetHeapSize(VAddr* heap_addr, u64 heap_size) { | 45 | static ResultCode SetHeapSize(VAddr* heap_addr, u64 heap_size) { |
| 41 | LOG_TRACE(Kernel_SVC, "called, heap_size=0x{:X}", heap_size); | 46 | LOG_TRACE(Kernel_SVC, "called, heap_size=0x{:X}", heap_size); |
| 47 | |||
| 48 | // Size must be a multiple of 0x200000 (2MB) and be equal to or less than 4GB. | ||
| 49 | if ((heap_size & 0xFFFFFFFE001FFFFF) != 0) { | ||
| 50 | return ERR_INVALID_SIZE; | ||
| 51 | } | ||
| 52 | |||
| 42 | auto& process = *Core::CurrentProcess(); | 53 | auto& process = *Core::CurrentProcess(); |
| 43 | CASCADE_RESULT(*heap_addr, | 54 | CASCADE_RESULT(*heap_addr, |
| 44 | process.HeapAllocate(Memory::HEAP_VADDR, heap_size, VMAPermission::ReadWrite)); | 55 | process.HeapAllocate(Memory::HEAP_VADDR, heap_size, VMAPermission::ReadWrite)); |
| @@ -56,6 +67,15 @@ static ResultCode SetMemoryAttribute(VAddr addr, u64 size, u32 state0, u32 state | |||
| 56 | static ResultCode MapMemory(VAddr dst_addr, VAddr src_addr, u64 size) { | 67 | static ResultCode MapMemory(VAddr dst_addr, VAddr src_addr, u64 size) { |
| 57 | LOG_TRACE(Kernel_SVC, "called, dst_addr=0x{:X}, src_addr=0x{:X}, size=0x{:X}", dst_addr, | 68 | LOG_TRACE(Kernel_SVC, "called, dst_addr=0x{:X}, src_addr=0x{:X}, size=0x{:X}", dst_addr, |
| 58 | src_addr, size); | 69 | src_addr, size); |
| 70 | |||
| 71 | if (!Is4KBAligned(dst_addr) || !Is4KBAligned(src_addr)) { | ||
| 72 | return ERR_INVALID_ADDRESS; | ||
| 73 | } | ||
| 74 | |||
| 75 | if (size == 0 || !Is4KBAligned(size)) { | ||
| 76 | return ERR_INVALID_SIZE; | ||
| 77 | } | ||
| 78 | |||
| 59 | return Core::CurrentProcess()->MirrorMemory(dst_addr, src_addr, size); | 79 | return Core::CurrentProcess()->MirrorMemory(dst_addr, src_addr, size); |
| 60 | } | 80 | } |
| 61 | 81 | ||
| @@ -63,6 +83,15 @@ static ResultCode MapMemory(VAddr dst_addr, VAddr src_addr, u64 size) { | |||
| 63 | static ResultCode UnmapMemory(VAddr dst_addr, VAddr src_addr, u64 size) { | 83 | static ResultCode UnmapMemory(VAddr dst_addr, VAddr src_addr, u64 size) { |
| 64 | LOG_TRACE(Kernel_SVC, "called, dst_addr=0x{:X}, src_addr=0x{:X}, size=0x{:X}", dst_addr, | 84 | LOG_TRACE(Kernel_SVC, "called, dst_addr=0x{:X}, src_addr=0x{:X}, size=0x{:X}", dst_addr, |
| 65 | src_addr, size); | 85 | src_addr, size); |
| 86 | |||
| 87 | if (!Is4KBAligned(dst_addr) || !Is4KBAligned(src_addr)) { | ||
| 88 | return ERR_INVALID_ADDRESS; | ||
| 89 | } | ||
| 90 | |||
| 91 | if (size == 0 || !Is4KBAligned(size)) { | ||
| 92 | return ERR_INVALID_SIZE; | ||
| 93 | } | ||
| 94 | |||
| 66 | return Core::CurrentProcess()->UnmapMemory(dst_addr, src_addr, size); | 95 | return Core::CurrentProcess()->UnmapMemory(dst_addr, src_addr, size); |
| 67 | } | 96 | } |
| 68 | 97 | ||
| @@ -415,35 +444,43 @@ static ResultCode MapSharedMemory(Handle shared_memory_handle, VAddr addr, u64 s | |||
| 415 | "called, shared_memory_handle=0x{:X}, addr=0x{:X}, size=0x{:X}, permissions=0x{:08X}", | 444 | "called, shared_memory_handle=0x{:X}, addr=0x{:X}, size=0x{:X}, permissions=0x{:08X}", |
| 416 | shared_memory_handle, addr, size, permissions); | 445 | shared_memory_handle, addr, size, permissions); |
| 417 | 446 | ||
| 447 | if (!Is4KBAligned(addr)) { | ||
| 448 | return ERR_INVALID_ADDRESS; | ||
| 449 | } | ||
| 450 | |||
| 451 | if (size == 0 || !Is4KBAligned(size)) { | ||
| 452 | return ERR_INVALID_SIZE; | ||
| 453 | } | ||
| 454 | |||
| 455 | const auto permissions_type = static_cast<MemoryPermission>(permissions); | ||
| 456 | if (permissions_type != MemoryPermission::Read && | ||
| 457 | permissions_type != MemoryPermission::ReadWrite) { | ||
| 458 | LOG_ERROR(Kernel_SVC, "Invalid permissions=0x{:08X}", permissions); | ||
| 459 | return ERR_INVALID_MEMORY_PERMISSIONS; | ||
| 460 | } | ||
| 461 | |||
| 418 | auto& kernel = Core::System::GetInstance().Kernel(); | 462 | auto& kernel = Core::System::GetInstance().Kernel(); |
| 419 | auto shared_memory = kernel.HandleTable().Get<SharedMemory>(shared_memory_handle); | 463 | auto shared_memory = kernel.HandleTable().Get<SharedMemory>(shared_memory_handle); |
| 420 | if (!shared_memory) { | 464 | if (!shared_memory) { |
| 421 | return ERR_INVALID_HANDLE; | 465 | return ERR_INVALID_HANDLE; |
| 422 | } | 466 | } |
| 423 | 467 | ||
| 424 | MemoryPermission permissions_type = static_cast<MemoryPermission>(permissions); | 468 | return shared_memory->Map(Core::CurrentProcess().get(), addr, permissions_type, |
| 425 | switch (permissions_type) { | 469 | MemoryPermission::DontCare); |
| 426 | case MemoryPermission::Read: | ||
| 427 | case MemoryPermission::Write: | ||
| 428 | case MemoryPermission::ReadWrite: | ||
| 429 | case MemoryPermission::Execute: | ||
| 430 | case MemoryPermission::ReadExecute: | ||
| 431 | case MemoryPermission::WriteExecute: | ||
| 432 | case MemoryPermission::ReadWriteExecute: | ||
| 433 | case MemoryPermission::DontCare: | ||
| 434 | return shared_memory->Map(Core::CurrentProcess().get(), addr, permissions_type, | ||
| 435 | MemoryPermission::DontCare); | ||
| 436 | default: | ||
| 437 | LOG_ERROR(Kernel_SVC, "unknown permissions=0x{:08X}", permissions); | ||
| 438 | } | ||
| 439 | |||
| 440 | return RESULT_SUCCESS; | ||
| 441 | } | 470 | } |
| 442 | 471 | ||
| 443 | static ResultCode UnmapSharedMemory(Handle shared_memory_handle, VAddr addr, u64 size) { | 472 | static ResultCode UnmapSharedMemory(Handle shared_memory_handle, VAddr addr, u64 size) { |
| 444 | LOG_WARNING(Kernel_SVC, "called, shared_memory_handle=0x{:08X}, addr=0x{:X}, size=0x{:X}", | 473 | LOG_WARNING(Kernel_SVC, "called, shared_memory_handle=0x{:08X}, addr=0x{:X}, size=0x{:X}", |
| 445 | shared_memory_handle, addr, size); | 474 | shared_memory_handle, addr, size); |
| 446 | 475 | ||
| 476 | if (!Is4KBAligned(addr)) { | ||
| 477 | return ERR_INVALID_ADDRESS; | ||
| 478 | } | ||
| 479 | |||
| 480 | if (size == 0 || !Is4KBAligned(size)) { | ||
| 481 | return ERR_INVALID_SIZE; | ||
| 482 | } | ||
| 483 | |||
| 447 | auto& kernel = Core::System::GetInstance().Kernel(); | 484 | auto& kernel = Core::System::GetInstance().Kernel(); |
| 448 | auto shared_memory = kernel.HandleTable().Get<SharedMemory>(shared_memory_handle); | 485 | auto shared_memory = kernel.HandleTable().Get<SharedMemory>(shared_memory_handle); |
| 449 | 486 | ||
| @@ -899,12 +936,28 @@ static ResultCode CreateSharedMemory(Handle* handle, u64 size, u32 local_permiss | |||
| 899 | LOG_TRACE(Kernel_SVC, "called, size=0x{:X}, localPerms=0x{:08X}, remotePerms=0x{:08X}", size, | 936 | LOG_TRACE(Kernel_SVC, "called, size=0x{:X}, localPerms=0x{:08X}, remotePerms=0x{:08X}", size, |
| 900 | local_permissions, remote_permissions); | 937 | local_permissions, remote_permissions); |
| 901 | 938 | ||
| 939 | // Size must be a multiple of 4KB and be less than or equal to | ||
| 940 | // approx. 8 GB (actually (1GB - 512B) * 8) | ||
| 941 | if (size == 0 || (size & 0xFFFFFFFE00000FFF) != 0) { | ||
| 942 | return ERR_INVALID_SIZE; | ||
| 943 | } | ||
| 944 | |||
| 945 | const auto local_perms = static_cast<MemoryPermission>(local_permissions); | ||
| 946 | if (local_perms != MemoryPermission::Read && local_perms != MemoryPermission::ReadWrite) { | ||
| 947 | return ERR_INVALID_MEMORY_PERMISSIONS; | ||
| 948 | } | ||
| 949 | |||
| 950 | const auto remote_perms = static_cast<MemoryPermission>(remote_permissions); | ||
| 951 | if (remote_perms != MemoryPermission::Read && remote_perms != MemoryPermission::ReadWrite && | ||
| 952 | remote_perms != MemoryPermission::DontCare) { | ||
| 953 | return ERR_INVALID_MEMORY_PERMISSIONS; | ||
| 954 | } | ||
| 955 | |||
| 902 | auto& kernel = Core::System::GetInstance().Kernel(); | 956 | auto& kernel = Core::System::GetInstance().Kernel(); |
| 903 | auto& handle_table = kernel.HandleTable(); | 957 | auto& handle_table = kernel.HandleTable(); |
| 904 | auto shared_mem_handle = | 958 | auto shared_mem_handle = |
| 905 | SharedMemory::Create(kernel, handle_table.Get<Process>(KernelHandle::CurrentProcess), size, | 959 | SharedMemory::Create(kernel, handle_table.Get<Process>(KernelHandle::CurrentProcess), size, |
| 906 | static_cast<MemoryPermission>(local_permissions), | 960 | local_perms, remote_perms); |
| 907 | static_cast<MemoryPermission>(remote_permissions)); | ||
| 908 | 961 | ||
| 909 | CASCADE_RESULT(*handle, handle_table.Create(shared_mem_handle)); | 962 | CASCADE_RESULT(*handle, handle_table.Create(shared_mem_handle)); |
| 910 | return RESULT_SUCCESS; | 963 | return RESULT_SUCCESS; |