From d00406e089196a856ea80715b1f3f5931f6e7006 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Tue, 11 Oct 2022 20:15:33 -0700 Subject: [PATCH] os: update os namespace for 15.0.0, loader/ro: update to use csrng, spl: bump max sessions --- .../include/stratosphere/os.hpp | 1 + .../os/os_insecure_memory_api.hpp | 25 +++++++++++ .../os/os_interrupt_event_api.hpp | 3 ++ .../stratosphere/os/os_memory_common.hpp | 2 + .../os/os_process_code_memory_api.hpp | 2 +- .../stratosphere/os/os_process_memory_api.hpp | 2 +- .../svc/svc_stratosphere_shims.hpp | 8 ++++ .../os/impl/os_address_space_allocator.cpp | 24 +++++++++- .../os/impl/os_address_space_allocator.hpp | 4 +- .../os/impl/os_aslr_space_manager_types.hpp | 15 ++++--- .../os/impl/os_insecure_memory_impl.hpp | 27 ++++++++++++ .../os_insecure_memory_impl.os.horizon.cpp | 44 +++++++++++++++++++ .../os/impl/os_process_code_memory_impl.hpp | 2 +- ...os_process_code_memory_impl.os.horizon.cpp | 7 +-- .../source/os/impl/os_process_memory_impl.hpp | 2 +- .../os_process_memory_impl.os.horizon.cpp | 7 +-- .../os/impl/os_stack_guard_manager_types.hpp | 2 +- .../source/os/os_insecure_memory.cpp | 39 ++++++++++++++++ .../source/os/os_interrupt_event.cpp | 5 +++ .../source/os/os_process_code_memory.cpp | 4 +- .../source/os/os_process_memory.cpp | 4 +- .../vapours/svc/svc_definition_macro.hpp | 3 ++ .../loader/source/ldr_process_creation.cpp | 16 +++++-- stratosphere/ro/ro.json | 2 +- stratosphere/ro/source/impl/ro_nro_utils.cpp | 3 +- stratosphere/ro/source/impl/ro_nrr_utils.cpp | 5 ++- stratosphere/ro/source/impl/ro_random.cpp | 30 +++++++++++++ stratosphere/ro/source/impl/ro_random.hpp | 24 ++++++++++ .../ro/source/impl/ro_service_impl.cpp | 3 +- stratosphere/spl/source/spl_main.cpp | 14 +++--- 30 files changed, 290 insertions(+), 39 deletions(-) create mode 100644 libraries/libstratosphere/include/stratosphere/os/os_insecure_memory_api.hpp create mode 100644 libraries/libstratosphere/source/os/impl/os_insecure_memory_impl.hpp create mode 100644 libraries/libstratosphere/source/os/impl/os_insecure_memory_impl.os.horizon.cpp create mode 100644 libraries/libstratosphere/source/os/os_insecure_memory.cpp create mode 100644 stratosphere/ro/source/impl/ro_random.cpp create mode 100644 stratosphere/ro/source/impl/ro_random.hpp diff --git a/libraries/libstratosphere/include/stratosphere/os.hpp b/libraries/libstratosphere/include/stratosphere/os.hpp index 7bb10a349..8439a7963 100644 --- a/libraries/libstratosphere/include/stratosphere/os.hpp +++ b/libraries/libstratosphere/include/stratosphere/os.hpp @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include diff --git a/libraries/libstratosphere/include/stratosphere/os/os_insecure_memory_api.hpp b/libraries/libstratosphere/include/stratosphere/os/os_insecure_memory_api.hpp new file mode 100644 index 000000000..d9bec74ee --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/os/os_insecure_memory_api.hpp @@ -0,0 +1,25 @@ +/* + * Copyright (c) Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include + +namespace ams::os { + + Result AllocateInsecureMemory(uintptr_t *out_address, size_t size); + void FreeInsecureMemory(uintptr_t address, size_t size); + +} diff --git a/libraries/libstratosphere/include/stratosphere/os/os_interrupt_event_api.hpp b/libraries/libstratosphere/include/stratosphere/os/os_interrupt_event_api.hpp index 1704ad440..3a8b4f120 100644 --- a/libraries/libstratosphere/include/stratosphere/os/os_interrupt_event_api.hpp +++ b/libraries/libstratosphere/include/stratosphere/os/os_interrupt_event_api.hpp @@ -17,6 +17,7 @@ #pragma once #include #include +#include namespace ams::os { @@ -31,6 +32,8 @@ namespace ams::os { bool TimedWaitInterruptEvent(InterruptEventType *event, TimeSpan timeout); void ClearInterruptEvent(InterruptEventType *event); + NativeHandle GetInterruptEventHandle(const InterruptEventType *event); + void InitializeMultiWaitHolder(MultiWaitHolderType *multi_wait_holder, InterruptEventType *event); } diff --git a/libraries/libstratosphere/include/stratosphere/os/os_memory_common.hpp b/libraries/libstratosphere/include/stratosphere/os/os_memory_common.hpp index 0a418b632..070f95a68 100644 --- a/libraries/libstratosphere/include/stratosphere/os/os_memory_common.hpp +++ b/libraries/libstratosphere/include/stratosphere/os/os_memory_common.hpp @@ -18,6 +18,8 @@ namespace ams::os { + using AddressSpaceGenerateRandomFunction = u64 (*)(u64); + enum MemoryPermission { MemoryPermission_None = (0 << 0), MemoryPermission_ReadOnly = (1 << 0), diff --git a/libraries/libstratosphere/include/stratosphere/os/os_process_code_memory_api.hpp b/libraries/libstratosphere/include/stratosphere/os/os_process_code_memory_api.hpp index 0789b3730..27163ec96 100644 --- a/libraries/libstratosphere/include/stratosphere/os/os_process_code_memory_api.hpp +++ b/libraries/libstratosphere/include/stratosphere/os/os_process_code_memory_api.hpp @@ -25,7 +25,7 @@ namespace ams::os { u64 size; }; - Result MapProcessCodeMemory(u64 *out, NativeHandle handle, const ProcessMemoryRegion *regions, size_t num_regions); + Result MapProcessCodeMemory(u64 *out, NativeHandle handle, const ProcessMemoryRegion *regions, size_t num_regions, AddressSpaceGenerateRandomFunction generate_random); Result UnmapProcessCodeMemory(NativeHandle handle, u64 process_code_address, const ProcessMemoryRegion *regions, size_t num_regions); } diff --git a/libraries/libstratosphere/include/stratosphere/os/os_process_memory_api.hpp b/libraries/libstratosphere/include/stratosphere/os/os_process_memory_api.hpp index aea5f1a0c..ab4eda4f2 100644 --- a/libraries/libstratosphere/include/stratosphere/os/os_process_memory_api.hpp +++ b/libraries/libstratosphere/include/stratosphere/os/os_process_memory_api.hpp @@ -20,7 +20,7 @@ namespace ams::os { - Result MapProcessMemory(void **out, NativeHandle handle, u64 process_address, size_t process_size); + Result MapProcessMemory(void **out, NativeHandle handle, u64 process_address, size_t process_size, AddressSpaceGenerateRandomFunction generate_random); void UnmapProcessMemory(void *mapped_memory, NativeHandle handle, u64 process_address, size_t process_size); Result SetProcessMemoryPermission(NativeHandle handle, u64 process_address, u64 process_size, MemoryPermission perm); diff --git a/libraries/libstratosphere/include/stratosphere/svc/svc_stratosphere_shims.hpp b/libraries/libstratosphere/include/stratosphere/svc/svc_stratosphere_shims.hpp index 4850b0292..e0d2db28e 100644 --- a/libraries/libstratosphere/include/stratosphere/svc/svc_stratosphere_shims.hpp +++ b/libraries/libstratosphere/include/stratosphere/svc/svc_stratosphere_shims.hpp @@ -503,6 +503,14 @@ ::svcCallSecureMonitor(reinterpret_cast<::SecmonArgs *>(args)); } + ALWAYS_INLINE Result MapInsecureMemory(::ams::svc::Address address, ::ams::svc::Size size) { + R_RETURN(::svcMapInsecureMemory(reinterpret_cast(static_cast(address)), size)); + } + + ALWAYS_INLINE Result UnmapInsecureMemory(::ams::svc::Address address, ::ams::svc::Size size) { + R_RETURN(::svcUnmapInsecureMemory(reinterpret_cast(static_cast(address)), size)); + } + } #endif diff --git a/libraries/libstratosphere/source/os/impl/os_address_space_allocator.cpp b/libraries/libstratosphere/source/os/impl/os_address_space_allocator.cpp index 208e2e6da..a5f7e2ee7 100644 --- a/libraries/libstratosphere/source/os/impl/os_address_space_allocator.cpp +++ b/libraries/libstratosphere/source/os/impl/os_address_space_allocator.cpp @@ -19,6 +19,24 @@ namespace ams::os::impl { + namespace { + + constexpr inline u64 MaxProbabilityVariationInverseShift = 4; + + } + + u64 AddressSpaceAllocatorDefaultGenerateRandom(u64 max) { + /* Check that max is in range. */ + AMS_ASSERT(max + 1 <= (UINT64_C(1) << (BITSIZEOF(u64) - MaxProbabilityVariationInverseShift))); + + /* Generate random u64. */ + const u64 rand = GetRngManager().GenerateRandomU64(); + + /* Coerce into range. */ + AMS_ASSERT(max < std::numeric_limits::max()); + return rand % (max + 1); + } + template AddressSpaceAllocatorBase::AddressSpaceAllocatorBase(u64 start_address, u64 end_address, SizeType guard_size, const AddressSpaceAllocatorForbiddenRegion *forbidden_regions, size_t num_forbidden_regions) : m_critical_section(), m_forbidden_region_count(0) { /* Check pre-conditions. */ @@ -64,7 +82,7 @@ namespace ams::os::impl { } template - AddressType AddressSpaceAllocatorBase::AllocateSpace(SizeType size, SizeType align, SizeType align_offset) { + AddressType AddressSpaceAllocatorBase::AllocateSpace(SizeType size, SizeType align, SizeType align_offset, AddressSpaceGenerateRandomFunction generate_random) { /* Check pre-conditions. */ AMS_ASSERT(align > 0); AMS_ASSERT((align_offset & ~(align - 1)) == 0); @@ -98,7 +116,9 @@ namespace ams::os::impl { std::scoped_lock lk(m_critical_section); /* Determine a random page. */ - const AddressType target = (((GetRngManager().GenerateRandomU64() % (rand_end - rand_start + 1)) + rand_start) * align_page_count) + align_offset_page_count; + const u64 random = generate_random(rand_end - rand_start); + + const AddressType target = ((random + rand_start) * align_page_count) + align_offset_page_count; AMS_ASSERT(m_start_page <= target - m_guard_page_count && target + page_count + m_guard_page_count <= m_end_page); /* Check that the page is not forbidden. */ diff --git a/libraries/libstratosphere/source/os/impl/os_address_space_allocator.hpp b/libraries/libstratosphere/source/os/impl/os_address_space_allocator.hpp index d3ff688b5..d0a9f77d5 100644 --- a/libraries/libstratosphere/source/os/impl/os_address_space_allocator.hpp +++ b/libraries/libstratosphere/source/os/impl/os_address_space_allocator.hpp @@ -45,7 +45,7 @@ namespace ams::os::impl { public: AddressSpaceAllocatorBase(u64 start_address, u64 end_address, SizeType guard_size, const AddressSpaceAllocatorForbiddenRegion *forbidden_regions, size_t num_forbidden_regions); - AddressType AllocateSpace(SizeType size, SizeType align, SizeType align_offset); + AddressType AllocateSpace(SizeType size, SizeType align, SizeType align_offset, AddressSpaceGenerateRandomFunction generate_random); bool CheckGuardSpace(AddressType address, SizeType size, SizeType guard_size); private: @@ -54,6 +54,8 @@ namespace ams::os::impl { virtual bool CheckFreeSpace(AddressType address, SizeType size) = 0; }; + u64 AddressSpaceAllocatorDefaultGenerateRandom(u64 max); + } #if defined(ATMOSPHERE_OS_HORIZON) diff --git a/libraries/libstratosphere/source/os/impl/os_aslr_space_manager_types.hpp b/libraries/libstratosphere/source/os/impl/os_aslr_space_manager_types.hpp index 5f4ccb105..e87d03490 100644 --- a/libraries/libstratosphere/source/os/impl/os_aslr_space_manager_types.hpp +++ b/libraries/libstratosphere/source/os/impl/os_aslr_space_manager_types.hpp @@ -55,16 +55,16 @@ namespace ams::os::impl { } #endif - AddressType AllocateSpace(SizeType size, SizeType align_offset) { + AddressType AllocateSpace(SizeType size, SizeType align_offset, AddressSpaceGenerateRandomFunction generate_random) { /* Try to allocate a large-aligned space, if we can. */ if (align_offset || (size / AslrSpaceLargeAlign) != 0) { - if (auto large_align = m_allocator.AllocateSpace(size, AslrSpaceLargeAlign, align_offset & (AslrSpaceLargeAlign - 1)); large_align != 0) { + if (auto large_align = m_allocator.AllocateSpace(size, AslrSpaceLargeAlign, align_offset & (AslrSpaceLargeAlign - 1), generate_random); large_align != 0) { return large_align; } } /* Allocate a page-aligned space. */ - return m_allocator.AllocateSpace(size, MemoryPageSize, 0); + return m_allocator.AllocateSpace(size, MemoryPageSize, 0, generate_random); } bool CheckGuardSpace(AddressType address, SizeType size) { @@ -72,11 +72,11 @@ namespace ams::os::impl { } template - Result MapAtRandomAddress(AddressType *out, MapFunction map_function, UnmapFunction unmap_function, SizeType size, SizeType align_offset) { + Result MapAtRandomAddressWithCustomRandomGenerator(AddressType *out, MapFunction map_function, UnmapFunction unmap_function, SizeType size, SizeType align_offset, AddressSpaceGenerateRandomFunction generate_random) { /* Try to map up to 64 times. */ for (auto i = 0; i < 64; ++i) { /* Reserve space to map the memory. */ - const uintptr_t map_address = this->AllocateSpace(size, align_offset); + const uintptr_t map_address = this->AllocateSpace(size, align_offset, generate_random); if (map_address == 0) { break; } @@ -105,6 +105,11 @@ namespace ams::os::impl { /* We failed to map. */ R_THROW(os::ResultOutOfAddressSpace()); } + + template + Result MapAtRandomAddress(AddressType *out, MapFunction map_function, UnmapFunction unmap_function, SizeType size, SizeType align_offset) { + R_RETURN(this->MapAtRandomAddressWithCustomRandomGenerator(out, map_function, unmap_function, size, align_offset, os::impl::AddressSpaceAllocatorDefaultGenerateRandom)); + } }; using AslrSpaceManager = AslrSpaceManagerTemplate; diff --git a/libraries/libstratosphere/source/os/impl/os_insecure_memory_impl.hpp b/libraries/libstratosphere/source/os/impl/os_insecure_memory_impl.hpp new file mode 100644 index 000000000..fe4972798 --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_insecure_memory_impl.hpp @@ -0,0 +1,27 @@ +/* + * Copyright (c) Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include + +namespace ams::os::impl { + + class InsecureMemoryImpl { + public: + static Result AllocateInsecureMemoryImpl(uintptr_t *out_address, size_t size); + static void FreeInsecureMemoryImpl(uintptr_t address, size_t size); + }; + +} \ No newline at end of file diff --git a/libraries/libstratosphere/source/os/impl/os_insecure_memory_impl.os.horizon.cpp b/libraries/libstratosphere/source/os/impl/os_insecure_memory_impl.os.horizon.cpp new file mode 100644 index 000000000..11a63a7ae --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_insecure_memory_impl.os.horizon.cpp @@ -0,0 +1,44 @@ +/* + * Copyright (c) Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include +#include "os_insecure_memory_impl.hpp" +#include "os_aslr_space_manager.hpp" + +namespace ams::os::impl { + + Result InsecureMemoryImpl::AllocateInsecureMemoryImpl(uintptr_t *out_address, size_t size) { + /* Map at a random address. */ + R_RETURN(impl::GetAslrSpaceManager().MapAtRandomAddress(out_address, + [](uintptr_t map_address, size_t map_size) -> Result { + R_TRY_CATCH(svc::MapInsecureMemory(map_address, map_size)) { + R_CONVERT(svc::ResultInvalidCurrentMemory, os::ResultInvalidCurrentMemoryState()) + } R_END_TRY_CATCH_WITH_ABORT_UNLESS; + + R_SUCCEED(); + }, + [](uintptr_t map_address, size_t map_size) -> void { + return InsecureMemoryImpl::FreeInsecureMemoryImpl(map_address, map_size); + }, + size, + 0 + )); + } + + void InsecureMemoryImpl::FreeInsecureMemoryImpl(uintptr_t address, size_t size) { + R_ABORT_UNLESS(svc::UnmapInsecureMemory(address, size)); + } + +} diff --git a/libraries/libstratosphere/source/os/impl/os_process_code_memory_impl.hpp b/libraries/libstratosphere/source/os/impl/os_process_code_memory_impl.hpp index 45fe4e213..e48933dee 100644 --- a/libraries/libstratosphere/source/os/impl/os_process_code_memory_impl.hpp +++ b/libraries/libstratosphere/source/os/impl/os_process_code_memory_impl.hpp @@ -20,7 +20,7 @@ namespace ams::os::impl { class ProcessCodeMemoryImpl { public: - static Result Map(u64 *out, NativeHandle handle, const ProcessMemoryRegion *regions, size_t num_regions); + static Result Map(u64 *out, NativeHandle handle, const ProcessMemoryRegion *regions, size_t num_regions, AddressSpaceGenerateRandomFunction generate_random); static Result Unmap(NativeHandle handle, u64 process_code_address, const ProcessMemoryRegion *regions, size_t num_regions); }; diff --git a/libraries/libstratosphere/source/os/impl/os_process_code_memory_impl.os.horizon.cpp b/libraries/libstratosphere/source/os/impl/os_process_code_memory_impl.os.horizon.cpp index 7bafacc50..adb77c3dd 100644 --- a/libraries/libstratosphere/source/os/impl/os_process_code_memory_impl.os.horizon.cpp +++ b/libraries/libstratosphere/source/os/impl/os_process_code_memory_impl.os.horizon.cpp @@ -55,7 +55,7 @@ namespace ams::os::impl { } - Result ProcessCodeMemoryImpl::Map(u64 *out, NativeHandle handle, const ProcessMemoryRegion *regions, size_t num_regions) { + Result ProcessCodeMemoryImpl::Map(u64 *out, NativeHandle handle, const ProcessMemoryRegion *regions, size_t num_regions, AddressSpaceGenerateRandomFunction generate_random) { /* Get the total process memory region size. */ const size_t total_size = GetTotalProcessMemoryRegionSize(regions, num_regions); @@ -64,7 +64,7 @@ namespace ams::os::impl { /* Map at a random address. */ u64 mapped_address; - R_TRY(process_aslr_space_manager.MapAtRandomAddress(std::addressof(mapped_address), + R_TRY(process_aslr_space_manager.MapAtRandomAddressWithCustomRandomGenerator(std::addressof(mapped_address), [handle, regions, num_regions](u64 map_address, u64 map_size) -> Result { AMS_UNUSED(map_size); @@ -107,7 +107,8 @@ namespace ams::os::impl { R_ABORT_UNLESS(ProcessCodeMemoryImpl::Unmap(handle, map_address, regions, num_regions)); }, total_size, - regions[0].address /* NOTE: This seems like a Nintendo bug, if the caller passed no regions. */ + regions[0].address, /* NOTE: This seems like a Nintendo bug, if the caller passed no regions. */ + generate_random )); /* Set the output address. */ diff --git a/libraries/libstratosphere/source/os/impl/os_process_memory_impl.hpp b/libraries/libstratosphere/source/os/impl/os_process_memory_impl.hpp index faf035fe8..e3d4b2638 100644 --- a/libraries/libstratosphere/source/os/impl/os_process_memory_impl.hpp +++ b/libraries/libstratosphere/source/os/impl/os_process_memory_impl.hpp @@ -20,7 +20,7 @@ namespace ams::os::impl { class ProcessMemoryImpl { public: - static Result Map(void **out, NativeHandle handle, u64 process_address, size_t size); + static Result Map(void **out, NativeHandle handle, u64 process_address, size_t size, AddressSpaceGenerateRandomFunction generate_random); static void Unmap(void *mapped_memory, NativeHandle handle, u64 process_address, size_t size); static Result SetMemoryPermission(NativeHandle handle, u64 process_address, u64 size, MemoryPermission perm); diff --git a/libraries/libstratosphere/source/os/impl/os_process_memory_impl.os.horizon.cpp b/libraries/libstratosphere/source/os/impl/os_process_memory_impl.os.horizon.cpp index fc836391b..de7b241a6 100644 --- a/libraries/libstratosphere/source/os/impl/os_process_memory_impl.os.horizon.cpp +++ b/libraries/libstratosphere/source/os/impl/os_process_memory_impl.os.horizon.cpp @@ -33,10 +33,10 @@ namespace ams::os::impl { } - Result ProcessMemoryImpl::Map(void **out, NativeHandle handle, u64 process_address, size_t size) { + Result ProcessMemoryImpl::Map(void **out, NativeHandle handle, u64 process_address, size_t size, AddressSpaceGenerateRandomFunction generate_random) { /* Map at a random address. */ uintptr_t mapped_address; - R_TRY(impl::GetAslrSpaceManager().MapAtRandomAddress(std::addressof(mapped_address), + R_TRY(impl::GetAslrSpaceManager().MapAtRandomAddressWithCustomRandomGenerator(std::addressof(mapped_address), [handle, process_address](uintptr_t map_address, size_t map_size) -> Result { R_TRY_CATCH(svc::MapProcessMemory(map_address, handle, process_address, map_size)) { R_CONVERT(svc::ResultOutOfResource, os::ResultOutOfResource()) @@ -49,7 +49,8 @@ namespace ams::os::impl { return ProcessMemoryImpl::Unmap(reinterpret_cast(map_address), handle, process_address, map_size); }, size, - process_address + process_address, + generate_random )); /* Return the address we mapped at. */ diff --git a/libraries/libstratosphere/source/os/impl/os_stack_guard_manager_types.hpp b/libraries/libstratosphere/source/os/impl/os_stack_guard_manager_types.hpp index b49c4dd63..59f7cfbea 100644 --- a/libraries/libstratosphere/source/os/impl/os_stack_guard_manager_types.hpp +++ b/libraries/libstratosphere/source/os/impl/os_stack_guard_manager_types.hpp @@ -43,7 +43,7 @@ namespace ams::os::impl { } void *AllocateStackGuardSpace(size_t size) { - return reinterpret_cast(m_allocator.AllocateSpace(size, os::MemoryPageSize, 0)); + return reinterpret_cast(m_allocator.AllocateSpace(size, os::MemoryPageSize, 0, os::impl::AddressSpaceAllocatorDefaultGenerateRandom)); } bool CheckGuardSpace(uintptr_t address, size_t size) { diff --git a/libraries/libstratosphere/source/os/os_insecure_memory.cpp b/libraries/libstratosphere/source/os/os_insecure_memory.cpp new file mode 100644 index 000000000..f03ecd3e2 --- /dev/null +++ b/libraries/libstratosphere/source/os/os_insecure_memory.cpp @@ -0,0 +1,39 @@ +/* + * Copyright (c) Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include +#include "impl/os_insecure_memory_impl.hpp" + +namespace ams::os { + + Result AllocateInsecureMemory(uintptr_t *out_address, size_t size) { + /* Check arguments. */ + AMS_ASSERT(size > 0); + AMS_ASSERT(util::IsAligned(size, os::MemoryPageSize)); + + /* Allocate memory. */ + R_RETURN(impl::InsecureMemoryImpl::AllocateInsecureMemoryImpl(out_address, size)); + } + + void FreeInsecureMemory(uintptr_t address, size_t size) { + /* Check arguments. */ + AMS_ASSERT(util::IsAligned(address, os::MemoryPageSize)); + AMS_ASSERT(util::IsAligned(size, os::MemoryPageSize)); + + /* Free memory. */ + impl::InsecureMemoryImpl::FreeInsecureMemoryImpl(address, size); + } + +} diff --git a/libraries/libstratosphere/source/os/os_interrupt_event.cpp b/libraries/libstratosphere/source/os/os_interrupt_event.cpp index bcc8e326a..64bb5a323 100644 --- a/libraries/libstratosphere/source/os/os_interrupt_event.cpp +++ b/libraries/libstratosphere/source/os/os_interrupt_event.cpp @@ -62,6 +62,11 @@ namespace ams::os { return GetReference(event->impl).Clear(); } + NativeHandle GetInterruptEventHandle(const InterruptEventType *event) { + AMS_ASSERT(event->state == InterruptEventType::State_Initialized); + return GetReference(event->impl).GetHandle(); + } + void InitializeMultiWaitHolder(MultiWaitHolderType *multi_wait_holder, InterruptEventType *event) { AMS_ASSERT(event->state == InterruptEventType::State_Initialized); diff --git a/libraries/libstratosphere/source/os/os_process_code_memory.cpp b/libraries/libstratosphere/source/os/os_process_code_memory.cpp index ccd24d158..497f798c3 100644 --- a/libraries/libstratosphere/source/os/os_process_code_memory.cpp +++ b/libraries/libstratosphere/source/os/os_process_code_memory.cpp @@ -18,8 +18,8 @@ namespace ams::os { - Result MapProcessCodeMemory(u64 *out, NativeHandle handle, const ProcessMemoryRegion *regions, size_t num_regions) { - R_RETURN(::ams::os::impl::ProcessCodeMemoryImpl::Map(out, handle, regions, num_regions)); + Result MapProcessCodeMemory(u64 *out, NativeHandle handle, const ProcessMemoryRegion *regions, size_t num_regions, AddressSpaceGenerateRandomFunction generate_random) { + R_RETURN(::ams::os::impl::ProcessCodeMemoryImpl::Map(out, handle, regions, num_regions, generate_random)); } Result UnmapProcessCodeMemory(NativeHandle handle, u64 process_code_address, const ProcessMemoryRegion *regions, size_t num_regions) { diff --git a/libraries/libstratosphere/source/os/os_process_memory.cpp b/libraries/libstratosphere/source/os/os_process_memory.cpp index 65d023db6..8cdcbf8c7 100644 --- a/libraries/libstratosphere/source/os/os_process_memory.cpp +++ b/libraries/libstratosphere/source/os/os_process_memory.cpp @@ -18,8 +18,8 @@ namespace ams::os { - Result MapProcessMemory(void **out, NativeHandle handle, u64 process_address, size_t process_size) { - R_RETURN(::ams::os::impl::ProcessMemoryImpl::Map(out, handle, process_address, process_size)); + Result MapProcessMemory(void **out, NativeHandle handle, u64 process_address, size_t process_size, AddressSpaceGenerateRandomFunction generate_random) { + R_RETURN(::ams::os::impl::ProcessMemoryImpl::Map(out, handle, process_address, process_size, generate_random)); } void UnmapProcessMemory(void *mapped_memory, NativeHandle handle, u64 process_address, size_t process_size) { diff --git a/libraries/libvapours/include/vapours/svc/svc_definition_macro.hpp b/libraries/libvapours/include/vapours/svc/svc_definition_macro.hpp index 6376148ba..a69db1627 100644 --- a/libraries/libvapours/include/vapours/svc/svc_definition_macro.hpp +++ b/libraries/libvapours/include/vapours/svc/svc_definition_macro.hpp @@ -142,6 +142,9 @@ HANDLER(0x7E, Result, SetResourceLimitLimitValue, INPUT(::ams::svc::Handle, resource_limit_handle), INPUT(::ams::svc::LimitableResource, which), INPUT(int64_t, limit_value)) \ HANDLER(0x7F, void, CallSecureMonitor, OUTPUT(::ams::svc::NAMESPACE::SecureMonitorArguments, args)) \ \ + HANDLER(0x90, Result, MapInsecureMemory, INPUT(::ams::svc::Address, address), INPUT(::ams::svc::Size, size)) \ + HANDLER(0x91, Result, UnmapInsecureMemory, INPUT(::ams::svc::Address, address), INPUT(::ams::svc::Size, size)) \ + \ HANDLER(0x2E, Result, LegacyGetFutureThreadInfo, OUTPUT(::ams::svc::NAMESPACE::LastThreadContext, out_context), OUTPUT(::ams::svc::Address, out_tls_address), OUTPUT(uint32_t, out_flags), INPUT(int64_t, ns)) \ HANDLER(0x55, Result, LegacyQueryIoMapping, OUTPUT(::ams::svc::Address, out_address), INPUT(::ams::svc::PhysicalAddress, physical_address), INPUT(::ams::svc::Size, size)) \ HANDLER(0x64, Result, LegacyContinueDebugEvent, INPUT(::ams::svc::Handle, debug_handle), INPUT(uint32_t, flags), INPUT(uint64_t, thread_id)) diff --git a/stratosphere/loader/source/ldr_process_creation.cpp b/stratosphere/loader/source/ldr_process_creation.cpp index 8b0632aa9..58e4cf955 100644 --- a/stratosphere/loader/source/ldr_process_creation.cpp +++ b/stratosphere/loader/source/ldr_process_creation.cpp @@ -399,6 +399,15 @@ namespace ams::ldr { R_SUCCEED(); } + u64 GenerateSecureRandom(u64 max) { + /* Generate a cryptographically random number. */ + u64 rand; + crypto::GenerateCryptographicallyRandomBytes(std::addressof(rand), sizeof(rand)); + + /* Coerce into range. */ + return rand % (max + 1); + } + Result DecideAddressSpaceLayout(ProcessInfo *out, svc::CreateProcessParameter *out_param, const NsoHeader *nso_headers, const bool *has_nso, const ArgumentStore::Entry *argument) { /* Clear output. */ out->args_address = 0; @@ -468,8 +477,7 @@ namespace ams::ldr { uintptr_t aslr_slide = 0; size_t free_size = (aslr_size - total_size); if (out_param->flags & svc::CreateProcessFlag_EnableAslr) { - /* Nintendo uses MT19937 (not os::GenerateRandomBytes), but we'll just use TinyMT for now. */ - aslr_slide = os::GenerateRandomU64(free_size / os::MemoryBlockUnitSize) * os::MemoryBlockUnitSize; + aslr_slide = GenerateSecureRandom(free_size / os::MemoryBlockUnitSize) * os::MemoryBlockUnitSize; } /* Set out. */ @@ -527,7 +535,7 @@ namespace ams::ldr { { /* Map the process memory. */ void *mapped_memory = nullptr; - R_TRY(os::MapProcessMemory(std::addressof(mapped_memory), process_handle, nso_address, nso_size)); + R_TRY(os::MapProcessMemory(std::addressof(mapped_memory), process_handle, nso_address, nso_size, GenerateSecureRandom)); ON_SCOPE_EXIT { os::UnmapProcessMemory(mapped_memory, process_handle, nso_address, nso_size); }; const uintptr_t map_address = reinterpret_cast(mapped_memory); @@ -590,7 +598,7 @@ namespace ams::ldr { /* Write argument data into memory. */ { void *map_address = nullptr; - R_TRY(os::MapProcessMemory(std::addressof(map_address), process_info->process_handle, process_info->args_address, process_info->args_size)); + R_TRY(os::MapProcessMemory(std::addressof(map_address), process_info->process_handle, process_info->args_address, process_info->args_size, GenerateSecureRandom)); ON_SCOPE_EXIT { os::UnmapProcessMemory(map_address, process_info->process_handle, process_info->args_address, process_info->args_size); }; ProgramArguments *args = static_cast(map_address); diff --git a/stratosphere/ro/ro.json b/stratosphere/ro/ro.json index 57b009592..fe547227d 100644 --- a/stratosphere/ro/ro.json +++ b/stratosphere/ro/ro.json @@ -15,7 +15,7 @@ "filesystem_access": { "permissions": "0xFFFFFFFFFFFFFFFF" }, - "service_access": ["fatal:u", "spl:", "set:sys", "fsp-srv"], + "service_access": ["fatal:u", "spl:", "set:sys", "fsp-srv", "csrng"], "service_host": ["ldr:ro", "ro:dmnt", "ro:1"], "kernel_capabilities": [{ "type": "kernel_flags", diff --git a/stratosphere/ro/source/impl/ro_nro_utils.cpp b/stratosphere/ro/source/impl/ro_nro_utils.cpp index 5ebebe6b3..588a26387 100644 --- a/stratosphere/ro/source/impl/ro_nro_utils.cpp +++ b/stratosphere/ro/source/impl/ro_nro_utils.cpp @@ -15,6 +15,7 @@ */ #include #include "ro_nro_utils.hpp" +#include "ro_random.hpp" namespace ams::ro::impl { @@ -43,7 +44,7 @@ namespace ams::ro::impl { const size_t num_regions = SetupNroProcessMemoryRegions(regions, nro_heap_address, nro_heap_size, bss_heap_address, bss_heap_size); /* Re-map the nro/bss as code memory in the destination process. */ - R_TRY_CATCH(os::MapProcessCodeMemory(out_base_address, process_handle, regions, num_regions)) { + R_TRY_CATCH(os::MapProcessCodeMemory(out_base_address, process_handle, regions, num_regions, ro::impl::GenerateSecureRandom)) { R_CONVERT(os::ResultOutOfAddressSpace, ro::ResultOutOfAddressSpace()) } R_END_TRY_CATCH; diff --git a/stratosphere/ro/source/impl/ro_nrr_utils.cpp b/stratosphere/ro/source/impl/ro_nrr_utils.cpp index 27eeeddb9..60b69095a 100644 --- a/stratosphere/ro/source/impl/ro_nrr_utils.cpp +++ b/stratosphere/ro/source/impl/ro_nrr_utils.cpp @@ -15,6 +15,7 @@ */ #include #include "ro_nrr_utils.hpp" +#include "ro_random.hpp" #include "ro_service_impl.hpp" namespace ams::ro::impl { @@ -198,7 +199,7 @@ namespace ams::ro::impl { /* Re-map the nrr as code memory in the destination process. */ u64 code_address = 0; const os::ProcessMemoryRegion region = { nrr_heap_address, nrr_heap_size }; - R_TRY_CATCH(os::MapProcessCodeMemory(std::addressof(code_address), process_handle, std::addressof(region), 1)) { + R_TRY_CATCH(os::MapProcessCodeMemory(std::addressof(code_address), process_handle, std::addressof(region), 1, ro::impl::GenerateSecureRandom)) { R_CONVERT(os::ResultOutOfAddressSpace, ro::ResultOutOfAddressSpace()) } R_END_TRY_CATCH; @@ -207,7 +208,7 @@ namespace ams::ro::impl { /* Map the nrr in our process. */ void *mapped_memory = nullptr; - R_TRY_CATCH(os::MapProcessMemory(std::addressof(mapped_memory), process_handle, code_address, region.size)) { + R_TRY_CATCH(os::MapProcessMemory(std::addressof(mapped_memory), process_handle, code_address, region.size, ro::impl::GenerateSecureRandom)) { R_CONVERT(os::ResultOutOfAddressSpace, ro::ResultOutOfAddressSpace()) } R_END_TRY_CATCH; diff --git a/stratosphere/ro/source/impl/ro_random.cpp b/stratosphere/ro/source/impl/ro_random.cpp new file mode 100644 index 000000000..618b39676 --- /dev/null +++ b/stratosphere/ro/source/impl/ro_random.cpp @@ -0,0 +1,30 @@ +/* + * Copyright (c) Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include +#include "ro_random.hpp" + +namespace ams::ro::impl { + + u64 GenerateSecureRandom(u64 max) { + /* Generate a cryptographically random number. */ + u64 rand; + crypto::GenerateCryptographicallyRandomBytes(std::addressof(rand), sizeof(rand)); + + /* Coerce into range. */ + return rand % (max + 1); + } + +} \ No newline at end of file diff --git a/stratosphere/ro/source/impl/ro_random.hpp b/stratosphere/ro/source/impl/ro_random.hpp new file mode 100644 index 000000000..db4ee9e1e --- /dev/null +++ b/stratosphere/ro/source/impl/ro_random.hpp @@ -0,0 +1,24 @@ +/* + * Copyright (c) Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include + +namespace ams::ro::impl { + + u64 GenerateSecureRandom(u64 max); + +} \ No newline at end of file diff --git a/stratosphere/ro/source/impl/ro_service_impl.cpp b/stratosphere/ro/source/impl/ro_service_impl.cpp index 2d9e3e923..0be672f37 100644 --- a/stratosphere/ro/source/impl/ro_service_impl.cpp +++ b/stratosphere/ro/source/impl/ro_service_impl.cpp @@ -17,6 +17,7 @@ #include "ro_nrr_utils.hpp" #include "ro_nro_utils.hpp" #include "ro_patcher.hpp" +#include "ro_random.hpp" #include "ro_service_impl.hpp" namespace ams::ro::impl { @@ -249,7 +250,7 @@ namespace ams::ro::impl { Result ValidateNro(ModuleId *out_module_id, u64 *out_rx_size, u64 *out_ro_size, u64 *out_rw_size, u64 base_address, u64 expected_nro_size, u64 expected_bss_size) { /* Map the NRO. */ void *mapped_memory = nullptr; - R_TRY_CATCH(os::MapProcessMemory(std::addressof(mapped_memory), m_process_handle, base_address, expected_nro_size)) { + R_TRY_CATCH(os::MapProcessMemory(std::addressof(mapped_memory), m_process_handle, base_address, expected_nro_size, ro::impl::GenerateSecureRandom)) { R_CONVERT(os::ResultOutOfAddressSpace, ro::ResultOutOfAddressSpace()) } R_END_TRY_CATCH; diff --git a/stratosphere/spl/source/spl_main.cpp b/stratosphere/spl/source/spl_main.cpp index f77519458..a6e1134a1 100644 --- a/stratosphere/spl/source/spl_main.cpp +++ b/stratosphere/spl/source/spl_main.cpp @@ -51,26 +51,26 @@ namespace ams { }; constexpr sm::ServiceName RandomServiceName = sm::ServiceName::Encode("csrng"); - constexpr size_t RandomMaxSessions = 3; + constexpr size_t RandomMaxSessions = 10; /* NOTE: Official is 9. */ constexpr sm::ServiceName GeneralServiceName = sm::ServiceName::Encode("spl:"); constexpr size_t DeprecatedMaxSessions = 13; - constexpr size_t GeneralMaxSessions = 7; + constexpr size_t GeneralMaxSessions = 9; /* NOTE: Official is 8. */ constexpr sm::ServiceName CryptoServiceName = sm::ServiceName::Encode("spl:mig"); - constexpr size_t CryptoMaxSessions = 7; + constexpr size_t CryptoMaxSessions = 7; /* NOTE: Official is 6. */ constexpr sm::ServiceName SslServiceName = sm::ServiceName::Encode("spl:ssl"); - constexpr size_t SslMaxSessions = 2; + constexpr size_t SslMaxSessions = 2; /* NOTE: Official is 2. */ constexpr sm::ServiceName EsServiceName = sm::ServiceName::Encode("spl:es"); - constexpr size_t EsMaxSessions = 2; + constexpr size_t EsMaxSessions = 2; /* NOTE: Official is 2. */ constexpr sm::ServiceName FsServiceName = sm::ServiceName::Encode("spl:fs"); - constexpr size_t FsMaxSessions = 3; + constexpr size_t FsMaxSessions = 3; /* NOTE: Official is 1. */ constexpr sm::ServiceName ManuServiceName = sm::ServiceName::Encode("spl:manu"); - constexpr size_t ManuMaxSessions = 1; + constexpr size_t ManuMaxSessions = 1; /* NOTE: Official is 1. */ /* csrng, spl:, spl:mig, spl:ssl, spl:es, spl:fs, spl:manu. */ /* TODO: Consider max sessions enforcement? */