diff --git a/src/core/hle/kernel/errors.h b/src/core/hle/kernel/errors.h
index e5fa67ae8d59000d21e32cc462b3b70a4a005aa6..885259618dbe287c8bde0f8c9b516d582255da23 100644
--- a/src/core/hle/kernel/errors.h
+++ b/src/core/hle/kernel/errors.h
@@ -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);
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index 3afcce3fefd061c6a93670c1e1cc86741bfb50fe..3e4dd61dc6da63e8ef92456c30134d2f6cc6ed0c 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -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();
 
-    if (size == 0 || !Is4KBAligned(size)) {
-        return ERR_INVALID_SIZE;
+    const auto result = MapUnmapMemorySanityChecks(vm_manager, dst_addr, src_addr, size);
+    if (result != RESULT_SUCCESS) {
+        return result;
     }
 
-    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();
 
-    if (size == 0 || !Is4KBAligned(size)) {
-        return ERR_INVALID_SIZE;
+    const auto result = MapUnmapMemorySanityChecks(vm_manager, dst_addr, src_addr, size);
+    if (result != RESULT_SUCCESS) {
+        return result;
     }
 
-    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