From 607bd59a9cb78205e4b9d1013a9dbaa6899d07b5 Mon Sep 17 00:00:00 2001 From: Stephen Miller Date: Sat, 21 Jun 2025 13:39:13 -0500 Subject: [PATCH] Validate requested dmem range in MapMemory Handles a rare edge case that only comes up when modding Driveclub --- src/core/memory.cpp | 22 ++++++++++++++++++++++ src/core/memory.h | 10 +++++++--- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/src/core/memory.cpp b/src/core/memory.cpp index dad42347a..a50a298cb 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -320,6 +320,28 @@ s32 MemoryManager::MapMemory(void** out_addr, VAddr virtual_addr, u64 size, Memo return ORBIS_KERNEL_ERROR_ENOMEM; } + // Validate the requested physical address range + if (phys_addr != -1) { + auto validated_size = 0; + do { + auto dmem_area = FindDmemArea(phys_addr + validated_size)->second; + // If any requested dmem area is not allocated, return an error. + if (dmem_area.is_free) { + LOG_ERROR(Kernel_Vmm, "Unable to map {:#x} bytes at physical address {:#x}", size, + phys_addr); + return ORBIS_KERNEL_ERROR_ENOMEM; + } + // Track how much we've validated. + validated_size += dmem_area.size - (phys_addr + validated_size - dmem_area.base); + } while (validated_size < size && phys_addr + validated_size < GetTotalDirectSize()); + // If the requested range goes outside the dmem map, return an error. + if (validated_size < size) { + LOG_ERROR(Kernel_Vmm, "Unable to map {:#x} bytes at physical address {:#x}", size, + phys_addr); + return ORBIS_KERNEL_ERROR_ENOMEM; + } + } + // Limit the minumum address to SystemManagedVirtualBase to prevent hardware-specific issues. VAddr mapped_addr = (virtual_addr == 0) ? impl.SystemManagedVirtualBase() : virtual_addr; diff --git a/src/core/memory.h b/src/core/memory.h index d0a2a09b4..84c60dee8 100644 --- a/src/core/memory.h +++ b/src/core/memory.h @@ -63,8 +63,8 @@ enum class VMAType : u32 { struct DirectMemoryArea { PAddr base = 0; - size_t size = 0; - int memory_type = 0; + u64 size = 0; + s32 memory_type = 0; bool is_pooled = false; bool is_free = true; @@ -72,6 +72,10 @@ struct DirectMemoryArea { return base + size; } + bool Contains(PAddr addr, u64 size) const { + return addr >= base && (addr + size) <= (base + this->size); + } + bool CanMergeWith(const DirectMemoryArea& next) const { if (base + size != next.base) { return false; @@ -88,7 +92,7 @@ struct DirectMemoryArea { struct VirtualMemoryArea { VAddr base = 0; - size_t size = 0; + u64 size = 0; PAddr phys_base = 0; VMAType type = VMAType::Free; MemoryProt prot = MemoryProt::NoAccess;