From 0f15010ba542cbaf78934fd50e30ef8399ce48a9 Mon Sep 17 00:00:00 2001 From: Alula Date: Sun, 13 Sep 2026 11:41:53 +0200 Subject: [PATCH 1/5] kern/loader: make aware of new address space and shadow stack region --- .../arch/arm64/kern_cpu_system_registers.hpp | 1 + .../arch/arm64/kern_k_page_table.hpp | 12 +++- .../arch/arm64/kern_k_process_page_table.hpp | 26 +++---- .../mesosphere/init/kern_init_slab_setup.hpp | 19 ++++++ .../mesosphere/kern_k_address_space_info.hpp | 2 +- .../mesosphere/kern_k_memory_block.hpp | 20 +++--- .../mesosphere/kern_k_page_table_base.hpp | 55 +++++++++------ .../include/mesosphere/kern_k_process.hpp | 1 + .../source/arch/arm64/kern_k_page_table.cpp | 4 +- .../source/init/kern_init_slab_setup.cpp | 19 ------ .../source/kern_k_address_space_info.cpp | 12 +++- .../source/kern_k_initial_process_reader.cpp | 2 +- .../source/kern_k_page_table_base.cpp | 67 ++++++++++++++----- .../source/svc/kern_svc_info.cpp | 12 ++++ .../source/svc/kern_svc_process.cpp | 8 ++- .../include/stratosphere/cfg/cfg_types.hpp | 1 + .../include/stratosphere/ldr/ldr_types.hpp | 8 ++- .../cfg/cfg_override.board.nintendo_nx.inc | 2 + .../impl/osdbg_thread_info.os.horizon.hpp | 4 +- .../include/vapours/svc/svc_memory_map.hpp | 16 +++++ .../include/vapours/svc/svc_types_common.hpp | 19 +++++- .../include/vapours/svc/svc_version.hpp | 2 +- .../source/arch/arm64/init/kern_init_core.cpp | 17 ++++- stratosphere/loader/source/ldr_meta.cpp | 1 + .../loader/source/ldr_process_creation.cpp | 7 ++ 25 files changed, 238 insertions(+), 99 deletions(-) diff --git a/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_cpu_system_registers.hpp b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_cpu_system_registers.hpp index 61e066fee..1b6d93201 100644 --- a/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_cpu_system_registers.hpp +++ b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_cpu_system_registers.hpp @@ -81,6 +81,7 @@ namespace ams::kern::arch::arm64::cpu { MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(SpEl0, sp_el0) MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(IdAa64Dfr0El1, id_aa64dfr0_el1) + MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(IdAa64Mmfr0El1, id_aa64mmfr0_el1) MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(PmcrEl0, pmcr_el0) MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(PmUserEnrEl0, pmuserenr_el0) diff --git a/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_page_table.hpp b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_page_table.hpp index 2ab8527c9..356dc4217 100644 --- a/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_page_table.hpp +++ b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_page_table.hpp @@ -94,10 +94,10 @@ namespace ams::kern::arch::arm64 { return KPageTable::GetBlockSize(static_cast(KPageTable::GetBlockType(alignment) + 1)); } public: - /* TODO: How should this size be determined. Does the KProcess slab count need to go in a header as a define? */ - static constexpr size_t NumTtbr0Entries = 81; + static constexpr size_t NumPTEntries = ::ams::kern::init::SlabCountKProcess + 1; /* +1 for kernel. */ private: - static constinit inline const volatile u64 s_ttbr0_entries[NumTtbr0Entries] = {}; + static constinit inline const volatile u64 s_ttbr0_entries[NumPTEntries] = {}; + static constinit inline const volatile u64 s_tcr_el1_entries[NumPTEntries] = {}; private: KPageTableManager *m_manager; u8 m_asid; @@ -188,6 +188,12 @@ namespace ams::kern::arch::arm64 { return s_ttbr0_entries[0]; } + static const volatile u64 &GetTcrEL1Entry(size_t index) { return s_tcr_el1_entries[index]; } + + static ALWAYS_INLINE u64 GetKernelTcrEL1() { + return s_tcr_el1_entries[0]; + } + static ALWAYS_INLINE void ActivateKernel() { /* Activate, using asid 0 and process id = 0xFFFFFFFF */ cpu::SwitchProcess(GetKernelTtbr0(), 0xFFFFFFFF); diff --git a/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_process_page_table.hpp b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_process_page_table.hpp index e18a6fbc8..63a357e0e 100644 --- a/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_process_page_table.hpp +++ b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_process_page_table.hpp @@ -302,19 +302,21 @@ namespace ams::kern::arch::arm64 { bool CanContain(KProcessAddress addr, size_t size, KMemoryState state) const { return m_page_table.CanContain(addr, size, state); } bool CanContain(KProcessAddress addr, size_t size, ams::svc::MemoryState state) const { return m_page_table.CanContain(addr, size, state); } - KProcessAddress GetAddressSpaceStart() const { return m_page_table.GetAddressSpaceStart(); } - KProcessAddress GetHeapRegionStart() const { return m_page_table.GetHeapRegionStart(); } - KProcessAddress GetAliasRegionStart() const { return m_page_table.GetAliasRegionStart(); } - KProcessAddress GetStackRegionStart() const { return m_page_table.GetStackRegionStart(); } - KProcessAddress GetKernelMapRegionStart() const { return m_page_table.GetKernelMapRegionStart(); } - KProcessAddress GetAliasCodeRegionStart() const { return m_page_table.GetAliasCodeRegionStart(); } + KProcessAddress GetAddressSpaceStart() const { return m_page_table.GetAddressSpaceStart(); } + KProcessAddress GetShadowStackRegionStart() const { return m_page_table.GetShadowStackRegionStart(); } + KProcessAddress GetHeapRegionStart() const { return m_page_table.GetHeapRegionStart(); } + KProcessAddress GetAliasRegionStart() const { return m_page_table.GetAliasRegionStart(); } + KProcessAddress GetStackRegionStart() const { return m_page_table.GetStackRegionStart(); } + KProcessAddress GetKernelMapRegionStart() const { return m_page_table.GetKernelMapRegionStart(); } + KProcessAddress GetAliasCodeRegionStart() const { return m_page_table.GetAliasCodeRegionStart(); } - size_t GetAddressSpaceSize() const { return m_page_table.GetAddressSpaceSize(); } - size_t GetHeapRegionSize() const { return m_page_table.GetHeapRegionSize(); } - size_t GetAliasRegionSize() const { return m_page_table.GetAliasRegionSize(); } - size_t GetStackRegionSize() const { return m_page_table.GetStackRegionSize(); } - size_t GetKernelMapRegionSize() const { return m_page_table.GetKernelMapRegionSize(); } - size_t GetAliasCodeRegionSize() const { return m_page_table.GetAliasCodeRegionSize(); } + size_t GetAddressSpaceSize() const { return m_page_table.GetAddressSpaceSize(); } + size_t GetShadowStackRegionSize() const { return m_page_table.GetShadowStackRegionSize(); } + size_t GetHeapRegionSize() const { return m_page_table.GetHeapRegionSize(); } + size_t GetAliasRegionSize() const { return m_page_table.GetAliasRegionSize(); } + size_t GetStackRegionSize() const { return m_page_table.GetStackRegionSize(); } + size_t GetKernelMapRegionSize() const { return m_page_table.GetKernelMapRegionSize(); } + size_t GetAliasCodeRegionSize() const { return m_page_table.GetAliasCodeRegionSize(); } size_t GetAliasRegionExtraSize() const { return m_page_table.GetAliasRegionExtraSize(); } diff --git a/libraries/libmesosphere/include/mesosphere/init/kern_init_slab_setup.hpp b/libraries/libmesosphere/include/mesosphere/init/kern_init_slab_setup.hpp index 209b8d732..32bba1e5a 100644 --- a/libraries/libmesosphere/include/mesosphere/init/kern_init_slab_setup.hpp +++ b/libraries/libmesosphere/include/mesosphere/init/kern_init_slab_setup.hpp @@ -18,6 +18,25 @@ #include namespace ams::kern::init { + /* Constexpr counts. */ + constexpr size_t SlabCountKProcess = 80; + constexpr size_t SlabCountKThread = 800; + constexpr size_t SlabCountKEvent = 900; + constexpr size_t SlabCountKInterruptEvent = 100; + constexpr size_t SlabCountKPort = 384; + constexpr size_t SlabCountKSharedMemory = 80; + constexpr size_t SlabCountKTransferMemory = 200; + constexpr size_t SlabCountKCodeMemory = 10; + constexpr size_t SlabCountKDeviceAddressSpace = 300; + constexpr size_t SlabCountKSession = 1133; + constexpr size_t SlabCountKLightSession = 100; + constexpr size_t SlabCountKObjectName = 7; + constexpr size_t SlabCountKResourceLimit = 5; + constexpr size_t SlabCountKDebug = cpu::NumCores; + constexpr size_t SlabCountKIoPool = 1; + constexpr size_t SlabCountKIoRegion = 6; + constexpr size_t SlabcountKSessionRequestMappings = 40; + struct KSlabResourceCounts { size_t num_KProcess; diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_address_space_info.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_address_space_info.hpp index 775c0054c..00d942a66 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_address_space_info.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_address_space_info.hpp @@ -24,7 +24,7 @@ namespace ams::kern { enum Type { Type_MapSmall = 0, Type_MapLarge = 1, - Type_Map39Bit = 2, + Type_MapHuge = 2, Type_Heap = 3, Type_Stack = 4, Type_Alias = 5, diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_memory_block.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_memory_block.hpp index 57876fbcb..9e9e9c7a4 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_memory_block.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_memory_block.hpp @@ -211,15 +211,15 @@ namespace ams::kern { uintptr_t m_address; size_t m_size; KMemoryState m_state; - u16 m_device_disable_merge_left_count; - u16 m_device_disable_merge_right_count; - u16 m_ipc_lock_count; - u16 m_device_use_count; - u16 m_ipc_disable_merge_count; KMemoryPermission m_permission; KMemoryAttribute m_attribute; KMemoryPermission m_original_permission; + u16 m_ipc_lock_count; + u16 m_device_use_count; KMemoryBlockDisableMergeAttribute m_disable_merge_attribute; + u16 m_ipc_disable_merge_count; + u16 m_device_disable_merge_left_count; + u16 m_device_disable_merge_right_count; constexpr ams::svc::MemoryInfo GetSvcMemoryInfo() const { return { @@ -365,15 +365,15 @@ namespace ams::kern { .m_address = GetInteger(this->GetAddress()), .m_size = this->GetSize(), .m_state = m_memory_state, - .m_device_disable_merge_left_count = m_device_disable_merge_left_count, - .m_device_disable_merge_right_count = m_device_disable_merge_right_count, - .m_ipc_lock_count = m_ipc_lock_count, - .m_device_use_count = m_device_use_count, - .m_ipc_disable_merge_count = m_ipc_disable_merge_count, .m_permission = m_permission, .m_attribute = m_attribute, .m_original_permission = m_original_permission, + .m_ipc_lock_count = m_ipc_lock_count, + .m_device_use_count = m_device_use_count, .m_disable_merge_attribute = m_disable_merge_attribute, + .m_ipc_disable_merge_count = m_ipc_disable_merge_count, + .m_device_disable_merge_left_count = m_device_disable_merge_left_count, + .m_device_disable_merge_right_count = m_device_disable_merge_right_count, }; } public: diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_page_table_base.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_page_table_base.hpp index 25c149b7f..759fd1758 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_page_table_base.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_page_table_base.hpp @@ -90,10 +90,11 @@ namespace ams::kern { }; enum RegionType { - RegionType_KernelMap = 0, - RegionType_Stack = 1, - RegionType_Alias = 2, - RegionType_Heap = 3, + RegionType_KernelMap = 0, + RegionType_Stack = 1, + RegionType_Alias = 2, + RegionType_Heap = 3, + RegionType_ShadowStack = 4, RegionType_Count, }; @@ -196,7 +197,6 @@ namespace ams::kern { KPageTableImpl m_impl; KMemoryBlockManager m_memory_block_manager; u32 m_allocate_option; - u32 m_address_space_width; bool m_is_kernel; bool m_enable_aslr; bool m_enable_device_address_space_merge; @@ -212,23 +212,24 @@ namespace ams::kern { public: constexpr explicit KPageTableBase(util::ConstantInitializeTag) : m_address_space_start(Null), m_address_space_end(Null), - m_region_starts{Null, Null, Null, Null}, - m_region_ends{Null, Null, Null, Null}, + m_region_starts{Null, Null, Null, Null, Null}, + m_region_ends{Null, Null, Null, Null, Null}, m_current_heap_end(Null), m_alias_code_region_start(Null), m_alias_code_region_end(Null), m_code_region_start(Null), m_code_region_end(Null), - m_max_heap_size(), m_mapped_physical_memory_size(), m_mapped_unsafe_physical_memory(), m_mapped_insecure_memory(), m_mapped_ipc_server_memory(), m_alias_region_extra_size(), - m_general_lock(), m_map_physical_memory_lock(), m_device_map_lock(), m_impl(util::ConstantInitialize), m_memory_block_manager(util::ConstantInitialize), - m_allocate_option(), m_address_space_width(), m_is_kernel(), m_enable_aslr(), m_enable_device_address_space_merge(), m_allowed_exec_device_mapping(), - m_memory_block_slab_manager(), m_block_info_manager(), m_resource_limit(), m_cached_physical_linear_region(), m_cached_physical_heap_region(), - m_heap_fill_value(), m_ipc_fill_value(), m_stack_fill_value() + m_max_heap_size(), m_mapped_physical_memory_size(), m_mapped_unsafe_physical_memory(), m_mapped_insecure_memory(), + m_mapped_ipc_server_memory(), m_alias_region_extra_size(), m_general_lock(), m_map_physical_memory_lock(), + m_device_map_lock(), m_impl(util::ConstantInitialize), m_memory_block_manager(util::ConstantInitialize), + m_allocate_option(), m_is_kernel(), m_enable_aslr(), m_enable_device_address_space_merge(), m_allowed_exec_device_mapping(), + m_memory_block_slab_manager(), m_block_info_manager(), m_resource_limit(), m_cached_physical_linear_region(), + m_cached_physical_heap_region(), m_heap_fill_value(), m_ipc_fill_value(), m_stack_fill_value() { /* ... */ } explicit KPageTableBase() { /* ... */ } - NOINLINE void InitializeForKernel(bool is_64_bit, void *table, KVirtualAddress start, KVirtualAddress end); - NOINLINE Result InitializeForProcess(ams::svc::CreateProcessFlag flags, bool from_back, KMemoryManager::Pool pool, void *table, KProcessAddress start, KProcessAddress end, KProcessAddress code_address, size_t code_size, KSystemResource *system_resource, KResourceLimit *resource_limit); + NOINLINE void InitializeForKernel(void *table, KVirtualAddress start, KVirtualAddress end); + NOINLINE Result InitializeForProcess(ams::svc::CreateProcessFlag flags, bool from_back, void *table, KProcessAddress start, KProcessAddress end, KMemoryManager::Pool pool, KProcessAddress code_address, size_t code_size, KSystemResource *system_resource, KResourceLimit *resource_limit); void Finalize(); @@ -247,6 +248,14 @@ namespace ams::kern { return this->Contains(addr, size) && m_region_starts[RegionType_Alias] <= addr && addr + size - 1 <= m_region_ends[RegionType_Alias] - 1; } + constexpr bool IsInShadowStackRegion(KProcessAddress addr, size_t size) const { + return this->Contains(addr, size) && m_region_starts[RegionType_ShadowStack] <= addr && addr + size - 1 <= m_region_ends[RegionType_ShadowStack] - 1; + } + + constexpr bool IsSafeUserPointer(KProcessAddress addr, size_t size) const { + return this->Contains(addr, size) && !this->IsInShadowStackRegion(addr, size); + } + bool IsInUnsafeAliasRegion(KProcessAddress addr, size_t size) const { /* Even though Unsafe physical memory is KMemoryState_Normal, it must be mapped inside the alias code region. */ return this->CanContain(addr, size, ams::svc::MemoryState_AliasCode); @@ -490,19 +499,21 @@ namespace ams::kern { public: KProcessAddress GetAddressSpaceStart() const { return m_address_space_start; } - KProcessAddress GetHeapRegionStart() const { return m_region_starts[RegionType_Heap]; } - KProcessAddress GetAliasRegionStart() const { return m_region_starts[RegionType_Alias]; } - KProcessAddress GetStackRegionStart() const { return m_region_starts[RegionType_Stack]; } - KProcessAddress GetKernelMapRegionStart() const { return m_region_starts[RegionType_KernelMap]; } + KProcessAddress GetShadowStackRegionStart() const { return m_region_starts[RegionType_ShadowStack]; } + KProcessAddress GetHeapRegionStart() const { return m_region_starts[RegionType_Heap]; } + KProcessAddress GetAliasRegionStart() const { return m_region_starts[RegionType_Alias]; } + KProcessAddress GetStackRegionStart() const { return m_region_starts[RegionType_Stack]; } + KProcessAddress GetKernelMapRegionStart() const { return m_region_starts[RegionType_KernelMap]; } KProcessAddress GetAliasCodeRegionStart() const { return m_alias_code_region_start; } size_t GetAddressSpaceSize() const { return m_address_space_end - m_address_space_start; } - size_t GetHeapRegionSize() const { return m_region_ends[RegionType_Heap] - m_region_starts[RegionType_Heap]; } - size_t GetAliasRegionSize() const { return m_region_ends[RegionType_Alias] - m_region_starts[RegionType_Alias]; } - size_t GetStackRegionSize() const { return m_region_ends[RegionType_Stack] - m_region_starts[RegionType_Stack]; } - size_t GetKernelMapRegionSize() const { return m_region_ends[RegionType_KernelMap] - m_region_starts[RegionType_KernelMap]; } + size_t GetShadowStackRegionSize() const { return m_region_ends[RegionType_ShadowStack] - m_region_starts[RegionType_ShadowStack]; } + size_t GetHeapRegionSize() const { return m_region_ends[RegionType_Heap] - m_region_starts[RegionType_Heap]; } + size_t GetAliasRegionSize() const { return m_region_ends[RegionType_Alias] - m_region_starts[RegionType_Alias]; } + size_t GetStackRegionSize() const { return m_region_ends[RegionType_Stack] - m_region_starts[RegionType_Stack]; } + size_t GetKernelMapRegionSize() const { return m_region_ends[RegionType_KernelMap] - m_region_starts[RegionType_KernelMap]; } size_t GetAliasCodeRegionSize() const { return m_alias_code_region_end - m_alias_code_region_start; } diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_process.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_process.hpp index 0b0622869..d20e49c7c 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_process.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_process.hpp @@ -215,6 +215,7 @@ namespace ams::kern { } u32 GetAllocateOption() const { return m_page_table.GetAllocateOption(); } + size_t GetAddressSpaceSize() const { return m_page_table.GetAddressSpaceSize(); } ThreadList &GetThreadList() { return m_thread_list; } const ThreadList &GetThreadList() const { return m_thread_list; } diff --git a/libraries/libmesosphere/source/arch/arm64/kern_k_page_table.cpp b/libraries/libmesosphere/source/arch/arm64/kern_k_page_table.cpp index 6992281dd..b22874027 100644 --- a/libraries/libmesosphere/source/arch/arm64/kern_k_page_table.cpp +++ b/libraries/libmesosphere/source/arch/arm64/kern_k_page_table.cpp @@ -125,7 +125,7 @@ namespace ams::kern::arch::arm64 { m_manager = Kernel::GetSystemSystemResource().GetPageTableManagerPointer(); /* Initialize the base page table. */ - KPageTableBase::InitializeForKernel(true, table, start, end); + KPageTableBase::InitializeForKernel(table, start, end); } Result KPageTable::InitializeForProcess(ams::svc::CreateProcessFlag flags, bool from_back, KMemoryManager::Pool pool, KProcessAddress code_address, size_t code_size, KSystemResource *system_resource, KResourceLimit *resource_limit, size_t process_index) { @@ -144,7 +144,7 @@ namespace ams::kern::arch::arm64 { const size_t as_width = GetAddressSpaceWidth(flags); const KProcessAddress as_start = 0; const KProcessAddress as_end = (1ul << as_width); - R_TRY(KPageTableBase::InitializeForProcess(flags, from_back, pool, GetVoidPointer(ttbr0_virt), as_start, as_end, code_address, code_size, system_resource, resource_limit)); + R_TRY(KPageTableBase::InitializeForProcess(flags, from_back, GetVoidPointer(ttbr0_virt), as_start, as_end, pool, code_address, code_size, system_resource, resource_limit)); /* Note that we've updated the table (since we created it). */ this->NoteUpdated(); diff --git a/libraries/libmesosphere/source/init/kern_init_slab_setup.cpp b/libraries/libmesosphere/source/init/kern_init_slab_setup.cpp index b82e78f84..3336c94a9 100644 --- a/libraries/libmesosphere/source/init/kern_init_slab_setup.cpp +++ b/libraries/libmesosphere/source/init/kern_init_slab_setup.cpp @@ -60,25 +60,6 @@ namespace ams::kern::init { #undef DEFINE_SLAB_TYPE_ENUM_MEMBER - /* Constexpr counts. */ - constexpr size_t SlabCountKProcess = 80; - constexpr size_t SlabCountKThread = 800; - constexpr size_t SlabCountKEvent = 900; - constexpr size_t SlabCountKInterruptEvent = 100; - constexpr size_t SlabCountKPort = 384; - constexpr size_t SlabCountKSharedMemory = 80; - constexpr size_t SlabCountKTransferMemory = 200; - constexpr size_t SlabCountKCodeMemory = 10; - constexpr size_t SlabCountKDeviceAddressSpace = 300; - constexpr size_t SlabCountKSession = 1133; - constexpr size_t SlabCountKLightSession = 100; - constexpr size_t SlabCountKObjectName = 7; - constexpr size_t SlabCountKResourceLimit = 5; - constexpr size_t SlabCountKDebug = cpu::NumCores; - constexpr size_t SlabCountKIoPool = 1; - constexpr size_t SlabCountKIoRegion = 6; - constexpr size_t SlabcountKSessionRequestMappings = 40; - constexpr size_t SlabCountExtraKThread = (1024 + 256 + 256) - SlabCountKThread; namespace test { diff --git a/libraries/libmesosphere/source/kern_k_address_space_info.cpp b/libraries/libmesosphere/source/kern_k_address_space_info.cpp index 3aa24c5de..022dc9b54 100644 --- a/libraries/libmesosphere/source/kern_k_address_space_info.cpp +++ b/libraries/libmesosphere/source/kern_k_address_space_info.cpp @@ -30,15 +30,20 @@ namespace ams::kern { { 36, ams::svc::AddressLargeMap36Start, ams::svc::AddressLargeMap36Size, KAddressSpaceInfo::Type_MapLarge, }, { 36, Invalid, ams::svc::AddressMemoryRegionHeap36Size, KAddressSpaceInfo::Type_Heap, }, { 36, Invalid, ams::svc::AddressMemoryRegionAlias36Size, KAddressSpaceInfo::Type_Alias, }, - { 39, ams::svc::AddressMap39Start, ams::svc::AddressMap39Size, KAddressSpaceInfo::Type_Map39Bit, }, + { 39, ams::svc::AddressMap39Start, ams::svc::AddressMap39Size, KAddressSpaceInfo::Type_MapHuge, }, { 39, Invalid, ams::svc::AddressMemoryRegionSmall39Size, KAddressSpaceInfo::Type_MapSmall, }, { 39, Invalid, ams::svc::AddressMemoryRegionHeap39Size, KAddressSpaceInfo::Type_Heap, }, { 39, Invalid, ams::svc::AddressMemoryRegionAlias39Size, KAddressSpaceInfo::Type_Alias, }, { 39, Invalid, ams::svc::AddressMemoryRegionStack39Size, KAddressSpaceInfo::Type_Stack, }, + { 42, ams::svc::AddressMap42Start, ams::svc::AddressMap42Size, KAddressSpaceInfo::Type_MapHuge, }, + { 42, Invalid, ams::svc::AddressMemoryRegionSmall42Size, KAddressSpaceInfo::Type_MapSmall, }, + { 42, Invalid, 0, KAddressSpaceInfo::Type_Heap, }, + { 42, Invalid, ams::svc::AddressMemoryRegionAlias42Size, KAddressSpaceInfo::Type_Alias, }, + { 42, Invalid, ams::svc::AddressMemoryRegionStack42Size, KAddressSpaceInfo::Type_Stack, }, }; - constexpr u8 FlagsToAddressSpaceWidthTable[4] = { - 32, 36, 32, 39 + constexpr u8 FlagsToAddressSpaceWidthTable[5] = { + 32, 36, 32, 39, 42 }; constexpr size_t GetAddressSpaceWidth(ams::svc::CreateProcessFlag flags) { @@ -54,6 +59,7 @@ namespace ams::kern { static_assert(GetAddressSpaceWidth(ams::svc::CreateProcessFlag_AddressSpace64BitDeprecated) == 36); static_assert(GetAddressSpaceWidth(ams::svc::CreateProcessFlag_AddressSpace32BitWithoutAlias) == 32); static_assert(GetAddressSpaceWidth(ams::svc::CreateProcessFlag_AddressSpace64Bit) == 39); + static_assert(GetAddressSpaceWidth(ams::svc::CreateProcessFlag_AddressSpace64Bit64KPage) == 42); KAddressSpaceInfo &GetAddressSpaceInfo(size_t width, KAddressSpaceInfo::Type type) { for (auto &info : AddressSpaceInfos) { diff --git a/libraries/libmesosphere/source/kern_k_initial_process_reader.cpp b/libraries/libmesosphere/source/kern_k_initial_process_reader.cpp index 5d9164efb..61c04dd18 100644 --- a/libraries/libmesosphere/source/kern_k_initial_process_reader.cpp +++ b/libraries/libmesosphere/source/kern_k_initial_process_reader.cpp @@ -233,7 +233,7 @@ namespace ams::kern { /* a number of pages here. Even though this is presumably only used for debug assertions, this is */ /* almost certainly a bug. */ using ASType = KAddressSpaceInfo::Type; - const ASType as_type = this->Is64BitAddressSpace() ? ((GetTargetFirmware() >= TargetFirmware_2_0_0) ? KAddressSpaceInfo::Type_Map39Bit : KAddressSpaceInfo::Type_MapSmall) : KAddressSpaceInfo::Type_MapSmall; + const ASType as_type = this->Is64BitAddressSpace() ? ((GetTargetFirmware() >= TargetFirmware_2_0_0) ? KAddressSpaceInfo::Type_MapHuge : KAddressSpaceInfo::Type_MapSmall) : KAddressSpaceInfo::Type_MapSmall; const uintptr_t map_start = KAddressSpaceInfo::GetAddressSpaceStart(static_cast(out->flags), as_type, out->code_num_pages); const size_t map_size = KAddressSpaceInfo::GetAddressSpaceSize(static_cast(out->flags), as_type); const uintptr_t map_end = map_start + map_size; diff --git a/libraries/libmesosphere/source/kern_k_page_table_base.cpp b/libraries/libmesosphere/source/kern_k_page_table_base.cpp index 5d34dbe1f..98988dde6 100644 --- a/libraries/libmesosphere/source/kern_k_page_table_base.cpp +++ b/libraries/libmesosphere/source/kern_k_page_table_base.cpp @@ -88,14 +88,14 @@ namespace ams::kern { } } - void KPageTableBase::InitializeForKernel(bool is_64_bit, void *table, KVirtualAddress start, KVirtualAddress end) { + void KPageTableBase::InitializeForKernel(void *table, KVirtualAddress start, KVirtualAddress end) { /* Initialize our members. */ - m_address_space_width = (is_64_bit) ? BITSIZEOF(u64) : BITSIZEOF(u32); m_address_space_start = KProcessAddress(GetInteger(start)); m_address_space_end = KProcessAddress(GetInteger(end)); m_is_kernel = true; m_enable_aslr = true; m_enable_device_address_space_merge = false; + m_allowed_exec_device_mapping = false; for (auto i = 0; i < RegionType_Count; ++i) { m_region_starts[i] = 0; @@ -133,7 +133,7 @@ namespace ams::kern { MESOSPHERE_R_ABORT_UNLESS(m_memory_block_manager.Initialize(m_address_space_start, m_address_space_end, m_memory_block_slab_manager)); } - Result KPageTableBase::InitializeForProcess(ams::svc::CreateProcessFlag flags, bool from_back, KMemoryManager::Pool pool, void *table, KProcessAddress start, KProcessAddress end, KProcessAddress code_address, size_t code_size, KSystemResource *system_resource, KResourceLimit *resource_limit) { + Result KPageTableBase::InitializeForProcess(ams::svc::CreateProcessFlag flags, bool from_back, void *table, KProcessAddress start, KProcessAddress end, KMemoryManager::Pool pool, KProcessAddress code_address, size_t code_size, KSystemResource *system_resource, KResourceLimit *resource_limit) { /* Validate the region. */ MESOSPHERE_ABORT_UNLESS(start <= code_address); MESOSPHERE_ABORT_UNLESS(code_address < code_address + code_size); @@ -151,9 +151,9 @@ namespace ams::kern { m_alias_region_extra_size = 0; /* Set our width and heap/alias sizes. */ - m_address_space_width = GetAddressSpaceWidth(flags); - size_t alias_region_size = GetSpaceSize(KAddressSpaceInfo::Type_Alias); - size_t heap_region_size = GetSpaceSize(KAddressSpaceInfo::Type_Heap); + size_t address_space_width = GetAddressSpaceWidth(flags); + size_t alias_region_size = GetSpaceSize(KAddressSpaceInfo::Type_Alias); + size_t heap_region_size = GetSpaceSize(KAddressSpaceInfo::Type_Heap); /* Set code regions and determine remaining sizes. */ KProcessAddress process_code_start; @@ -162,12 +162,12 @@ namespace ams::kern { size_t kernel_map_region_size; KProcessAddress before_process_code_start, after_process_code_start; size_t before_process_code_size, after_process_code_size; - if (m_address_space_width == 39) { + if (address_space_width == 39 || address_space_width == 42) { stack_region_size = GetSpaceSize(KAddressSpaceInfo::Type_Stack); kernel_map_region_size = GetSpaceSize(KAddressSpaceInfo::Type_MapSmall); - m_code_region_start = GetSpaceStart(KAddressSpaceInfo::Type_Map39Bit); - m_code_region_end = m_code_region_start + GetSpaceSize(KAddressSpaceInfo::Type_Map39Bit); + m_code_region_start = GetSpaceStart(KAddressSpaceInfo::Type_MapHuge); + m_code_region_end = m_code_region_start + GetSpaceSize(KAddressSpaceInfo::Type_MapHuge); m_alias_code_region_start = m_code_region_start; m_alias_code_region_end = m_code_region_end; @@ -182,7 +182,7 @@ namespace ams::kern { /* If we have a 39-bit address space and should, enable extra size to the alias region. */ if (flags & ams::svc::CreateProcessFlag_EnableAliasRegionExtraSize) { /* Extra size is 1/8th of the address space. */ - m_alias_region_extra_size = (static_cast(1) << m_address_space_width) / 8; + m_alias_region_extra_size = (static_cast(1) << address_space_width) / 8; alias_region_size += m_alias_region_extra_size; } @@ -208,6 +208,9 @@ namespace ams::kern { after_process_code_size = GetSpaceSize(KAddressSpaceInfo::Type_MapLarge); } + m_region_starts[RegionType_ShadowStack] = Null; + m_region_ends[RegionType_ShadowStack] = Null; + /* Set other basic fields. */ m_enable_aslr = (flags & ams::svc::CreateProcessFlag_EnableAslr) != 0; m_enable_device_address_space_merge = (flags & ams::svc::CreateProcessFlag_DisableDeviceAddressSpaceMerge) == 0; @@ -237,6 +240,9 @@ namespace ams::kern { region_layouts[num_regions++] = { .size = alias_region_size, .type = RegionType_Alias, .alloc_index = 0, }; region_layouts[num_regions++] = { .size = heap_region_size, .type = RegionType_Heap, .alloc_index = 0, }; + if (flags & ams::svc::CreateProcessFlag_EnableShadowStack) { + region_layouts[num_regions++] = { .size = ams::svc::AddressShadowStackRegionSize, .type = RegionType_ShadowStack, .alloc_index = 0, }; + } /* Selection-sort the regions by size largest-to-smallest. */ for (size_t i = 0; i < num_regions - 1; ++i) { @@ -399,6 +405,18 @@ namespace ams::kern { break; } } + + /* Check for overlap with shadow stack. */ + for (size_t ss = 0; ss < num_regions; ++ss) { + if (const auto &shadow_stack_region = region_layouts[ss]; shadow_stack_region.type == RegionType_ShadowStack) { + if (shadow_stack_region.size != 0) { + const KProcessAddress shadow_stack_start = m_region_starts[RegionType_ShadowStack]; + const KProcessAddress shadow_stack_last = m_region_ends[RegionType_ShadowStack] - 1; + MESOSPHERE_ABORT_UNLESS(kmap_last < shadow_stack_start || shadow_stack_last < kmap_start); + } + break; + } + } } } @@ -494,6 +512,25 @@ namespace ams::kern { MESOSPHERE_ABORT_UNLESS(heap_last < process_code_start || process_code_last < heap_start); } } + + /* Check that the ShadowStack region is valid. */ + for (size_t ss = 0; ss < num_regions; ++ss) { + if (const auto &shadow_stack_region = region_layouts[ss]; shadow_stack_region.type == RegionType_ShadowStack) { + /* If there's no shadow stack region, we have nothing to check. */ + if (shadow_stack_region.size == 0) { + break; + } + + /* Check that the shadow stack region is within our address space. */ + MESOSPHERE_ABORT_UNLESS(IsInAddressSpace(m_region_starts[RegionType_ShadowStack])); + MESOSPHERE_ABORT_UNLESS(IsInAddressSpace(m_region_ends[RegionType_ShadowStack])); + + /* Check for overlap with process code. */ + const KProcessAddress shadow_stack_start = m_region_starts[RegionType_ShadowStack]; + const KProcessAddress shadow_stack_last = m_region_ends[RegionType_ShadowStack] - 1; + MESOSPHERE_ABORT_UNLESS(shadow_stack_last < process_code_start || process_code_last < shadow_stack_start); + } + } } /* Set heap and fill members. */ @@ -1997,15 +2034,15 @@ namespace ams::kern { .m_address = GetInteger(m_address_space_end), .m_size = 0 - GetInteger(m_address_space_end), .m_state = static_cast(ams::svc::MemoryState_Inaccessible), - .m_device_disable_merge_left_count = 0, - .m_device_disable_merge_right_count = 0, - .m_ipc_lock_count = 0, - .m_device_use_count = 0, - .m_ipc_disable_merge_count = 0, .m_permission = KMemoryPermission_None, .m_attribute = KMemoryAttribute_None, .m_original_permission = KMemoryPermission_None, + .m_ipc_lock_count = 0, + .m_device_use_count = 0, .m_disable_merge_attribute = KMemoryBlockDisableMergeAttribute_None, + .m_ipc_disable_merge_count = 0, + .m_device_disable_merge_left_count = 0, + .m_device_disable_merge_right_count = 0, }; out_page_info->flags = 0; diff --git a/libraries/libmesosphere/source/svc/kern_svc_info.cpp b/libraries/libmesosphere/source/svc/kern_svc_info.cpp index ec41ef59a..8b51c7fba 100644 --- a/libraries/libmesosphere/source/svc/kern_svc_info.cpp +++ b/libraries/libmesosphere/source/svc/kern_svc_info.cpp @@ -109,6 +109,15 @@ namespace ams::kern::svc { case ams::svc::InfoType_AliasRegionExtraSize: *out = process->GetPageTable().GetAliasRegionExtraSize(); break; + case ams::svc::InfoType_AddressSpaceSize: + *out = process->GetAddressSpaceSize(); + break; + case ams::svc::InfoType_ShadowStackRegionAddress: + *out = GetInteger(process->GetPageTable().GetShadowStackRegionStart()); + break; + case ams::svc::InfoType_ShadowStackRegionSize: + *out = process->GetPageTable().GetShadowStackRegionSize(); + break; MESOSPHERE_UNREACHABLE_DEFAULT_CASE(); } @@ -138,6 +147,9 @@ namespace ams::kern::svc { case ams::svc::InfoType_IsApplication: case ams::svc::InfoType_FreeThreadCount: case ams::svc::InfoType_AliasRegionExtraSize: + case ams::svc::InfoType_AddressSpaceSize: + case ams::svc::InfoType_ShadowStackRegionAddress: + case ams::svc::InfoType_ShadowStackRegionSize: { /* These info types don't support non-zero subtypes. */ R_UNLESS(info_subtype == 0, svc::ResultInvalidCombination()); diff --git a/libraries/libmesosphere/source/svc/kern_svc_process.cpp b/libraries/libmesosphere/source/svc/kern_svc_process.cpp index 6e516a51f..54f598d1e 100644 --- a/libraries/libmesosphere/source/svc/kern_svc_process.cpp +++ b/libraries/libmesosphere/source/svc/kern_svc_process.cpp @@ -100,6 +100,9 @@ namespace ams::kern::svc { /* Validate that the parameter flags are valid. */ R_UNLESS((params.flags & ~ams::svc::CreateProcessFlag_All) == 0, svc::ResultInvalidEnumValue()); + /* The 64KB page size is not yet allowed. */ + R_UNLESS((params.flags & ams::svc::CreateProcessFlag_AddressSpaceMask) != ams::svc::CreateProcessFlag_AddressSpace64Bit64KPage, svc::ResultInvalidCombination()); + /* Validate that 64-bit process is okay. */ const bool is_64_bit = (params.flags & ams::svc::CreateProcessFlag_Is64Bit) != 0; if constexpr (sizeof(void *) < sizeof(u64)) { @@ -130,12 +133,13 @@ namespace ams::kern::svc { } break; case ams::svc::CreateProcessFlag_AddressSpace64Bit: + case ams::svc::CreateProcessFlag_AddressSpace64Bit64KPage: { /* 64-bit address space requires 64-bit process. */ R_UNLESS(is_64_bit, svc::ResultInvalidCombination()); - map_start = KAddressSpaceInfo::GetAddressSpaceStart(static_cast(params.flags), KAddressSpaceInfo::Type_Map39Bit, code_size); - map_end = map_start + KAddressSpaceInfo::GetAddressSpaceSize(static_cast(params.flags), KAddressSpaceInfo::Type_Map39Bit); + map_start = KAddressSpaceInfo::GetAddressSpaceStart(static_cast(params.flags), KAddressSpaceInfo::Type_MapHuge, code_size); + map_end = map_start + KAddressSpaceInfo::GetAddressSpaceSize(static_cast(params.flags), KAddressSpaceInfo::Type_MapHuge); map_size = KAddressSpaceInfo::GetAddressSpaceSize(static_cast(params.flags), KAddressSpaceInfo::Type_Heap); } diff --git a/libraries/libstratosphere/include/stratosphere/cfg/cfg_types.hpp b/libraries/libstratosphere/include/stratosphere/cfg/cfg_types.hpp index dd898a96f..20976587c 100644 --- a/libraries/libstratosphere/include/stratosphere/cfg/cfg_types.hpp +++ b/libraries/libstratosphere/include/stratosphere/cfg/cfg_types.hpp @@ -35,6 +35,7 @@ namespace ams::cfg { OverrideStatusFlag_AddressSpace64BitDeprecated = (svc::CreateProcessFlag_AddressSpace64BitDeprecated >> svc::CreateProcessFlag_AddressSpaceShift) << OverrideStatusFlag_AddressSpaceShift, OverrideStatusFlag_AddressSpace32BitWithoutAlias = (svc::CreateProcessFlag_AddressSpace32BitWithoutAlias >> svc::CreateProcessFlag_AddressSpaceShift) << OverrideStatusFlag_AddressSpaceShift, OverrideStatusFlag_AddressSpace64Bit = (svc::CreateProcessFlag_AddressSpace64Bit >> svc::CreateProcessFlag_AddressSpaceShift) << OverrideStatusFlag_AddressSpaceShift, + OverrideStatusFlag_AddressSpace64Bit64KPage = (svc::CreateProcessFlag_AddressSpace64Bit64KPage >> svc::CreateProcessFlag_AddressSpaceShift) << OverrideStatusFlag_AddressSpaceShift, #endif }; diff --git a/libraries/libstratosphere/include/stratosphere/ldr/ldr_types.hpp b/libraries/libstratosphere/include/stratosphere/ldr/ldr_types.hpp index aa33b4e15..c97711a53 100644 --- a/libraries/libstratosphere/include/stratosphere/ldr/ldr_types.hpp +++ b/libraries/libstratosphere/include/stratosphere/ldr/ldr_types.hpp @@ -235,11 +235,16 @@ namespace ams::ldr { MetaFlag_PreventCodeReads = (1 << 7), }; + enum MetaFlag2 { + MetaFlag2_EnableShadowStack = (1 << 0), + }; + enum AddressSpaceType { AddressSpaceType_32Bit = 0, AddressSpaceType_64BitDeprecated = 1, AddressSpaceType_32BitWithoutAlias = 2, AddressSpaceType_64Bit = 3, + AddressSpaceType_64Bit64KPage = 4, }; #if defined(ATMOSPHERE_OS_HORIZON) @@ -247,13 +252,14 @@ namespace ams::ldr { static_assert(AddressSpaceType_64BitDeprecated == (svc::CreateProcessFlag_AddressSpace64BitDeprecated >> svc::CreateProcessFlag_AddressSpaceShift)); static_assert(AddressSpaceType_32BitWithoutAlias == (svc::CreateProcessFlag_AddressSpace32BitWithoutAlias >> svc::CreateProcessFlag_AddressSpaceShift)); static_assert(AddressSpaceType_64Bit == (svc::CreateProcessFlag_AddressSpace64Bit >> svc::CreateProcessFlag_AddressSpaceShift)); + static_assert(AddressSpaceType_64Bit64KPage == (svc::CreateProcessFlag_AddressSpace64Bit64KPage >> svc::CreateProcessFlag_AddressSpaceShift)); #endif u32 magic; u32 signature_key_generation; u8 reserved_08[4]; u8 flags; - u8 reserved_0D; + u8 flags2; u8 main_thread_priority; u8 default_cpu_id; u8 reserved_10[4]; diff --git a/libraries/libstratosphere/source/cfg/cfg_override.board.nintendo_nx.inc b/libraries/libstratosphere/source/cfg/cfg_override.board.nintendo_nx.inc index a91da9268..420f71198 100644 --- a/libraries/libstratosphere/source/cfg/cfg_override.board.nintendo_nx.inc +++ b/libraries/libstratosphere/source/cfg/cfg_override.board.nintendo_nx.inc @@ -153,6 +153,8 @@ namespace ams::cfg { impl::OverrideStatusFlag ParseOverrideAddressSpace(const char *value) { if (strcasecmp(value, "39_bit") == 0 || strcasecmp(value, "39") == 0) { return impl::OverrideStatusFlag_AddressSpace64Bit; + } else if (strcasecmp(value, "42_bit") == 0 || strcasecmp(value, "42") == 0) { + return impl::OverrideStatusFlag_AddressSpace64Bit64KPage; } else if (strcasecmp(value, "36_bit") == 0 || strcasecmp(value, "36") == 0) { return impl::OverrideStatusFlag_AddressSpace64BitDeprecated; } else if (strcasecmp(value, "32_bit") == 0 || strcasecmp(value, "32") == 0) { diff --git a/libraries/libstratosphere/source/osdbg/impl/osdbg_thread_info.os.horizon.hpp b/libraries/libstratosphere/source/osdbg/impl/osdbg_thread_info.os.horizon.hpp index e43fec1e1..1bd74bfba 100644 --- a/libraries/libstratosphere/source/osdbg/impl/osdbg_thread_info.os.horizon.hpp +++ b/libraries/libstratosphere/source/osdbg/impl/osdbg_thread_info.os.horizon.hpp @@ -28,7 +28,9 @@ namespace ams::osdbg::impl { constexpr inline bool IsLp64(const ThreadInfo *info) { const auto as = info->_debug_info_create_process.flags & svc::CreateProcessFlag_AddressSpaceMask; - return as == svc::CreateProcessFlag_AddressSpace64Bit || as == svc::CreateProcessFlag_AddressSpace64BitDeprecated; + return as == svc::CreateProcessFlag_AddressSpace64Bit + || as == svc::CreateProcessFlag_AddressSpace64BitDeprecated + || as == svc::CreateProcessFlag_AddressSpace64Bit64KPage; } constexpr inline bool Is64BitArch(const ThreadInfo *info) { diff --git a/libraries/libvapours/include/vapours/svc/svc_memory_map.hpp b/libraries/libvapours/include/vapours/svc/svc_memory_map.hpp index 08bf1773b..55bb5ec36 100644 --- a/libraries/libvapours/include/vapours/svc/svc_memory_map.hpp +++ b/libraries/libvapours/include/vapours/svc/svc_memory_map.hpp @@ -37,6 +37,13 @@ namespace ams::svc { constexpr inline size_t AddressMemoryRegion39Size = 512_GB; + constexpr inline size_t AddressMemoryRegionSmall42Size = 64_GB; + constexpr inline size_t AddressMemoryRegionAlias42Size = 512_GB; + constexpr inline size_t AddressMemoryRegionStack42Size = 2_GB; + + constexpr inline size_t AddressMemoryRegion42Size = 4096_GB; + + constexpr inline size_t AddressShadowStackRegionSize = 4_GB; #elif defined(ATMOSPHERE_ARCH_ARM) constexpr inline size_t AddressMemoryRegionSmall32Size = 512_MB; @@ -56,6 +63,12 @@ namespace ams::svc { constexpr inline size_t AddressMemoryRegion39Size = 0; + constexpr inline size_t AddressMemoryRegionSmall42Size = 0; + constexpr inline size_t AddressMemoryRegionAlias42Size = 0; + constexpr inline size_t AddressMemoryRegionStack42Size = 0; + + constexpr inline size_t AddressMemoryRegion42Size = 0; + #else #error "Unknown architecture for svc::AddressMemoryRegion*Size" @@ -97,4 +110,7 @@ namespace ams::svc { constexpr inline uintptr_t AddressMap39End = AddressMemoryRegion39Size; constexpr inline size_t AddressMap39Size = AddressMap39End - AddressMap39Start; + constexpr inline uintptr_t AddressMap42Start = 0 + AddressNullGuard64Size; + constexpr inline uintptr_t AddressMap42End = AddressMemoryRegion42Size; + constexpr inline size_t AddressMap42Size = AddressMap42End - AddressMap42Start; } diff --git a/libraries/libvapours/include/vapours/svc/svc_types_common.hpp b/libraries/libvapours/include/vapours/svc/svc_types_common.hpp index 21ab685d0..20aa4ea90 100644 --- a/libraries/libvapours/include/vapours/svc/svc_types_common.hpp +++ b/libraries/libvapours/include/vapours/svc/svc_types_common.hpp @@ -191,8 +191,16 @@ namespace ams::svc { InfoType_IsSvcPermitted = 26, InfoType_IoRegionHint = 27, InfoType_AliasRegionExtraSize = 28, - /* ... */ + InfoType_RemoteRegionAddress = 29, + InfoType_RemoteRegionSize = 30, + InfoType_RemoteMemorySize = 31, + InfoType_RemoteMemoryUsageMax = 32, + InfoType_AllocateAlignment = 33, InfoType_TransferMemoryHint = 34, + /* ... */ + InfoType_AddressSpaceSize = 36, + InfoType_ShadowStackRegionAddress = 37, + InfoType_ShadowStackRegionSize = 38, InfoType_MesosphereMeta = 65000, InfoType_MesosphereCurrentProcess = 65001, @@ -408,11 +416,12 @@ namespace ams::svc { /* What kind of address space? */ CreateProcessFlag_AddressSpaceShift = 1, - CreateProcessFlag_AddressSpaceMask = (7 << CreateProcessFlag_AddressSpaceShift), + CreateProcessFlag_AddressSpaceMask = (7 << CreateProcessFlag_AddressSpaceShift), /* Should be 15 but Nintendo didn't make 64K isn't usable yet */ CreateProcessFlag_AddressSpace32Bit = (0 << CreateProcessFlag_AddressSpaceShift), CreateProcessFlag_AddressSpace64BitDeprecated = (1 << CreateProcessFlag_AddressSpaceShift), CreateProcessFlag_AddressSpace32BitWithoutAlias = (2 << CreateProcessFlag_AddressSpaceShift), CreateProcessFlag_AddressSpace64Bit = (3 << CreateProcessFlag_AddressSpaceShift), + CreateProcessFlag_AddressSpace64Bit64KPage = (4 << CreateProcessFlag_AddressSpaceShift), /* Should JIT debug be done on crash? */ CreateProcessFlag_EnableDebug = (1 << 4), @@ -443,6 +452,9 @@ namespace ams::svc { /* 18.x EnableAliasRegionExtraSize. */ CreateProcessFlag_EnableAliasRegionExtraSize = (1 << 13), + /* 23.x EnableShadowStack. */ + CreateProcessFlag_EnableShadowStack = (1 << 17), + /* Mask of all flags. */ CreateProcessFlag_All = CreateProcessFlag_Is64Bit | CreateProcessFlag_AddressSpaceMask | @@ -452,7 +464,8 @@ namespace ams::svc { CreateProcessFlag_PoolPartitionMask | CreateProcessFlag_OptimizeMemoryAllocation | CreateProcessFlag_DisableDeviceAddressSpaceMerge | - CreateProcessFlag_EnableAliasRegionExtraSize, + CreateProcessFlag_EnableAliasRegionExtraSize | + CreateProcessFlag_EnableShadowStack, }; /* Debug types. */ diff --git a/libraries/libvapours/include/vapours/svc/svc_version.hpp b/libraries/libvapours/include/vapours/svc/svc_version.hpp index 500da0e21..e8c2b3ae8 100644 --- a/libraries/libvapours/include/vapours/svc/svc_version.hpp +++ b/libraries/libvapours/include/vapours/svc/svc_version.hpp @@ -57,7 +57,7 @@ namespace ams::svc { /* This is the highest SVC version supported by Atmosphere, to be updated on new kernel releases. */ /* NOTE: Official kernel versions have SVC major = SDK major + 4, SVC minor = SDK minor. */ - constexpr inline u32 SupportedKernelMajorVersion = ConvertToSvcMajorVersion(22); + constexpr inline u32 SupportedKernelMajorVersion = ConvertToSvcMajorVersion(23); constexpr inline u32 SupportedKernelMinorVersion = ConvertToSvcMinorVersion( 2); constexpr inline u32 SupportedKernelVersion = EncodeKernelVersion(SupportedKernelMajorVersion, SupportedKernelMinorVersion); diff --git a/mesosphere/kernel/source/arch/arm64/init/kern_init_core.cpp b/mesosphere/kernel/source/arch/arm64/init/kern_init_core.cpp index 10a000c6d..415b5bca2 100644 --- a/mesosphere/kernel/source/arch/arm64/init/kern_init_core.cpp +++ b/mesosphere/kernel/source/arch/arm64/init/kern_init_core.cpp @@ -224,15 +224,20 @@ namespace ams::kern::init { static_assert(kern::arch::arm64::init::IsInitialPageAllocator); void SetupAllTtbr0Entries(KInitialPageTable &init_pt, KInitialPageAllocator &allocator) { - /* Validate that the ttbr0 array is in rodata. */ + /* Validate that the ttbr0/tcr_el1 arrays are in rodata. */ const uintptr_t rodata_start = reinterpret_cast(__rodata_start); const uintptr_t rodata_end = reinterpret_cast(__rodata_end); MESOSPHERE_INIT_ABORT_UNLESS(rodata_start < rodata_end); MESOSPHERE_INIT_ABORT_UNLESS(rodata_start <= reinterpret_cast(std::addressof(KPageTable::GetTtbr0Entry(0)))); - MESOSPHERE_INIT_ABORT_UNLESS(reinterpret_cast(std::addressof(KPageTable::GetTtbr0Entry(KPageTable::NumTtbr0Entries))) < rodata_end); + MESOSPHERE_INIT_ABORT_UNLESS(reinterpret_cast(std::addressof(KPageTable::GetTtbr0Entry(KPageTable::NumPTEntries))) < rodata_end); + MESOSPHERE_INIT_ABORT_UNLESS(rodata_start <= reinterpret_cast(std::addressof(KPageTable::GetTcrEL1Entry(0)))); + MESOSPHERE_INIT_ABORT_UNLESS(reinterpret_cast(std::addressof(KPageTable::GetTcrEL1Entry(KPageTable::NumPTEntries))) < rodata_end); + + /* Get the default tcr_el1 value, with T0SZ set for a 39-bit address space. */ + const u64 tcr_el1 = (cpu::GetTcrEl1() & ~UINT64_C(0x3F)) | UINT64_C(64 - 39); /* Allocate pages for all ttbr0 entries. */ - for (size_t i = 0; i < KPageTable::NumTtbr0Entries; ++i) { + for (size_t i = 0; i < KPageTable::NumPTEntries; ++i) { /* Allocate a page. */ KPhysicalAddress page = allocator.Allocate(PageSize); MESOSPHERE_INIT_ABORT_UNLESS(page != Null); @@ -245,6 +250,12 @@ namespace ams::kern::init { /* Set the entry to the newly allocated page. */ *reinterpret_cast(GetInteger(ttbr0_phys_ptr)) = (static_cast(i) << 48) | GetInteger(page); + + /* Get the physical address of the tcr_el1 entry. */ + const auto tcr_el1_phys_ptr = init_pt.GetPhysicalAddress(KVirtualAddress(std::addressof(KPageTable::GetTcrEL1Entry(i)))); + + /* Set the entry to the default tcr_el1 value. */ + *reinterpret_cast(GetInteger(tcr_el1_phys_ptr)) = tcr_el1; } } diff --git a/stratosphere/loader/source/ldr_meta.cpp b/stratosphere/loader/source/ldr_meta.cpp index d6b6d7852..f7da96292 100644 --- a/stratosphere/loader/source/ldr_meta.cpp +++ b/stratosphere/loader/source/ldr_meta.cpp @@ -270,6 +270,7 @@ namespace ams::ldr { case cfg::impl::OverrideStatusFlag_AddressSpace64BitDeprecated: meta->npdm->flags |= (Npdm::AddressSpaceType_64BitDeprecated) << Npdm::MetaFlag_AddressSpaceTypeShift; break; case cfg::impl::OverrideStatusFlag_AddressSpace32BitWithoutAlias: meta->npdm->flags |= (Npdm::AddressSpaceType_32BitWithoutAlias) << Npdm::MetaFlag_AddressSpaceTypeShift; break; case cfg::impl::OverrideStatusFlag_AddressSpace64Bit: meta->npdm->flags |= (Npdm::AddressSpaceType_64Bit) << Npdm::MetaFlag_AddressSpaceTypeShift; break; + case cfg::impl::OverrideStatusFlag_AddressSpace64Bit64KPage: meta->npdm->flags |= (Npdm::AddressSpaceType_64Bit64KPage) << Npdm::MetaFlag_AddressSpaceTypeShift; break; AMS_UNREACHABLE_DEFAULT_CASE(); } } diff --git a/stratosphere/loader/source/ldr_process_creation.cpp b/stratosphere/loader/source/ldr_process_creation.cpp index bea773f44..d05450541 100644 --- a/stratosphere/loader/source/ldr_process_creation.cpp +++ b/stratosphere/loader/source/ldr_process_creation.cpp @@ -423,6 +423,9 @@ namespace ams::ldr { case Npdm::AddressSpaceType_64Bit: flags |= svc::CreateProcessFlag_AddressSpace64Bit; break; + case Npdm::AddressSpaceType_64Bit64KPage: + flags |= svc::CreateProcessFlag_AddressSpace64Bit64KPage; + break; default: R_THROW(ldr::ResultInvalidMeta()); } @@ -597,6 +600,10 @@ namespace ams::ldr { aslr_start = svc::AddressMap39Start; aslr_size = svc::AddressMap39Size; break; + case svc::CreateProcessFlag_AddressSpace64Bit64KPage: + aslr_start = svc::AddressMap42Start; + aslr_size = svc::AddressMap42Size; + break; AMS_UNREACHABLE_DEFAULT_CASE(); } } else { From 289ba7104e988d4e9feeb29a40b233a21440b94d Mon Sep 17 00:00:00 2001 From: Alula Date: Tue, 15 Sep 2026 16:57:27 +0200 Subject: [PATCH 2/5] kern: add new unknown DebugThreadParam --- libraries/libmesosphere/include/mesosphere/kern_k_thread.hpp | 4 ++++ libraries/libmesosphere/source/kern_k_process.cpp | 3 +++ libraries/libmesosphere/source/svc/kern_svc_debug.cpp | 5 +++++ 3 files changed, 12 insertions(+) diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_thread.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_thread.hpp index 8904a6a92..7e294473c 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_thread.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_thread.hpp @@ -341,6 +341,7 @@ namespace ams::kern { bool m_debug_attached; s8 m_priority_inheritance_count; bool m_resource_limit_release_hint; + bool m_debug_unknown5; public: constexpr explicit KThread(util::ConstantInitializeTag) : KAutoObjectWithSlabHeapAndContainer(util::ConstantInitialize), KTimerTask(util::ConstantInitialize), @@ -683,6 +684,9 @@ namespace ams::kern { constexpr void SetDebugAttached() { m_debug_attached = true; } constexpr bool IsAttachedToDebugger() const { return m_debug_attached; } + constexpr void SetDebugUnknown5(bool value) { m_debug_unknown5 = value; } + constexpr bool IsDebugUnknown5() const { return m_debug_unknown5; } + void AddCpuTime(s32 core_id, s64 amount) { m_cpu_time += amount; /* TODO: Debug kernels track per-core tick counts. Should we? */ diff --git a/libraries/libmesosphere/source/kern_k_process.cpp b/libraries/libmesosphere/source/kern_k_process.cpp index 91048f4f6..7d1b0d0f4 100644 --- a/libraries/libmesosphere/source/kern_k_process.cpp +++ b/libraries/libmesosphere/source/kern_k_process.cpp @@ -970,6 +970,9 @@ namespace ams::kern { /* Initialize the thread. */ R_TRY(KThread::InitializeUserThread(main_thread, reinterpret_cast(GetVoidPointer(this->GetEntryPoint())), 0, stack_top, priority, m_ideal_core_id, this)); + /* TODO: what is this? */ + main_thread->SetDebugUnknown5(true); + /* Register the thread, and commit our reservation. */ KThread::Register(main_thread); thread_reservation.Commit(); diff --git a/libraries/libmesosphere/source/svc/kern_svc_debug.cpp b/libraries/libmesosphere/source/svc/kern_svc_debug.cpp index 986654ce4..635b91cbe 100644 --- a/libraries/libmesosphere/source/svc/kern_svc_debug.cpp +++ b/libraries/libmesosphere/source/svc/kern_svc_debug.cpp @@ -429,6 +429,11 @@ namespace ams::kern::svc { *out_32 = affinity_mask; } break; + case ams::svc::DebugThreadParam_Unknown5: + { + *out_32 = thread->IsDebugUnknown5(); + } + break; default: R_THROW(ams::svc::ResultInvalidEnumValue()); } From 7e58f5fbae70971d5f84df61122ef3983345288f Mon Sep 17 00:00:00 2001 From: Alula Date: Tue, 15 Sep 2026 17:03:11 +0200 Subject: [PATCH 3/5] kern: finish shadow stack region, 64k page process segregation implementation, fix some long-standing issues --- .../arch/arm64/kern_k_page_table.hpp | 1 + .../arch/arm64/kern_k_process_page_table.hpp | 9 + .../arm64/kern_userspace_memory_access.hpp | 2 +- .../mesosphere/kern_k_page_table_base.hpp | 10 +- .../source/kern_k_page_table_base.cpp | 247 +++++------------- .../source/kern_k_system_control_base.cpp | 7 + .../source/svc/kern_svc_process.cpp | 38 ++- .../include/vapours/svc/svc_types_common.hpp | 4 + .../source/arch/arm64/init/kern_init_core.cpp | 2 +- 9 files changed, 132 insertions(+), 188 deletions(-) diff --git a/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_page_table.hpp b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_page_table.hpp index 356dc4217..9fd7dbd2f 100644 --- a/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_page_table.hpp +++ b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_page_table.hpp @@ -19,6 +19,7 @@ #include #include #include +#include namespace ams::kern::arch::arm64 { diff --git a/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_process_page_table.hpp b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_process_page_table.hpp index 63a357e0e..e80311a47 100644 --- a/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_process_page_table.hpp +++ b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_process_page_table.hpp @@ -32,6 +32,11 @@ namespace ams::kern::arch::arm64 { R_RETURN(m_page_table.InitializeForProcess(flags, from_back, pool, code_address, code_size, system_resource, resource_limit, process_index)); } + static ALWAYS_INLINE u64 GetProcessTcrEl1(size_t process_index) { + /* The kernel's root table is entry zero; processes are indexed from one. */ + return KPageTable::GetTcrEL1Entry(process_index + 1); + } + void Finalize() { m_page_table.Finalize(); } ALWAYS_INLINE KScopedLightLock AcquireDeviceMapLock() { @@ -302,6 +307,10 @@ namespace ams::kern::arch::arm64 { bool CanContain(KProcessAddress addr, size_t size, KMemoryState state) const { return m_page_table.CanContain(addr, size, state); } bool CanContain(KProcessAddress addr, size_t size, ams::svc::MemoryState state) const { return m_page_table.CanContain(addr, size, state); } + bool IsInShadowStackRegion(KProcessAddress addr, size_t size) const { return m_page_table.IsInShadowStackRegion(addr, size); } + bool IsInShadowStackRegion(KProcessAddress addr) const { return m_page_table.IsInShadowStackRegion(addr); } + bool IsSafeUserPointer(KProcessAddress addr, size_t size) const { return m_page_table.IsSafeUserPointer(addr, size); } + KProcessAddress GetAddressSpaceStart() const { return m_page_table.GetAddressSpaceStart(); } KProcessAddress GetShadowStackRegionStart() const { return m_page_table.GetShadowStackRegionStart(); } KProcessAddress GetHeapRegionStart() const { return m_page_table.GetHeapRegionStart(); } diff --git a/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_userspace_memory_access.hpp b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_userspace_memory_access.hpp index fc075178b..28580e038 100644 --- a/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_userspace_memory_access.hpp +++ b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_userspace_memory_access.hpp @@ -77,7 +77,7 @@ namespace ams::kern::arch::arm64 { static bool CopyMemoryFromUserSize32BitWithSupervisorAccess(void *dst, const void *src) { /* Check that the address is within the valid userspace range. */ - if (const uintptr_t src_uptr = reinterpret_cast(src); src_uptr < ams::svc::AddressNullGuard32Size || (src_uptr + sizeof(u32) - 1) >= ams::svc::AddressMemoryRegion39Size) { + if (const uintptr_t src_uptr = reinterpret_cast(src); src_uptr < ams::svc::AddressNullGuard32Size || (src_uptr + sizeof(u32) - 1) >= ams::svc::AddressMemoryRegion42Size) { return false; } diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_page_table_base.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_page_table_base.hpp index 759fd1758..c0139ab79 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_page_table_base.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_page_table_base.hpp @@ -249,7 +249,15 @@ namespace ams::kern { } constexpr bool IsInShadowStackRegion(KProcessAddress addr, size_t size) const { - return this->Contains(addr, size) && m_region_starts[RegionType_ShadowStack] <= addr && addr + size - 1 <= m_region_ends[RegionType_ShadowStack] - 1; + const auto start = m_region_starts[RegionType_ShadowStack]; + const auto end = m_region_ends[RegionType_ShadowStack]; + return start != end && addr < end && start < addr + size; + } + + constexpr bool IsInShadowStackRegion(KProcessAddress addr) const { + const auto start = m_region_starts[RegionType_ShadowStack]; + const auto end = m_region_ends[RegionType_ShadowStack]; + return start <= addr && addr < end; } constexpr bool IsSafeUserPointer(KProcessAddress addr, size_t size) const { diff --git a/libraries/libmesosphere/source/kern_k_page_table_base.cpp b/libraries/libmesosphere/source/kern_k_page_table_base.cpp index 98988dde6..652583fd4 100644 --- a/libraries/libmesosphere/source/kern_k_page_table_base.cpp +++ b/libraries/libmesosphere/source/kern_k_page_table_base.cpp @@ -353,182 +353,36 @@ namespace ams::kern { const KProcessAddress process_code_last = process_code_end - 1; auto IsInAddressSpace = [&](KProcessAddress addr) ALWAYS_INLINE_LAMBDA { return m_address_space_start <= addr && addr <= m_address_space_end; }; - /* Ensure that the KernelMap region is valid. */ - for (size_t k = 0; k < num_regions; ++k) { - if (const auto &kmap_region = region_layouts[k]; kmap_region.type == RegionType_KernelMap) { - /* If there's no kmap region, we have nothing to check. */ - if (kmap_region.size == 0) { - break; - } - - /* Check that the kmap region is within our address space. */ - MESOSPHERE_ABORT_UNLESS(IsInAddressSpace(m_region_starts[RegionType_KernelMap])); - MESOSPHERE_ABORT_UNLESS(IsInAddressSpace(m_region_ends[RegionType_KernelMap])); - - /* Check for overlap with process code. */ - const KProcessAddress kmap_start = m_region_starts[RegionType_KernelMap]; - const KProcessAddress kmap_last = m_region_ends[RegionType_KernelMap] - 1; - MESOSPHERE_ABORT_UNLESS(kernel_map_region_size == 0 || kmap_last < process_code_start || process_code_last < kmap_start); - - /* Check for overlap with stack. */ - for (size_t s = 0; s < num_regions; ++s) { - if (const auto &stack_region = region_layouts[s]; stack_region.type == RegionType_Stack) { - if (stack_region.size != 0) { - const KProcessAddress stack_start = m_region_starts[RegionType_Stack]; - const KProcessAddress stack_last = m_region_ends[RegionType_Stack] - 1; - MESOSPHERE_ABORT_UNLESS((kernel_map_region_size == 0 && stack_region_size == 0) || kmap_last < stack_start || stack_last < kmap_start); - } - break; - } - } - - /* Check for overlap with alias. */ - for (size_t a = 0; a < num_regions; ++a) { - if (const auto &alias_region = region_layouts[a]; alias_region.type == RegionType_Alias) { - if (alias_region.size != 0) { - const KProcessAddress alias_start = m_region_starts[RegionType_Alias]; - const KProcessAddress alias_last = m_region_ends[RegionType_Alias] - 1; - MESOSPHERE_ABORT_UNLESS(kmap_last < alias_start || alias_last < kmap_start); - } - break; - } - } - - /* Check for overlap with heap. */ - for (size_t h = 0; h < num_regions; ++h) { - if (const auto &heap_region = region_layouts[h]; heap_region.type == RegionType_Heap) { - if (heap_region.size != 0) { - const KProcessAddress heap_start = m_region_starts[RegionType_Heap]; - const KProcessAddress heap_last = m_region_ends[RegionType_Heap] - 1; - MESOSPHERE_ABORT_UNLESS(kmap_last < heap_start || heap_last < kmap_start); - } - break; - } - } - - /* Check for overlap with shadow stack. */ - for (size_t ss = 0; ss < num_regions; ++ss) { - if (const auto &shadow_stack_region = region_layouts[ss]; shadow_stack_region.type == RegionType_ShadowStack) { - if (shadow_stack_region.size != 0) { - const KProcessAddress shadow_stack_start = m_region_starts[RegionType_ShadowStack]; - const KProcessAddress shadow_stack_last = m_region_ends[RegionType_ShadowStack] - 1; - MESOSPHERE_ABORT_UNLESS(kmap_last < shadow_stack_start || shadow_stack_last < kmap_start); - } - break; - } - } - } + /* Map each region type to its layout entry. */ + const RegionLayoutInfo *region_layouts_by_type[RegionType_Count] = {}; + for (size_t i = 0; i < num_regions; ++i) { + region_layouts_by_type[region_layouts[i].type] = std::addressof(region_layouts[i]); } - /* Check that the Stack region is valid. */ - for (size_t s = 0; s < num_regions; ++s) { - if (const auto &stack_region = region_layouts[s]; stack_region.type == RegionType_Stack) { - /* If there's no stack region, we have nothing to check. */ - if (stack_region.size == 0) { - break; - } - - /* Check that the stack region is within our address space. */ - MESOSPHERE_ABORT_UNLESS(IsInAddressSpace(m_region_starts[RegionType_Stack])); - MESOSPHERE_ABORT_UNLESS(IsInAddressSpace(m_region_ends[RegionType_Stack])); - - /* Check for overlap with process code. */ - const KProcessAddress stack_start = m_region_starts[RegionType_Stack]; - const KProcessAddress stack_last = m_region_ends[RegionType_Stack] - 1; - MESOSPHERE_ABORT_UNLESS(stack_region_size == 0 || stack_last < process_code_start || process_code_last < stack_start); - - /* Check for overlap with alias. */ - for (size_t a = 0; a < num_regions; ++a) { - if (const auto &alias_region = region_layouts[a]; alias_region.type == RegionType_Alias) { - if (alias_region.size != 0) { - const KProcessAddress alias_start = m_region_starts[RegionType_Alias]; - const KProcessAddress alias_last = m_region_ends[RegionType_Alias] - 1; - MESOSPHERE_ABORT_UNLESS(stack_last < alias_start || alias_last < stack_start); - } - break; - } - } - - /* Check for overlap with heap. */ - for (size_t h = 0; h < num_regions; ++h) { - if (const auto &heap_region = region_layouts[h]; heap_region.type == RegionType_Heap) { - if (heap_region.size != 0) { - const KProcessAddress heap_start = m_region_starts[RegionType_Heap]; - const KProcessAddress heap_last = m_region_ends[RegionType_Heap] - 1; - MESOSPHERE_ABORT_UNLESS(stack_last < heap_start || heap_last < stack_start); - } - break; - } - } + /* Validate each region. */ + for (size_t i = 0; i < RegionType_Count; ++i) { + /* If the region isn't present, there's nothing to check. */ + const RegionLayoutInfo * const region = region_layouts_by_type[i]; + if (region == nullptr || region->size == 0) { + continue; } - } - /* Check that the Alias region is valid. */ - for (size_t a = 0; a < num_regions; ++a) { - if (const auto &alias_region = region_layouts[a]; alias_region.type == RegionType_Alias) { - /* If there's no alias region, we have nothing to check. */ - if (alias_region.size == 0) { - break; + /* Check that the region is within our address space. */ + MESOSPHERE_ABORT_UNLESS(IsInAddressSpace(m_region_starts[i])); + MESOSPHERE_ABORT_UNLESS(IsInAddressSpace(m_region_ends[i])); + + /* Check for overlap with process code. */ + MESOSPHERE_ABORT_UNLESS(m_region_ends[i] - 1 < process_code_start || process_code_last < m_region_starts[i]); + + /* Check for overlap with every later region. */ + for (size_t j = i; j < RegionType_ShadowStack; ++j) { + /* If the other region isn't present, there's nothing to check. */ + const RegionLayoutInfo * const other = region_layouts_by_type[j + 1]; + if (other == nullptr || other->size == 0) { + continue; } - /* Check that the alias region is within our address space. */ - MESOSPHERE_ABORT_UNLESS(IsInAddressSpace(m_region_starts[RegionType_Alias])); - MESOSPHERE_ABORT_UNLESS(IsInAddressSpace(m_region_ends[RegionType_Alias])); - - /* Check for overlap with process code. */ - const KProcessAddress alias_start = m_region_starts[RegionType_Alias]; - const KProcessAddress alias_last = m_region_ends[RegionType_Alias] - 1; - MESOSPHERE_ABORT_UNLESS(alias_last < process_code_start || process_code_last < alias_start); - - /* Check for overlap with heap. */ - for (size_t h = 0; h < num_regions; ++h) { - if (const auto &heap_region = region_layouts[h]; heap_region.type == RegionType_Heap) { - if (heap_region.size != 0) { - const KProcessAddress heap_start = m_region_starts[RegionType_Heap]; - const KProcessAddress heap_last = m_region_ends[RegionType_Heap] - 1; - MESOSPHERE_ABORT_UNLESS(alias_last < heap_start || heap_last < alias_start); - } - break; - } - } - } - } - - /* Check that the Heap region is valid. */ - for (size_t h = 0; h < num_regions; ++h) { - if (const auto &heap_region = region_layouts[h]; heap_region.type == RegionType_Heap) { - /* If there's no heap region, we have nothing to check. */ - if (heap_region.size == 0) { - break; - } - - /* Check that the heap region is within our address space. */ - MESOSPHERE_ABORT_UNLESS(IsInAddressSpace(m_region_starts[RegionType_Heap])); - MESOSPHERE_ABORT_UNLESS(IsInAddressSpace(m_region_ends[RegionType_Heap])); - - /* Check for overlap with process code. */ - const KProcessAddress heap_start = m_region_starts[RegionType_Heap]; - const KProcessAddress heap_last = m_region_ends[RegionType_Heap] - 1; - MESOSPHERE_ABORT_UNLESS(heap_last < process_code_start || process_code_last < heap_start); - } - } - - /* Check that the ShadowStack region is valid. */ - for (size_t ss = 0; ss < num_regions; ++ss) { - if (const auto &shadow_stack_region = region_layouts[ss]; shadow_stack_region.type == RegionType_ShadowStack) { - /* If there's no shadow stack region, we have nothing to check. */ - if (shadow_stack_region.size == 0) { - break; - } - - /* Check that the shadow stack region is within our address space. */ - MESOSPHERE_ABORT_UNLESS(IsInAddressSpace(m_region_starts[RegionType_ShadowStack])); - MESOSPHERE_ABORT_UNLESS(IsInAddressSpace(m_region_ends[RegionType_ShadowStack])); - - /* Check for overlap with process code. */ - const KProcessAddress shadow_stack_start = m_region_starts[RegionType_ShadowStack]; - const KProcessAddress shadow_stack_last = m_region_ends[RegionType_ShadowStack] - 1; - MESOSPHERE_ABORT_UNLESS(shadow_stack_last < process_code_start || process_code_last < shadow_stack_start); + MESOSPHERE_ABORT_UNLESS(m_region_ends[i] - 1 < m_region_starts[j + 1] || m_region_ends[j + 1] - 1 < m_region_starts[i]); } } } @@ -598,6 +452,8 @@ namespace ams::kern { case ams::svc::MemoryState_Static: case ams::svc::MemoryState_ThreadLocal: return m_region_starts[RegionType_KernelMap]; + case ams::svc::MemoryState_ShadowStack: + return m_region_starts[RegionType_ShadowStack]; case ams::svc::MemoryState_Io: case ams::svc::MemoryState_Shared: case ams::svc::MemoryState_AliasCode: @@ -633,6 +489,8 @@ namespace ams::kern { case ams::svc::MemoryState_Static: case ams::svc::MemoryState_ThreadLocal: return m_region_ends[RegionType_KernelMap] - m_region_starts[RegionType_KernelMap]; + case ams::svc::MemoryState_ShadowStack: + return m_region_ends[RegionType_ShadowStack] - m_region_starts[RegionType_ShadowStack]; case ams::svc::MemoryState_Io: case ams::svc::MemoryState_Shared: case ams::svc::MemoryState_AliasCode: @@ -659,12 +517,20 @@ namespace ams::kern { const KProcessAddress region_start = this->GetRegionAddress(state); const size_t region_size = this->GetRegionSize(state); + if (region_size == 0) { + return false; + } + const bool is_in_region = region_start <= addr && addr < end && last <= region_start + region_size - 1; - const bool is_in_heap = !(end <= m_region_starts[RegionType_Heap] || m_region_ends[RegionType_Heap] <= addr || m_region_starts[RegionType_Heap] == m_region_ends[RegionType_Heap]); - const bool is_in_alias = !(end <= m_region_starts[RegionType_Alias] || m_region_ends[RegionType_Alias] <= addr || m_region_starts[RegionType_Alias] == m_region_ends[RegionType_Alias]); + switch (state) { case ams::svc::MemoryState_Free: + case ams::svc::MemoryState_Normal: + case ams::svc::MemoryState_Ipc: + case ams::svc::MemoryState_NonSecureIpc: + case ams::svc::MemoryState_NonDeviceIpc: case ams::svc::MemoryState_Kernel: + case ams::svc::MemoryState_ShadowStack: return is_in_region; case ams::svc::MemoryState_Io: case ams::svc::MemoryState_Static: @@ -682,17 +548,32 @@ namespace ams::kern { case ams::svc::MemoryState_CodeOut: case ams::svc::MemoryState_Coverage: case ams::svc::MemoryState_Insecure: - return is_in_region && !is_in_heap && !is_in_alias; - case ams::svc::MemoryState_Normal: - MESOSPHERE_ASSERT(is_in_heap); - return is_in_region && !is_in_alias; - case ams::svc::MemoryState_Ipc: - case ams::svc::MemoryState_NonSecureIpc: - case ams::svc::MemoryState_NonDeviceIpc: - MESOSPHERE_ASSERT(is_in_alias); - return is_in_region && !is_in_heap; - default: - return false; + { + if (!is_in_region) { + return false; + } + + const auto heap_start = m_region_starts[RegionType_Heap]; + const auto heap_end = m_region_ends[RegionType_Heap]; + if (heap_start != heap_end && addr < heap_end && heap_start < end) { + return false; + } + + const auto alias_start = m_region_starts[RegionType_Alias]; + const auto alias_end = m_region_ends[RegionType_Alias]; + if (alias_start != alias_end && addr < alias_end && alias_start < end) { + return false; + } + + const auto shadow_start = m_region_starts[RegionType_ShadowStack]; + const auto shadow_end = m_region_ends[RegionType_ShadowStack]; + if (shadow_start != shadow_end && addr < shadow_end && shadow_start < end) { + return false; + } + + return true; + } + MESOSPHERE_UNREACHABLE_DEFAULT_CASE(); } } diff --git a/libraries/libmesosphere/source/kern_k_system_control_base.cpp b/libraries/libmesosphere/source/kern_k_system_control_base.cpp index dece074ef..38c507486 100644 --- a/libraries/libmesosphere/source/kern_k_system_control_base.cpp +++ b/libraries/libmesosphere/source/kern_k_system_control_base.cpp @@ -170,6 +170,13 @@ namespace ams::kern { KAddressSpaceInfo::SetAddressSpaceSize(39, KAddressSpaceInfo::Type_Alias, alias_size); } + /* Update 42-bit address space infos. */ + { + /* Heap should be equal to the total memory size, maximum 128 GB. */ + /* Alias/Stack/MapSmall are left at their static defaults. */ + KAddressSpaceInfo::SetAddressSpaceSize(42, KAddressSpaceInfo::Type_Heap, std::min(util::AlignUp(total_memory_size, 1_GB), 128_GB)); + } + const auto &slab_counts = init::GetSlabResourceCounts(); MESOSPHERE_R_ABORT_UNLESS(sys_res_limit.SetLimitValue(ams::svc::LimitableResource_PhysicalMemoryMax, total_memory_size)); MESOSPHERE_R_ABORT_UNLESS(sys_res_limit.SetLimitValue(ams::svc::LimitableResource_ThreadCountMax, slab_counts.num_KThread)); diff --git a/libraries/libmesosphere/source/svc/kern_svc_process.cpp b/libraries/libmesosphere/source/svc/kern_svc_process.cpp index 54f598d1e..375386562 100644 --- a/libraries/libmesosphere/source/svc/kern_svc_process.cpp +++ b/libraries/libmesosphere/source/svc/kern_svc_process.cpp @@ -86,6 +86,40 @@ namespace ams::kern::svc { R_RETURN(KProcess::GetProcessList(out_num_processes, out_process_ids, max_out_count)); } + constexpr size_t GetProcessSlotT0Sz(ams::svc::CreateProcessFlag flags) { + if ((flags & ams::svc::CreateProcessFlag_AddressSpaceMask) == ams::svc::CreateProcessFlag_AddressSpace64Bit64KPage) { + return (64 - 42); + } else { + return (64 - 39); + } + } + + KProcess *CreateProcessForAddressSpace(ams::svc::CreateProcessFlag flags) { + /* Find a process slab slot whose root page table is meant for the requested address space. */ + const size_t desired_t0sz = GetProcessSlotT0Sz(flags); + + KProcess *process = nullptr; + KProcess *rejected[init::SlabCountKProcess]; + size_t num_rejected = 0; + while ((process = KProcess::Create()) != nullptr) { + /* Stop once we find a slot whose T0SZ matches. */ + if ((KProcessPageTable::GetProcessTcrEl1(process->GetSlabIndex()) & 0x3F) == desired_t0sz) { + break; + } + + /* Otherwise, park the process and try the next slot. */ + rejected[num_rejected++] = process; + process = nullptr; + } + + /* Release every process we parked while searching. */ + for (size_t i = 0; i < num_rejected; ++i) { + rejected[i]->Close(); + } + + return process; + } + Result CreateProcess(ams::svc::Handle *out, const ams::svc::CreateProcessParameter ¶ms, KUserPointer user_caps, int32_t num_caps) { /* Validate the capabilities pointer. */ R_UNLESS(num_caps >= 0, svc::ResultInvalidPointer()); @@ -219,8 +253,8 @@ namespace ams::kern::svc { /* Get the current handle table. */ auto &handle_table = GetCurrentProcess().GetHandleTable(); - /* Create the new process. */ - KProcess *process = KProcess::Create(); + /* Create the new process, ensuring its page table slot matches the requested address space. */ + KProcess *process = CreateProcessForAddressSpace(static_cast(params.flags)); R_UNLESS(process != nullptr, svc::ResultOutOfResource()); /* Ensure that the only reference to the process is in the handle table when we're done. */ diff --git a/libraries/libvapours/include/vapours/svc/svc_types_common.hpp b/libraries/libvapours/include/vapours/svc/svc_types_common.hpp index 20aa4ea90..66f5a5648 100644 --- a/libraries/libvapours/include/vapours/svc/svc_types_common.hpp +++ b/libraries/libvapours/include/vapours/svc/svc_types_common.hpp @@ -96,6 +96,9 @@ namespace ams::svc { MemoryState_CodeOut = 0x15, MemoryState_Coverage = 0x16, MemoryState_Insecure = 0x17, + MemoryState_Remote = 0x18, + MemoryState_Protected = 0x19, + MemoryState_ShadowStack = 0x1A, }; enum MemoryPermission : u32 { @@ -483,6 +486,7 @@ namespace ams::svc { DebugThreadParam_IdealCore = 2, DebugThreadParam_CurrentCore = 3, DebugThreadParam_AffinityMask = 4, + DebugThreadParam_Unknown5 = 5, }; enum DebugException : u32 { diff --git a/mesosphere/kernel/source/arch/arm64/init/kern_init_core.cpp b/mesosphere/kernel/source/arch/arm64/init/kern_init_core.cpp index 415b5bca2..e37780b7e 100644 --- a/mesosphere/kernel/source/arch/arm64/init/kern_init_core.cpp +++ b/mesosphere/kernel/source/arch/arm64/init/kern_init_core.cpp @@ -234,7 +234,7 @@ namespace ams::kern::init { MESOSPHERE_INIT_ABORT_UNLESS(reinterpret_cast(std::addressof(KPageTable::GetTcrEL1Entry(KPageTable::NumPTEntries))) < rodata_end); /* Get the default tcr_el1 value, with T0SZ set for a 39-bit address space. */ - const u64 tcr_el1 = (cpu::GetTcrEl1() & ~UINT64_C(0x3F)) | UINT64_C(64 - 39); + const u64 tcr_el1 = (cpu::GetTcrEl1() & ~UINT64_C(0x3F)) | (64 - 39); /* Allocate pages for all ttbr0 entries. */ for (size_t i = 0; i < KPageTable::NumPTEntries; ++i) { From dbfe192b2faf5de748b63f60fa1eaa7d2a6c953d Mon Sep 17 00:00:00 2001 From: Alula Date: Tue, 15 Sep 2026 17:04:18 +0200 Subject: [PATCH 4/5] kern: reject shadow stack accesses in syscalls --- .../libmesosphere/source/kern_k_debug_base.cpp | 8 ++++---- .../source/kern_k_page_table_base.cpp | 4 ++-- .../source/svc/kern_svc_address_arbiter.cpp | 10 ++++++---- .../libmesosphere/source/svc/kern_svc_cache.cpp | 2 +- .../source/svc/kern_svc_condition_variable.cpp | 8 +++++--- .../libmesosphere/source/svc/kern_svc_debug.cpp | 10 ++++++++++ .../source/svc/kern_svc_debug_string.cpp | 2 +- .../libmesosphere/source/svc/kern_svc_ipc.cpp | 2 +- .../libmesosphere/source/svc/kern_svc_lock.cpp | 10 ++++++---- .../libmesosphere/source/svc/kern_svc_port.cpp | 17 ++++++++++++++--- .../source/svc/kern_svc_process.cpp | 4 ++-- .../source/svc/kern_svc_process_memory.cpp | 4 ++-- .../source/svc/kern_svc_query_memory.cpp | 2 ++ .../source/svc/kern_svc_synchronization.cpp | 2 +- .../source/svc/kern_svc_thread.cpp | 4 +++- 15 files changed, 60 insertions(+), 29 deletions(-) diff --git a/libraries/libmesosphere/source/kern_k_debug_base.cpp b/libraries/libmesosphere/source/kern_k_debug_base.cpp index 453eb745c..40ff0ce3f 100644 --- a/libraries/libmesosphere/source/kern_k_debug_base.cpp +++ b/libraries/libmesosphere/source/kern_k_debug_base.cpp @@ -100,8 +100,8 @@ namespace ams::kern { KProcessPageTable &target_pt = process->GetPageTable(); /* Verify that the regions are in range. */ - R_UNLESS(target_pt.Contains(address, size), svc::ResultInvalidCurrentMemory()); - R_UNLESS(debugger_pt.Contains(buffer, size), svc::ResultInvalidCurrentMemory()); + R_UNLESS(target_pt.Contains(address, size), svc::ResultInvalidCurrentMemory()); + R_UNLESS(debugger_pt.IsSafeUserPointer(buffer, size), svc::ResultInvalidCurrentMemory()); /* Iterate over the target process's memory blocks. */ KProcessAddress cur_address = address; @@ -166,8 +166,8 @@ namespace ams::kern { KProcessPageTable &target_pt = process->GetPageTable(); /* Verify that the regions are in range. */ - R_UNLESS(target_pt.Contains(address, size), svc::ResultInvalidCurrentMemory()); - R_UNLESS(debugger_pt.Contains(buffer, size), svc::ResultInvalidCurrentMemory()); + R_UNLESS(target_pt.Contains(address, size), svc::ResultInvalidCurrentMemory()); + R_UNLESS(debugger_pt.IsSafeUserPointer(buffer, size), svc::ResultInvalidCurrentMemory()); /* Iterate over the target process's memory blocks. */ KProcessAddress cur_address = address; diff --git a/libraries/libmesosphere/source/kern_k_page_table_base.cpp b/libraries/libmesosphere/source/kern_k_page_table_base.cpp index 652583fd4..5b40e20e0 100644 --- a/libraries/libmesosphere/source/kern_k_page_table_base.cpp +++ b/libraries/libmesosphere/source/kern_k_page_table_base.cpp @@ -3205,7 +3205,7 @@ namespace ams::kern { Result KPageTableBase::CopyMemoryFromLinearToUser(KProcessAddress dst_addr, size_t size, KProcessAddress src_addr, u32 src_state_mask, u32 src_state, KMemoryPermission src_test_perm, u32 src_attr_mask, u32 src_attr) { /* Lightly validate the range before doing anything else. */ - R_UNLESS(this->Contains(src_addr, size), svc::ResultInvalidCurrentMemory()); + R_UNLESS(this->IsSafeUserPointer(src_addr, size), svc::ResultInvalidCurrentMemory()); /* Copy the memory. */ { @@ -3354,7 +3354,7 @@ namespace ams::kern { Result KPageTableBase::CopyMemoryFromUserToLinear(KProcessAddress dst_addr, size_t size, u32 dst_state_mask, u32 dst_state, KMemoryPermission dst_test_perm, u32 dst_attr_mask, u32 dst_attr, KProcessAddress src_addr) { /* Lightly validate the range before doing anything else. */ - R_UNLESS(this->Contains(dst_addr, size), svc::ResultInvalidCurrentMemory()); + R_UNLESS(this->IsSafeUserPointer(dst_addr, size), svc::ResultInvalidCurrentMemory()); /* Copy the memory. */ { diff --git a/libraries/libmesosphere/source/svc/kern_svc_address_arbiter.cpp b/libraries/libmesosphere/source/svc/kern_svc_address_arbiter.cpp index 2b495ad45..939c29107 100644 --- a/libraries/libmesosphere/source/svc/kern_svc_address_arbiter.cpp +++ b/libraries/libmesosphere/source/svc/kern_svc_address_arbiter.cpp @@ -21,8 +21,10 @@ namespace ams::kern::svc { namespace { - constexpr bool IsKernelAddress(uintptr_t address) { - return KernelVirtualAddressSpaceBase <= address && address < KernelVirtualAddressSpaceEnd; + constexpr bool IsValidAddress(uintptr_t address) { + if (KernelVirtualAddressSpaceBase <= address && address < KernelVirtualAddressSpaceEnd) return false; + if (GetCurrentProcess().GetPageTable().IsInShadowStackRegion(address)) return false; + return true; } constexpr bool IsValidSignalType(ams::svc::SignalType type) { @@ -50,7 +52,7 @@ namespace ams::kern::svc { Result WaitForAddress(uintptr_t address, ams::svc::ArbitrationType arb_type, int64_t value, int64_t timeout_ns) { /* Validate input. */ - R_UNLESS(AMS_LIKELY(!IsKernelAddress(address)), svc::ResultInvalidCurrentMemory()); + R_UNLESS(AMS_LIKELY(IsValidAddress(address)), svc::ResultInvalidCurrentMemory()); if (arb_type == ams::svc::ArbitrationType_WaitIfEqual64) { R_UNLESS(util::IsAligned(address, sizeof(int64_t)), svc::ResultInvalidAddress()); } else { @@ -79,7 +81,7 @@ namespace ams::kern::svc { Result SignalToAddress(uintptr_t address, ams::svc::SignalType signal_type, int32_t value, int32_t count) { /* Validate input. */ - R_UNLESS(AMS_LIKELY(!IsKernelAddress(address)), svc::ResultInvalidCurrentMemory()); + R_UNLESS(AMS_LIKELY(IsValidAddress(address)), svc::ResultInvalidCurrentMemory()); R_UNLESS(util::IsAligned(address, sizeof(int32_t)), svc::ResultInvalidAddress()); R_UNLESS(IsValidSignalType(signal_type), svc::ResultInvalidEnumValue()); diff --git a/libraries/libmesosphere/source/svc/kern_svc_cache.cpp b/libraries/libmesosphere/source/svc/kern_svc_cache.cpp index 00f84781f..895959f9a 100644 --- a/libraries/libmesosphere/source/svc/kern_svc_cache.cpp +++ b/libraries/libmesosphere/source/svc/kern_svc_cache.cpp @@ -83,7 +83,7 @@ namespace ams::kern::svc { R_SUCCEED_IF(size == 0); /* Validate that the region is within range. */ - R_UNLESS(GetCurrentProcess().GetPageTable().Contains(address, size), svc::ResultInvalidCurrentMemory()); + R_UNLESS(GetCurrentProcess().GetPageTable().IsSafeUserPointer(address, size), svc::ResultInvalidCurrentMemory()); /* did N intend ResultInvalidPointer like everywhere else? */ /* Flush the cache. */ R_TRY(cpu::FlushDataCache(reinterpret_cast(address), size)); diff --git a/libraries/libmesosphere/source/svc/kern_svc_condition_variable.cpp b/libraries/libmesosphere/source/svc/kern_svc_condition_variable.cpp index 2d3a031ef..aebe88443 100644 --- a/libraries/libmesosphere/source/svc/kern_svc_condition_variable.cpp +++ b/libraries/libmesosphere/source/svc/kern_svc_condition_variable.cpp @@ -21,13 +21,15 @@ namespace ams::kern::svc { namespace { - constexpr bool IsKernelAddress(uintptr_t address) { - return KernelVirtualAddressSpaceBase <= address && address < KernelVirtualAddressSpaceEnd; + constexpr bool IsValidAddress(uintptr_t address) { + if (KernelVirtualAddressSpaceBase <= address && address < KernelVirtualAddressSpaceEnd) return false; + if (GetCurrentProcess().GetPageTable().IsInShadowStackRegion(address)) return false; + return true; } Result WaitProcessWideKeyAtomic(uintptr_t address, uintptr_t cv_key, uint32_t tag, int64_t timeout_ns) { /* Validate input. */ - R_UNLESS(AMS_LIKELY(!IsKernelAddress(address)), svc::ResultInvalidCurrentMemory()); + R_UNLESS(AMS_LIKELY(IsValidAddress(address)), svc::ResultInvalidPointer()); R_UNLESS(util::IsAligned(address, sizeof(int32_t)), svc::ResultInvalidAddress()); /* Convert timeout from nanoseconds to ticks. */ diff --git a/libraries/libmesosphere/source/svc/kern_svc_debug.cpp b/libraries/libmesosphere/source/svc/kern_svc_debug.cpp index 635b91cbe..39db3775b 100644 --- a/libraries/libmesosphere/source/svc/kern_svc_debug.cpp +++ b/libraries/libmesosphere/source/svc/kern_svc_debug.cpp @@ -97,6 +97,8 @@ namespace ams::kern::svc { /* Only allow invoking the svc on development hardware or if force debug prod. */ R_UNLESS(KTargetSystem::IsDebugMode() || GetCurrentProcess().CanForceDebugProd(), svc::ResultNotImplemented()); + R_UNLESS(GetCurrentProcess().GetPageTable().IsSafeUserPointer(KProcessAddress(out_info.GetUnsafePointer()), sizeof(EventInfoType)), svc::ResultInvalidPointer()); + /* Get the debug object. */ KScopedAutoObject debug = GetCurrentProcess().GetHandleTable().GetObject(debug_handle); R_UNLESS(debug.IsNotNull(), svc::ResultInvalidHandle()); @@ -139,6 +141,8 @@ namespace ams::kern::svc { /* Verify that the number of thread ids is valid. */ R_UNLESS((0 <= num_thread_ids && num_thread_ids <= MaximumDebuggableThreadCount), svc::ResultOutOfRange()); + R_UNLESS(GetCurrentProcess().GetPageTable().IsSafeUserPointer(KProcessAddress(user_thread_ids.GetUnsafePointer()), num_thread_ids * sizeof(uint64_t)), svc::ResultInvalidPointer()); + /* Copy the threads from userspace. */ uint64_t thread_ids[MaximumDebuggableThreadCount]; if (num_thread_ids > 0) { @@ -172,6 +176,8 @@ namespace ams::kern::svc { /* Only allow invoking the svc on development hardware or if force debug prod. */ R_UNLESS(KTargetSystem::IsDebugMode() || GetCurrentProcess().CanForceDebugProd(), svc::ResultNotImplemented()); + R_UNLESS(GetCurrentProcess().GetPageTable().IsSafeUserPointer(KProcessAddress(out_context.GetUnsafePointer()), sizeof(ams::svc::ThreadContext)), svc::ResultInvalidPointer()); + /* Validate the context flags. */ R_UNLESS((context_flags | ams::svc::ThreadContextFlag_All) == ams::svc::ThreadContextFlag_All, svc::ResultInvalidEnumValue()); @@ -193,6 +199,8 @@ namespace ams::kern::svc { /* Only allow invoking the svc on development hardware. */ R_UNLESS(KTargetSystem::IsDebugMode(), svc::ResultNotImplemented()); + R_UNLESS(GetCurrentProcess().GetPageTable().IsSafeUserPointer(KProcessAddress(user_context.GetUnsafePointer()), sizeof(ams::svc::ThreadContext)), svc::ResultInvalidPointer()); + /* Validate the context flags. */ #if defined(MESOSPHERE_ENABLE_HARDWARE_SINGLE_STEP) { @@ -243,6 +251,8 @@ namespace ams::kern::svc { template Result QueryDebugProcessMemory(KUserPointer out_memory_info, ams::svc::PageInfo *out_page_info, ams::svc::Handle debug_handle, uint64_t address) { + R_UNLESS(GetCurrentProcess().GetPageTable().IsSafeUserPointer(KProcessAddress(out_memory_info.GetUnsafePointer()), sizeof(T)), svc::ResultInvalidPointer()); + /* Get an ams::svc::MemoryInfo for the region. */ ams::svc::MemoryInfo info = {}; R_TRY(QueryDebugProcessMemory(std::addressof(info), out_page_info, debug_handle, address)); diff --git a/libraries/libmesosphere/source/svc/kern_svc_debug_string.cpp b/libraries/libmesosphere/source/svc/kern_svc_debug_string.cpp index c36c93ffe..5f15e77f4 100644 --- a/libraries/libmesosphere/source/svc/kern_svc_debug_string.cpp +++ b/libraries/libmesosphere/source/svc/kern_svc_debug_string.cpp @@ -26,7 +26,7 @@ namespace ams::kern::svc { R_SUCCEED_IF(len == 0); /* Ensure that the data being output is in range. */ - R_UNLESS(GetCurrentProcess().GetPageTable().Contains(KProcessAddress(debug_str.GetUnsafePointer()), len), svc::ResultInvalidCurrentMemory()); + R_UNLESS(GetCurrentProcess().GetPageTable().IsSafeUserPointer(KProcessAddress(debug_str.GetUnsafePointer()), len), svc::ResultInvalidPointer()); /* Output the string. */ R_RETURN(KDebugLog::PrintUserString(debug_str, len)); diff --git a/libraries/libmesosphere/source/svc/kern_svc_ipc.cpp b/libraries/libmesosphere/source/svc/kern_svc_ipc.cpp index e2013a1b3..603db823c 100644 --- a/libraries/libmesosphere/source/svc/kern_svc_ipc.cpp +++ b/libraries/libmesosphere/source/svc/kern_svc_ipc.cpp @@ -110,7 +110,7 @@ namespace ams::kern::svc { /* Copy user handles. */ if (num_handles > 0) { /* Ensure that we can try to get the handles. */ - R_UNLESS(GetCurrentProcess().GetPageTable().Contains(KProcessAddress(user_handles.GetUnsafePointer()), num_handles * sizeof(ams::svc::Handle)), svc::ResultInvalidPointer()); + R_UNLESS(GetCurrentProcess().GetPageTable().IsSafeUserPointer(KProcessAddress(user_handles.GetUnsafePointer()), num_handles * sizeof(ams::svc::Handle)), svc::ResultInvalidPointer()); /* Get the handles. */ R_TRY(user_handles.CopyArrayTo(handles, num_handles)); diff --git a/libraries/libmesosphere/source/svc/kern_svc_lock.cpp b/libraries/libmesosphere/source/svc/kern_svc_lock.cpp index be19bc0ed..9ada8d0fc 100644 --- a/libraries/libmesosphere/source/svc/kern_svc_lock.cpp +++ b/libraries/libmesosphere/source/svc/kern_svc_lock.cpp @@ -21,13 +21,15 @@ namespace ams::kern::svc { namespace { - constexpr bool IsKernelAddress(uintptr_t address) { - return KernelVirtualAddressSpaceBase <= address && address < KernelVirtualAddressSpaceEnd; + constexpr bool IsValidAddress(uintptr_t address) { + if (KernelVirtualAddressSpaceBase <= address && address < KernelVirtualAddressSpaceEnd) return false; + if (GetCurrentProcess().GetPageTable().IsInShadowStackRegion(address)) return false; + return true; } Result ArbitrateLock(ams::svc::Handle thread_handle, uintptr_t address, uint32_t tag) { /* Validate the input address. */ - R_UNLESS(!IsKernelAddress(address), svc::ResultInvalidCurrentMemory()); + R_UNLESS(IsValidAddress(address), svc::ResultInvalidCurrentMemory()); R_UNLESS(util::IsAligned(address, sizeof(u32)), svc::ResultInvalidAddress()); R_RETURN(KConditionVariable::WaitForAddress(thread_handle, address, tag)); @@ -35,7 +37,7 @@ namespace ams::kern::svc { Result ArbitrateUnlock(uintptr_t address) { /* Validate the input address. */ - R_UNLESS(!IsKernelAddress(address), svc::ResultInvalidCurrentMemory()); + R_UNLESS(IsValidAddress(address), svc::ResultInvalidCurrentMemory()); R_UNLESS(util::IsAligned(address, sizeof(u32)), svc::ResultInvalidAddress()); R_RETURN(KConditionVariable::SignalToAddress(address)); diff --git a/libraries/libmesosphere/source/svc/kern_svc_port.cpp b/libraries/libmesosphere/source/svc/kern_svc_port.cpp index 1ac5803d2..cfc13a3a8 100644 --- a/libraries/libmesosphere/source/svc/kern_svc_port.cpp +++ b/libraries/libmesosphere/source/svc/kern_svc_port.cpp @@ -21,11 +21,22 @@ namespace ams::kern::svc { namespace { + static Result GetPortName(char (&name)[KObjectName::NameLengthMax], KUserPointer user_name) { + /* Copy the provided name from user memory to kernel memory. */ + R_TRY(user_name.CopyStringTo(name, sizeof(name))); + + /* Oddly enough N here first copies then validates if it's not in forbidden range. */ + const auto name_len = util::Strnlen(name, sizeof(name)); + R_UNLESS(GetCurrentProcess().GetPageTable().IsSafeUserPointer(KProcessAddress(user_name.GetUnsafePointer()), name_len + 1), svc::ResultInvalidPointer()); + + R_SUCCEED(); + } + Result ManageNamedPort(ams::svc::Handle *out_server_handle, KUserPointer user_name, s32 max_sessions) { /* Copy the provided name from user memory to kernel memory. */ char name[KObjectName::NameLengthMax] = {}; - R_TRY(user_name.CopyStringTo(name, sizeof(name))); - + R_TRY(GetPortName(name, user_name)); + /* Validate that sessions and name are valid. */ R_UNLESS(max_sessions >= 0, svc::ResultOutOfRange()); R_UNLESS(name[sizeof(name) - 1] == '\x00', svc::ResultOutOfRange()); @@ -106,7 +117,7 @@ namespace ams::kern::svc { Result ConnectToNamedPort(ams::svc::Handle *out, KUserPointer user_name) { /* Copy the provided name from user memory to kernel memory. */ char name[KObjectName::NameLengthMax] = {}; - R_TRY(user_name.CopyStringTo(name, sizeof(name))); + R_TRY(GetPortName(name, user_name)); /* Validate that name is valid. */ R_UNLESS(name[sizeof(name) - 1] == '\x00', svc::ResultOutOfRange()); diff --git a/libraries/libmesosphere/source/svc/kern_svc_process.cpp b/libraries/libmesosphere/source/svc/kern_svc_process.cpp index 375386562..c570c40d6 100644 --- a/libraries/libmesosphere/source/svc/kern_svc_process.cpp +++ b/libraries/libmesosphere/source/svc/kern_svc_process.cpp @@ -79,7 +79,7 @@ namespace ams::kern::svc { /* Validate that the pointer is in range. */ if (max_out_count > 0) { - R_UNLESS(GetCurrentProcess().GetPageTable().Contains(KProcessAddress(out_process_ids.GetUnsafePointer()), max_out_count * sizeof(u64)), svc::ResultInvalidCurrentMemory()); + R_UNLESS(GetCurrentProcess().GetPageTable().IsSafeUserPointer(KProcessAddress(out_process_ids.GetUnsafePointer()), max_out_count * sizeof(u64)), svc::ResultInvalidPointer()); } /* Get the process list. */ @@ -128,7 +128,7 @@ namespace ams::kern::svc { R_UNLESS(((num_caps * sizeof(u32)) / sizeof(u32)) == static_cast(num_caps), svc::ResultInvalidPointer()); /* Validate that the pointer is in range. */ - R_UNLESS(GetCurrentProcess().GetPageTable().Contains(KProcessAddress(user_caps.GetUnsafePointer()), num_caps * sizeof(u32)), svc::ResultInvalidPointer()); + R_UNLESS(GetCurrentProcess().GetPageTable().IsSafeUserPointer(KProcessAddress(user_caps.GetUnsafePointer()), num_caps * sizeof(u32)), svc::ResultInvalidPointer()); } /* Validate that the parameter flags are valid. */ diff --git a/libraries/libmesosphere/source/svc/kern_svc_process_memory.cpp b/libraries/libmesosphere/source/svc/kern_svc_process_memory.cpp index 41420ca06..56978b1cd 100644 --- a/libraries/libmesosphere/source/svc/kern_svc_process_memory.cpp +++ b/libraries/libmesosphere/source/svc/kern_svc_process_memory.cpp @@ -148,7 +148,7 @@ namespace ams::kern::svc { /* Validate that the mapping is in range. */ auto &page_table = process->GetPageTable(); R_UNLESS(page_table.Contains(src_address, size), svc::ResultInvalidCurrentMemory()); - R_UNLESS(page_table.CanContain(dst_address, size, KMemoryState_AliasCode), svc::ResultInvalidCurrentMemory()); + R_UNLESS(page_table.CanContain(dst_address, size, KMemoryState_AliasCode), svc::ResultInvalidMemoryRegion()); /* Map the memory. */ R_TRY(page_table.MapCodeMemory(dst_address, src_address, size)); @@ -175,7 +175,7 @@ namespace ams::kern::svc { /* Validate that the mapping is in range. */ auto &page_table = process->GetPageTable(); R_UNLESS(page_table.Contains(src_address, size), svc::ResultInvalidCurrentMemory()); - R_UNLESS(page_table.CanContain(dst_address, size, KMemoryState_AliasCode), svc::ResultInvalidCurrentMemory()); + R_UNLESS(page_table.CanContain(dst_address, size, KMemoryState_AliasCode), svc::ResultInvalidMemoryRegion()); /* Unmap the memory. */ R_TRY(page_table.UnmapCodeMemory(dst_address, src_address, size)); diff --git a/libraries/libmesosphere/source/svc/kern_svc_query_memory.cpp b/libraries/libmesosphere/source/svc/kern_svc_query_memory.cpp index 555130743..d93e3310f 100644 --- a/libraries/libmesosphere/source/svc/kern_svc_query_memory.cpp +++ b/libraries/libmesosphere/source/svc/kern_svc_query_memory.cpp @@ -37,6 +37,8 @@ namespace ams::kern::svc { template Result QueryProcessMemory(KUserPointer out_memory_info, ams::svc::PageInfo *out_page_info, ams::svc::Handle process_handle, uint64_t address) { + R_UNLESS(GetCurrentProcess().GetPageTable().IsSafeUserPointer(KProcessAddress(out_memory_info.GetUnsafePointer()), sizeof(T)), svc::ResultInvalidPointer()); + /* Get an ams::svc::MemoryInfo for the region. */ ams::svc::MemoryInfo info = {}; R_TRY(QueryProcessMemory(std::addressof(info), out_page_info, process_handle, address)); diff --git a/libraries/libmesosphere/source/svc/kern_svc_synchronization.cpp b/libraries/libmesosphere/source/svc/kern_svc_synchronization.cpp index 20e025bb5..ae23f50bd 100644 --- a/libraries/libmesosphere/source/svc/kern_svc_synchronization.cpp +++ b/libraries/libmesosphere/source/svc/kern_svc_synchronization.cpp @@ -82,7 +82,7 @@ namespace ams::kern::svc { /* Copy user handles. */ if (num_handles > 0) { /* Ensure that we can try to get the handles. */ - R_UNLESS(GetCurrentProcess().GetPageTable().Contains(KProcessAddress(user_handles.GetUnsafePointer()), num_handles * sizeof(ams::svc::Handle)), svc::ResultInvalidPointer()); + R_UNLESS(GetCurrentProcess().GetPageTable().IsSafeUserPointer(KProcessAddress(user_handles.GetUnsafePointer()), num_handles * sizeof(ams::svc::Handle)), svc::ResultInvalidPointer()); /* Get the handles. */ R_TRY(user_handles.CopyArrayTo(handles, num_handles)); diff --git a/libraries/libmesosphere/source/svc/kern_svc_thread.cpp b/libraries/libmesosphere/source/svc/kern_svc_thread.cpp index 14af1bb11..d0c3dc012 100644 --- a/libraries/libmesosphere/source/svc/kern_svc_thread.cpp +++ b/libraries/libmesosphere/source/svc/kern_svc_thread.cpp @@ -204,6 +204,8 @@ namespace ams::kern::svc { /* Get the thread from its handle. */ KScopedAutoObject thread = GetCurrentProcess().GetHandleTable().GetObject(thread_handle); R_UNLESS(thread.IsNotNull(), svc::ResultInvalidHandle()); + + R_UNLESS(GetCurrentProcess().GetPageTable().IsSafeUserPointer(KProcessAddress(out_context.GetUnsafePointer()), sizeof(ams::svc::ThreadContext)), svc::ResultInvalidPointer()); /* Require the handle be to a non-current thread in the current process. */ R_UNLESS(thread->GetOwnerProcess() == GetCurrentProcessPointer(), svc::ResultInvalidHandle()); @@ -228,7 +230,7 @@ namespace ams::kern::svc { /* Validate that the pointer is in range. */ if (max_out_count > 0) { - R_UNLESS(GetCurrentProcess().GetPageTable().Contains(KProcessAddress(out_thread_ids.GetUnsafePointer()), max_out_count * sizeof(u64)), svc::ResultInvalidCurrentMemory()); + R_UNLESS(GetCurrentProcess().GetPageTable().IsSafeUserPointer(KProcessAddress(out_thread_ids.GetUnsafePointer()), max_out_count * sizeof(u64)), svc::ResultInvalidPointer()); } /* Get the handle table. */ From b7048ec59529a1fa1f753681cbdfae92082813d1 Mon Sep 17 00:00:00 2001 From: Alula Date: Wed, 16 Sep 2026 05:30:17 +0200 Subject: [PATCH 5/5] kern: fix kthread constinit --- libraries/libmesosphere/include/mesosphere/kern_k_thread.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_thread.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_thread.hpp index 7e294473c..f6193dd71 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_thread.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_thread.hpp @@ -353,7 +353,7 @@ namespace ams::kern { m_wait_result{svc::ResultNoSynchronizationObject()}, m_debug_exception_result{ResultSuccess()}, m_base_priority{}, m_base_priority_on_unpin{}, m_physical_ideal_core_id{}, m_virtual_ideal_core_id{}, m_num_kernel_waiters{}, m_current_core_id{}, m_core_id{}, m_original_physical_affinity_mask{}, m_original_physical_ideal_core_id{}, m_num_core_migration_disables{}, m_thread_state{}, m_termination_requested{false}, m_wait_cancelled{}, - m_cancellable{}, m_signaled{}, m_initialized{}, m_debug_attached{}, m_priority_inheritance_count{}, m_resource_limit_release_hint{} + m_cancellable{}, m_signaled{}, m_initialized{}, m_debug_attached{}, m_priority_inheritance_count{}, m_resource_limit_release_hint{}, m_debug_unknown5{} { /* ... */ }