os: update os namespace for 15.0.0, loader/ro: update to use csrng, spl: bump max sessions

This commit is contained in:
Michael Scire 2022-10-11 20:15:33 -07:00 committed by SciresM
parent dddb5bfdea
commit d00406e089
30 changed files with 290 additions and 39 deletions

View file

@ -28,6 +28,7 @@
#include <stratosphere/os/os_process_handle_api.hpp> #include <stratosphere/os/os_process_handle_api.hpp>
#include <stratosphere/os/os_process_memory_api.hpp> #include <stratosphere/os/os_process_memory_api.hpp>
#include <stratosphere/os/os_process_code_memory_api.hpp> #include <stratosphere/os/os_process_code_memory_api.hpp>
#include <stratosphere/os/os_insecure_memory_api.hpp>
#include <stratosphere/os/os_random.hpp> #include <stratosphere/os/os_random.hpp>
#include <stratosphere/os/os_mutex.hpp> #include <stratosphere/os/os_mutex.hpp>
#include <stratosphere/os/os_condition_variable.hpp> #include <stratosphere/os/os_condition_variable.hpp>

View file

@ -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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <stratosphere/os/os_memory_common.hpp>
namespace ams::os {
Result AllocateInsecureMemory(uintptr_t *out_address, size_t size);
void FreeInsecureMemory(uintptr_t address, size_t size);
}

View file

@ -17,6 +17,7 @@
#pragma once #pragma once
#include <vapours.hpp> #include <vapours.hpp>
#include <stratosphere/os/os_interrupt_event_common.hpp> #include <stratosphere/os/os_interrupt_event_common.hpp>
#include <stratosphere/os/os_native_handle.hpp>
namespace ams::os { namespace ams::os {
@ -31,6 +32,8 @@ namespace ams::os {
bool TimedWaitInterruptEvent(InterruptEventType *event, TimeSpan timeout); bool TimedWaitInterruptEvent(InterruptEventType *event, TimeSpan timeout);
void ClearInterruptEvent(InterruptEventType *event); void ClearInterruptEvent(InterruptEventType *event);
NativeHandle GetInterruptEventHandle(const InterruptEventType *event);
void InitializeMultiWaitHolder(MultiWaitHolderType *multi_wait_holder, InterruptEventType *event); void InitializeMultiWaitHolder(MultiWaitHolderType *multi_wait_holder, InterruptEventType *event);
} }

View file

@ -18,6 +18,8 @@
namespace ams::os { namespace ams::os {
using AddressSpaceGenerateRandomFunction = u64 (*)(u64);
enum MemoryPermission { enum MemoryPermission {
MemoryPermission_None = (0 << 0), MemoryPermission_None = (0 << 0),
MemoryPermission_ReadOnly = (1 << 0), MemoryPermission_ReadOnly = (1 << 0),

View file

@ -25,7 +25,7 @@ namespace ams::os {
u64 size; 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); Result UnmapProcessCodeMemory(NativeHandle handle, u64 process_code_address, const ProcessMemoryRegion *regions, size_t num_regions);
} }

View file

@ -20,7 +20,7 @@
namespace ams::os { 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); 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); Result SetProcessMemoryPermission(NativeHandle handle, u64 process_address, u64 process_size, MemoryPermission perm);

View file

@ -503,6 +503,14 @@
::svcCallSecureMonitor(reinterpret_cast<::SecmonArgs *>(args)); ::svcCallSecureMonitor(reinterpret_cast<::SecmonArgs *>(args));
} }
ALWAYS_INLINE Result MapInsecureMemory(::ams::svc::Address address, ::ams::svc::Size size) {
R_RETURN(::svcMapInsecureMemory(reinterpret_cast<void *>(static_cast<uintptr_t>(address)), size));
}
ALWAYS_INLINE Result UnmapInsecureMemory(::ams::svc::Address address, ::ams::svc::Size size) {
R_RETURN(::svcUnmapInsecureMemory(reinterpret_cast<void *>(static_cast<uintptr_t>(address)), size));
}
} }
#endif #endif

View file

@ -19,6 +19,24 @@
namespace ams::os::impl { 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<u64>::max());
return rand % (max + 1);
}
template<std::unsigned_integral AddressType, std::unsigned_integral SizeType> template<std::unsigned_integral AddressType, std::unsigned_integral SizeType>
AddressSpaceAllocatorBase<AddressType, SizeType>::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) { AddressSpaceAllocatorBase<AddressType, SizeType>::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. */ /* Check pre-conditions. */
@ -64,7 +82,7 @@ namespace ams::os::impl {
} }
template<std::unsigned_integral AddressType, std::unsigned_integral SizeType> template<std::unsigned_integral AddressType, std::unsigned_integral SizeType>
AddressType AddressSpaceAllocatorBase<AddressType, SizeType>::AllocateSpace(SizeType size, SizeType align, SizeType align_offset) { AddressType AddressSpaceAllocatorBase<AddressType, SizeType>::AllocateSpace(SizeType size, SizeType align, SizeType align_offset, AddressSpaceGenerateRandomFunction generate_random) {
/* Check pre-conditions. */ /* Check pre-conditions. */
AMS_ASSERT(align > 0); AMS_ASSERT(align > 0);
AMS_ASSERT((align_offset & ~(align - 1)) == 0); AMS_ASSERT((align_offset & ~(align - 1)) == 0);
@ -98,7 +116,9 @@ namespace ams::os::impl {
std::scoped_lock lk(m_critical_section); std::scoped_lock lk(m_critical_section);
/* Determine a random page. */ /* 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); 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. */ /* Check that the page is not forbidden. */

View file

@ -45,7 +45,7 @@ namespace ams::os::impl {
public: public:
AddressSpaceAllocatorBase(u64 start_address, u64 end_address, SizeType guard_size, const AddressSpaceAllocatorForbiddenRegion *forbidden_regions, size_t num_forbidden_regions); 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); bool CheckGuardSpace(AddressType address, SizeType size, SizeType guard_size);
private: private:
@ -54,6 +54,8 @@ namespace ams::os::impl {
virtual bool CheckFreeSpace(AddressType address, SizeType size) = 0; virtual bool CheckFreeSpace(AddressType address, SizeType size) = 0;
}; };
u64 AddressSpaceAllocatorDefaultGenerateRandom(u64 max);
} }
#if defined(ATMOSPHERE_OS_HORIZON) #if defined(ATMOSPHERE_OS_HORIZON)

View file

@ -55,16 +55,16 @@ namespace ams::os::impl {
} }
#endif #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. */ /* Try to allocate a large-aligned space, if we can. */
if (align_offset || (size / AslrSpaceLargeAlign) != 0) { 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; return large_align;
} }
} }
/* Allocate a page-aligned space. */ /* 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) { bool CheckGuardSpace(AddressType address, SizeType size) {
@ -72,11 +72,11 @@ namespace ams::os::impl {
} }
template<typename MapFunction, typename UnmapFunction> template<typename MapFunction, typename UnmapFunction>
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. */ /* Try to map up to 64 times. */
for (auto i = 0; i < 64; ++i) { for (auto i = 0; i < 64; ++i) {
/* Reserve space to map the memory. */ /* 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) { if (map_address == 0) {
break; break;
} }
@ -105,6 +105,11 @@ namespace ams::os::impl {
/* We failed to map. */ /* We failed to map. */
R_THROW(os::ResultOutOfAddressSpace()); R_THROW(os::ResultOutOfAddressSpace());
} }
template<typename MapFunction, typename UnmapFunction>
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<AddressSpaceAllocator, AslrSpaceManagerImpl>; using AslrSpaceManager = AslrSpaceManagerTemplate<AddressSpaceAllocator, AslrSpaceManagerImpl>;

View file

@ -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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <stratosphere.hpp>
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);
};
}

View file

@ -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 <http://www.gnu.org/licenses/>.
*/
#include <stratosphere.hpp>
#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));
}
}

View file

@ -20,7 +20,7 @@ namespace ams::os::impl {
class ProcessCodeMemoryImpl { class ProcessCodeMemoryImpl {
public: 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); static Result Unmap(NativeHandle handle, u64 process_code_address, const ProcessMemoryRegion *regions, size_t num_regions);
}; };

View file

@ -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. */ /* Get the total process memory region size. */
const size_t total_size = GetTotalProcessMemoryRegionSize(regions, num_regions); const size_t total_size = GetTotalProcessMemoryRegionSize(regions, num_regions);
@ -64,7 +64,7 @@ namespace ams::os::impl {
/* Map at a random address. */ /* Map at a random address. */
u64 mapped_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 { [handle, regions, num_regions](u64 map_address, u64 map_size) -> Result {
AMS_UNUSED(map_size); AMS_UNUSED(map_size);
@ -107,7 +107,8 @@ namespace ams::os::impl {
R_ABORT_UNLESS(ProcessCodeMemoryImpl::Unmap(handle, map_address, regions, num_regions)); R_ABORT_UNLESS(ProcessCodeMemoryImpl::Unmap(handle, map_address, regions, num_regions));
}, },
total_size, 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. */ /* Set the output address. */

View file

@ -20,7 +20,7 @@ namespace ams::os::impl {
class ProcessMemoryImpl { class ProcessMemoryImpl {
public: 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 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); static Result SetMemoryPermission(NativeHandle handle, u64 process_address, u64 size, MemoryPermission perm);

View file

@ -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. */ /* Map at a random address. */
uintptr_t mapped_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 { [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_TRY_CATCH(svc::MapProcessMemory(map_address, handle, process_address, map_size)) {
R_CONVERT(svc::ResultOutOfResource, os::ResultOutOfResource()) R_CONVERT(svc::ResultOutOfResource, os::ResultOutOfResource())
@ -49,7 +49,8 @@ namespace ams::os::impl {
return ProcessMemoryImpl::Unmap(reinterpret_cast<void *>(map_address), handle, process_address, map_size); return ProcessMemoryImpl::Unmap(reinterpret_cast<void *>(map_address), handle, process_address, map_size);
}, },
size, size,
process_address process_address,
generate_random
)); ));
/* Return the address we mapped at. */ /* Return the address we mapped at. */

View file

@ -43,7 +43,7 @@ namespace ams::os::impl {
} }
void *AllocateStackGuardSpace(size_t size) { void *AllocateStackGuardSpace(size_t size) {
return reinterpret_cast<void *>(m_allocator.AllocateSpace(size, os::MemoryPageSize, 0)); return reinterpret_cast<void *>(m_allocator.AllocateSpace(size, os::MemoryPageSize, 0, os::impl::AddressSpaceAllocatorDefaultGenerateRandom));
} }
bool CheckGuardSpace(uintptr_t address, size_t size) { bool CheckGuardSpace(uintptr_t address, size_t size) {

View file

@ -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 <http://www.gnu.org/licenses/>.
*/
#include <stratosphere.hpp>
#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);
}
}

View file

@ -62,6 +62,11 @@ namespace ams::os {
return GetReference(event->impl).Clear(); 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) { void InitializeMultiWaitHolder(MultiWaitHolderType *multi_wait_holder, InterruptEventType *event) {
AMS_ASSERT(event->state == InterruptEventType::State_Initialized); AMS_ASSERT(event->state == InterruptEventType::State_Initialized);

View file

@ -18,8 +18,8 @@
namespace ams::os { namespace ams::os {
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) {
R_RETURN(::ams::os::impl::ProcessCodeMemoryImpl::Map(out, handle, regions, num_regions)); 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) { Result UnmapProcessCodeMemory(NativeHandle handle, u64 process_code_address, const ProcessMemoryRegion *regions, size_t num_regions) {

View file

@ -18,8 +18,8 @@
namespace ams::os { 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) {
R_RETURN(::ams::os::impl::ProcessMemoryImpl::Map(out, handle, process_address, process_size)); 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) { void UnmapProcessMemory(void *mapped_memory, NativeHandle handle, u64 process_address, size_t process_size) {

View file

@ -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(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(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(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(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)) HANDLER(0x64, Result, LegacyContinueDebugEvent, INPUT(::ams::svc::Handle, debug_handle), INPUT(uint32_t, flags), INPUT(uint64_t, thread_id))

View file

@ -399,6 +399,15 @@ namespace ams::ldr {
R_SUCCEED(); 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) { Result DecideAddressSpaceLayout(ProcessInfo *out, svc::CreateProcessParameter *out_param, const NsoHeader *nso_headers, const bool *has_nso, const ArgumentStore::Entry *argument) {
/* Clear output. */ /* Clear output. */
out->args_address = 0; out->args_address = 0;
@ -468,8 +477,7 @@ namespace ams::ldr {
uintptr_t aslr_slide = 0; uintptr_t aslr_slide = 0;
size_t free_size = (aslr_size - total_size); size_t free_size = (aslr_size - total_size);
if (out_param->flags & svc::CreateProcessFlag_EnableAslr) { if (out_param->flags & svc::CreateProcessFlag_EnableAslr) {
/* Nintendo uses MT19937 (not os::GenerateRandomBytes), but we'll just use TinyMT for now. */ aslr_slide = GenerateSecureRandom(free_size / os::MemoryBlockUnitSize) * os::MemoryBlockUnitSize;
aslr_slide = os::GenerateRandomU64(free_size / os::MemoryBlockUnitSize) * os::MemoryBlockUnitSize;
} }
/* Set out. */ /* Set out. */
@ -527,7 +535,7 @@ namespace ams::ldr {
{ {
/* Map the process memory. */ /* Map the process memory. */
void *mapped_memory = nullptr; 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); }; ON_SCOPE_EXIT { os::UnmapProcessMemory(mapped_memory, process_handle, nso_address, nso_size); };
const uintptr_t map_address = reinterpret_cast<uintptr_t>(mapped_memory); const uintptr_t map_address = reinterpret_cast<uintptr_t>(mapped_memory);
@ -590,7 +598,7 @@ namespace ams::ldr {
/* Write argument data into memory. */ /* Write argument data into memory. */
{ {
void *map_address = nullptr; 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); }; ON_SCOPE_EXIT { os::UnmapProcessMemory(map_address, process_info->process_handle, process_info->args_address, process_info->args_size); };
ProgramArguments *args = static_cast<ProgramArguments *>(map_address); ProgramArguments *args = static_cast<ProgramArguments *>(map_address);

View file

@ -15,7 +15,7 @@
"filesystem_access": { "filesystem_access": {
"permissions": "0xFFFFFFFFFFFFFFFF" "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"], "service_host": ["ldr:ro", "ro:dmnt", "ro:1"],
"kernel_capabilities": [{ "kernel_capabilities": [{
"type": "kernel_flags", "type": "kernel_flags",

View file

@ -15,6 +15,7 @@
*/ */
#include <stratosphere.hpp> #include <stratosphere.hpp>
#include "ro_nro_utils.hpp" #include "ro_nro_utils.hpp"
#include "ro_random.hpp"
namespace ams::ro::impl { 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); 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. */ /* 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_CONVERT(os::ResultOutOfAddressSpace, ro::ResultOutOfAddressSpace())
} R_END_TRY_CATCH; } R_END_TRY_CATCH;

View file

@ -15,6 +15,7 @@
*/ */
#include <stratosphere.hpp> #include <stratosphere.hpp>
#include "ro_nrr_utils.hpp" #include "ro_nrr_utils.hpp"
#include "ro_random.hpp"
#include "ro_service_impl.hpp" #include "ro_service_impl.hpp"
namespace ams::ro::impl { namespace ams::ro::impl {
@ -198,7 +199,7 @@ namespace ams::ro::impl {
/* Re-map the nrr as code memory in the destination process. */ /* Re-map the nrr as code memory in the destination process. */
u64 code_address = 0; u64 code_address = 0;
const os::ProcessMemoryRegion region = { nrr_heap_address, nrr_heap_size }; 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_CONVERT(os::ResultOutOfAddressSpace, ro::ResultOutOfAddressSpace())
} R_END_TRY_CATCH; } R_END_TRY_CATCH;
@ -207,7 +208,7 @@ namespace ams::ro::impl {
/* Map the nrr in our process. */ /* Map the nrr in our process. */
void *mapped_memory = nullptr; 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_CONVERT(os::ResultOutOfAddressSpace, ro::ResultOutOfAddressSpace())
} R_END_TRY_CATCH; } R_END_TRY_CATCH;

View file

@ -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 <http://www.gnu.org/licenses/>.
*/
#include <stratosphere.hpp>
#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);
}
}

View file

@ -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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <stratosphere.hpp>
namespace ams::ro::impl {
u64 GenerateSecureRandom(u64 max);
}

View file

@ -17,6 +17,7 @@
#include "ro_nrr_utils.hpp" #include "ro_nrr_utils.hpp"
#include "ro_nro_utils.hpp" #include "ro_nro_utils.hpp"
#include "ro_patcher.hpp" #include "ro_patcher.hpp"
#include "ro_random.hpp"
#include "ro_service_impl.hpp" #include "ro_service_impl.hpp"
namespace ams::ro::impl { 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) { 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. */ /* Map the NRO. */
void *mapped_memory = nullptr; 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_CONVERT(os::ResultOutOfAddressSpace, ro::ResultOutOfAddressSpace())
} R_END_TRY_CATCH; } R_END_TRY_CATCH;

View file

@ -51,26 +51,26 @@ namespace ams {
}; };
constexpr sm::ServiceName RandomServiceName = sm::ServiceName::Encode("csrng"); 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 sm::ServiceName GeneralServiceName = sm::ServiceName::Encode("spl:");
constexpr size_t DeprecatedMaxSessions = 13; 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 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 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 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 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 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. */ /* csrng, spl:, spl:mig, spl:ssl, spl:es, spl:fs, spl:manu. */
/* TODO: Consider max sessions enforcement? */ /* TODO: Consider max sessions enforcement? */