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 9db423f1f..25c149b7f 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_page_table_base.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_page_table_base.hpp @@ -200,6 +200,7 @@ namespace ams::kern { bool m_is_kernel; bool m_enable_aslr; bool m_enable_device_address_space_merge; + bool m_allowed_exec_device_mapping; KMemoryBlockSlabManager *m_memory_block_slab_manager; KBlockInfoManager *m_block_info_manager; KResourceLimit *m_resource_limit; @@ -217,7 +218,7 @@ namespace ams::kern { 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_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() { @@ -520,6 +521,8 @@ namespace ams::kern { size_t GetAliasCodeDataSize() const; u32 GetAllocateOption() const { return m_allocate_option; } + + void AllowDeviceMappingOfExecPages() { m_allowed_exec_device_mapping = true; } public: static ALWAYS_INLINE KVirtualAddress GetLinearMappedVirtualAddress(KPhysicalAddress addr) { return KMemoryLayout::GetLinearVirtualAddress(addr); diff --git a/libraries/libmesosphere/source/kern_k_page_table_base.cpp b/libraries/libmesosphere/source/kern_k_page_table_base.cpp index ea44184fe..5d34dbe1f 100644 --- a/libraries/libmesosphere/source/kern_k_page_table_base.cpp +++ b/libraries/libmesosphere/source/kern_k_page_table_base.cpp @@ -211,6 +211,7 @@ namespace ams::kern { /* 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; + m_allowed_exec_device_mapping = false; m_address_space_start = start; m_address_space_end = end; m_is_kernel = false; @@ -3077,7 +3078,9 @@ namespace ams::kern { const u32 test_state = (is_aligned ? KMemoryState_FlagCanAlignedDeviceMap : KMemoryState_FlagCanDeviceMap) | (check_heap ? KMemoryState_FlagReferenceCounted : KMemoryState_None); size_t num_allocator_blocks; KMemoryState old_state; - R_TRY(this->CheckMemoryState(std::addressof(old_state), nullptr, nullptr, std::addressof(num_allocator_blocks), address, size, test_state, test_state, perm, perm, KMemoryAttribute_IpcLocked | KMemoryAttribute_Locked, KMemoryAttribute_None, KMemoryAttribute_DeviceShared)); + const KMemoryPermission perm_mask = static_cast(perm | (m_allowed_exec_device_mapping ? KMemoryPermission_None : KMemoryPermission_UserExecute)); + + R_TRY(this->CheckMemoryState(std::addressof(old_state), nullptr, nullptr, std::addressof(num_allocator_blocks), address, size, test_state, test_state, perm_mask, perm, KMemoryAttribute_IpcLocked | KMemoryAttribute_Locked, KMemoryAttribute_None, KMemoryAttribute_DeviceShared)); /* Create an update allocator. */ Result allocator_result; diff --git a/libraries/libmesosphere/source/kern_k_process.cpp b/libraries/libmesosphere/source/kern_k_process.cpp index c11cf0c42..91048f4f6 100644 --- a/libraries/libmesosphere/source/kern_k_process.cpp +++ b/libraries/libmesosphere/source/kern_k_process.cpp @@ -185,6 +185,11 @@ namespace ams::kern { /* Validate that the intended kernel version isn't too high for us to support. */ R_UNLESS(m_capabilities.GetIntendedKernelVersion() <= ams::svc::SupportedKernelVersion, svc::ResultInvalidCombination()); + /* Enable mapping device pages as executable on legacy processes. */ + if (m_capabilities.GetIntendedKernelMajorVersion() < 26) { + m_page_table.GetBasePageTable().AllowDeviceMappingOfExecPages(); + } + /* Create and clear the process local region. */ R_TRY(this->CreateThreadLocalRegion(std::addressof(m_plr_address))); m_plr_heap_address = this->GetThreadLocalRegionPointer(m_plr_address);