strat: remove map namespace, svc: add address space defs

This commit is contained in:
Michael Scire
2021-10-05 12:22:34 -07:00
parent 69777cf792
commit 719ead824e
17 changed files with 643 additions and 494 deletions

View File

@@ -0,0 +1,21 @@
/*
* 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 {
}

View File

@@ -0,0 +1,83 @@
/*
* 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_map_utils.hpp"
namespace ams::ro::impl {
namespace {
ALWAYS_INLINE u64 GetCurrentProcessInfo(svc::InfoType info_type) {
u64 value;
R_ABORT_UNLESS(svc::GetInfo(std::addressof(value), info_type, svc::PseudoHandle::CurrentProcess, 0));
return value;
}
}
Result SearchFreeRegion(uintptr_t *out, size_t mapping_size) {
/* Get address space extents. */
const uintptr_t heap_start = GetCurrentProcessInfo(svc::InfoType_HeapRegionAddress);
const size_t heap_size = GetCurrentProcessInfo(svc::InfoType_HeapRegionSize);
const uintptr_t alias_start = GetCurrentProcessInfo(svc::InfoType_AliasRegionAddress);
const size_t alias_size = GetCurrentProcessInfo(svc::InfoType_AliasRegionSize);
const uintptr_t aslr_start = GetCurrentProcessInfo(svc::InfoType_AslrRegionAddress);
const size_t aslr_size = GetCurrentProcessInfo(svc::InfoType_AslrRegionSize);
/* Iterate upwards to find a free region. */
uintptr_t address = aslr_start;
while (true) {
/* Declare variables for memory querying. */
svc::MemoryInfo mem_info;
svc::PageInfo page_info;
/* Check that we're still within bounds. */
R_UNLESS(address < address + mapping_size, ro::ResultOutOfAddressSpace());
/* If we're within the heap region, skip to the end of the heap region. */
if (heap_size != 0 && !(address + mapping_size - 1 < heap_start || heap_start + heap_size - 1 < address)) {
R_UNLESS(address < heap_start + heap_size, ro::ResultOutOfAddressSpace());
address = heap_start + heap_size;
continue;
}
/* If we're within the alias region, skip to the end of the alias region. */
if (alias_size != 0 && !(address + mapping_size - 1 < alias_start || alias_start + alias_size - 1 < address)) {
R_UNLESS(address < alias_start + alias_size, ro::ResultOutOfAddressSpace());
address = alias_start + alias_size;
continue;
}
/* Get the current memory range. */
R_ABORT_UNLESS(svc::QueryMemory(std::addressof(mem_info), std::addressof(page_info), address));
/* If the memory range is free and big enough, use it. */
if (mem_info.state == svc::MemoryState_Free && mapping_size <= ((mem_info.addr + mem_info.size) - address)) {
*out = address;
return ResultSuccess();
}
/* Check that we can advance. */
R_UNLESS(address < mem_info.addr + mem_info.size, ro::ResultOutOfAddressSpace());
R_UNLESS(mem_info.addr + mem_info.size - 1 < aslr_start + aslr_size - 1, ro::ResultOutOfAddressSpace());
/* Advance. */
address = mem_info.addr + mem_info.size;
}
}
}

View File

@@ -0,0 +1,176 @@
/*
* 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 {
constexpr inline auto RetrySearchCount = 512;
Result SearchFreeRegion(uintptr_t *out, size_t mapping_size);
class ProcessRegionInfo {
NON_COPYABLE(ProcessRegionInfo);
NON_MOVEABLE(ProcessRegionInfo);
private:
static constexpr size_t StackGuardSize = 4 * os::MemoryPageSize;
private:
u64 m_heap_start;
u64 m_heap_size;
u64 m_alias_start;
u64 m_alias_size;
u64 m_aslr_start;
u64 m_aslr_size;
public:
ProcessRegionInfo(os::NativeHandle process) {
R_ABORT_UNLESS(svc::GetInfo(std::addressof(m_heap_start), svc::InfoType_HeapRegionAddress, svc::PseudoHandle::CurrentProcess, 0));
R_ABORT_UNLESS(svc::GetInfo(std::addressof(m_heap_size), svc::InfoType_HeapRegionSize, svc::PseudoHandle::CurrentProcess, 0));
R_ABORT_UNLESS(svc::GetInfo(std::addressof(m_alias_start), svc::InfoType_AliasRegionAddress, svc::PseudoHandle::CurrentProcess, 0));
R_ABORT_UNLESS(svc::GetInfo(std::addressof(m_alias_size), svc::InfoType_AliasRegionSize, svc::PseudoHandle::CurrentProcess, 0));
R_ABORT_UNLESS(svc::GetInfo(std::addressof(m_aslr_start), svc::InfoType_AslrRegionAddress, svc::PseudoHandle::CurrentProcess, 0));
R_ABORT_UNLESS(svc::GetInfo(std::addressof(m_aslr_size), svc::InfoType_AslrRegionSize, svc::PseudoHandle::CurrentProcess, 0));
}
u64 GetAslrRegion(u64 mapping_size) const {
/* If we can, look for a region. */
if (mapping_size <= m_aslr_size) {
for (auto i = 0; i < RetrySearchCount; ++i) {
/* Get a random address. */
const u64 address = m_aslr_start + os::GenerateRandomU64((m_aslr_size - mapping_size) / os::MemoryPageSize) * os::MemoryPageSize;
/* Check that it's not contained within heap. */
if (m_heap_size != 0 && !(address + mapping_size - 1 < m_heap_start || m_heap_start + m_heap_size - 1 < address)) {
continue;
}
/* Check that it's not contained within alias. */
if (m_alias_size != 0 && !(address + mapping_size - 1 < m_alias_start || m_alias_start + m_alias_size - 1 < address)) {
continue;
}
/* Return the address. */
}
}
/* We failed to find a region. */
return 0;
}
bool CanEmplaceGuardSpaces(os::NativeHandle process, u64 address, u64 size) {
/* NOTE: Nintendo does not check the results of these svc calls. */
svc::MemoryInfo mem_info;
svc::PageInfo page_info;
/* Check for guard availability before the region. */
R_ABORT_UNLESS(svc::QueryProcessMemory(std::addressof(mem_info), std::addressof(page_info), process, address - 1));
if (!(mem_info.state == svc::MemoryState_Free && mem_info.addr <= address - StackGuardSize)) {
return false;
}
/* Check for guard availability after the region. */
R_ABORT_UNLESS(svc::QueryProcessMemory(std::addressof(mem_info), std::addressof(page_info), process, address + size));
if (!(mem_info.state == svc::MemoryState_Free && address + size + StackGuardSize <= mem_info.addr + mem_info.size)) {
return false;
}
return true;
}
};
class AutoCloseMap {
private:
Result m_result;
uintptr_t m_map_address;
os::NativeHandle m_handle;
u64 m_address;
u64 m_size;
public:
AutoCloseMap(uintptr_t map, os::NativeHandle handle, u64 addr, u64 size) : m_map_address(map), m_handle(handle), m_address(addr), m_size(size) {
m_result = svc::MapProcessMemory(m_map_address, m_handle, m_address, m_size);
}
~AutoCloseMap() {
if (m_handle != os::InvalidNativeHandle && R_SUCCEEDED(m_result)) {
R_ABORT_UNLESS(svc::UnmapProcessMemory(m_map_address, m_handle, m_address, m_size));
}
}
Result GetResult() const {
return m_result;
}
bool IsSuccess() const {
return R_SUCCEEDED(m_result);
}
void Cancel() {
m_handle = os::InvalidNativeHandle;
}
};
class MappedCodeMemory {
NON_COPYABLE(MappedCodeMemory);
private:
os::NativeHandle m_handle;
Result m_result;
u64 m_dst_address;
u64 m_src_address;
u64 m_size;
public:
constexpr MappedCodeMemory() : m_handle(os::InvalidNativeHandle), m_result(ro::ResultInternalError()), m_dst_address(0), m_src_address(0), m_size(0) {
/* ... */
}
MappedCodeMemory(svc::Handle handle, u64 dst, u64 src, u64 size) : m_handle(handle), m_dst_address(dst), m_src_address(src), m_size(size) {
m_result = svc::MapProcessCodeMemory(m_handle, m_dst_address, m_src_address, m_size);
}
~MappedCodeMemory() {
if (m_handle != os::InvalidNativeHandle && R_SUCCEEDED(m_result) && m_size > 0) {
R_ABORT_UNLESS(svc::UnmapProcessCodeMemory(m_handle, m_dst_address, m_src_address, m_size));
}
}
MappedCodeMemory(MappedCodeMemory &&rhs) : m_handle(rhs.m_handle), m_result(rhs.m_result), m_dst_address(rhs.m_dst_address), m_src_address(rhs.m_src_address), m_size(rhs.m_size) {
rhs.m_handle = os::InvalidNativeHandle;
}
MappedCodeMemory &operator=(MappedCodeMemory &&rhs) {
m_handle = rhs.m_handle;
m_result = rhs.m_result;
m_dst_address = rhs.m_dst_address;
m_src_address = rhs.m_src_address;
m_size = rhs.m_size;
rhs.m_handle = os::InvalidNativeHandle;
return *this;
}
Result GetResult() const {
return m_result;
}
bool IsSuccess() const {
return R_SUCCEEDED(m_result);
}
void Cancel() {
m_handle = os::InvalidNativeHandle;
}
};
}

View File

@@ -15,53 +15,63 @@
*/
#include <stratosphere.hpp>
#include "ro_nro_utils.hpp"
#include "ro_map_utils.hpp"
namespace ams::ro::impl {
namespace {
constexpr size_t MaxMapRetries = 0x200;
}
Result MapNro(u64 *out_base_address, os::NativeHandle process_handle, u64 nro_heap_address, u64 nro_heap_size, u64 bss_heap_address, u64 bss_heap_size) {
map::MappedCodeMemory nro_mcm(ResultInternalError{});
map::MappedCodeMemory bss_mcm(ResultInternalError{});
/* Re-map the NRO/BSS as code memory in the destination process. */
MappedCodeMemory nro_mcm;
MappedCodeMemory bss_mcm;
ProcessRegionInfo region_info(process_handle);
u64 base_address;
{
const u64 memory_size = nro_heap_size + bss_heap_size;
int i;
for (i = 0; i < RetrySearchCount; ++i) {
/* Get a random address for the nro. */
base_address = region_info.GetAslrRegion(memory_size);
R_UNLESS(base_address != 0, ro::ResultOutOfAddressSpace());
/* Map the NRO, and map the BSS immediately after it. */
size_t i;
for (i = 0; i < MaxMapRetries; i++) {
map::MappedCodeMemory tmp_nro_mcm(ResultInternalError{});
R_TRY(map::MapCodeMemoryInProcess(tmp_nro_mcm, process_handle, nro_heap_address, nro_heap_size));
base_address = tmp_nro_mcm.GetDstAddress();
if (bss_heap_size > 0) {
map::MappedCodeMemory tmp_bss_mcm(process_handle, base_address + nro_heap_size, bss_heap_address, bss_heap_size);
R_TRY_CATCH(tmp_bss_mcm.GetResult()) {
R_CATCH(svc::ResultInvalidCurrentMemory) {
continue;
}
/* Map the NRO, retrying if random address was invalid. */
MappedCodeMemory tmp_nro_mcm(process_handle, base_address, nro_heap_address, nro_heap_size);
R_TRY_CATCH(tmp_nro_mcm.GetResult()) {
R_CATCH(svc::ResultInvalidCurrentMemory) { continue; }
} R_END_TRY_CATCH;
if (!map::CanAddGuardRegionsInProcess(process_handle, base_address, nro_heap_size + bss_heap_size)) {
continue;
/* Handle bss. */
if (bss_heap_size > 0) {
/* Map BSS, retrying if random address was invalid. */
MappedCodeMemory tmp_bss_mcm(process_handle, base_address + nro_heap_size, bss_heap_address, bss_heap_size);
R_TRY_CATCH(tmp_bss_mcm.GetResult()) {
R_CATCH(svc::ResultInvalidCurrentMemory) { continue; }
} R_END_TRY_CATCH;
/* Check that we can have guard spaces. */
if (!region_info.CanEmplaceGuardSpaces(process_handle, base_address, memory_size)) {
continue;
}
/* We succeeded, so save the bss memory. */
bss_mcm = std::move(tmp_bss_mcm);
} else {
/* Check that we can have guard spaces. */
if (!region_info.CanEmplaceGuardSpaces(process_handle, base_address, memory_size)) {
continue;
}
}
bss_mcm = std::move(tmp_bss_mcm);
} else {
if (!map::CanAddGuardRegionsInProcess(process_handle, base_address, nro_heap_size)) {
continue;
}
/* We succeeded, so save the code memory. */
nro_mcm = std::move(tmp_nro_mcm);
break;
}
nro_mcm = std::move(tmp_nro_mcm);
break;
}
R_UNLESS(i < MaxMapRetries, ResultOutOfAddressSpace());
/* Invalidation here actually prevents them from unmapping at scope exit. */
nro_mcm.Invalidate();
bss_mcm.Invalidate();
R_UNLESS(i != RetrySearchCount, ro::ResultOutOfAddressSpace());
}
/* Cancel the automatic closing of our mappings. */
nro_mcm.Cancel();
bss_mcm.Cancel();
*out_base_address = base_address;
return ResultSuccess();

View File

@@ -15,6 +15,7 @@
*/
#include <stratosphere.hpp>
#include "ro_nrr_utils.hpp"
#include "ro_map_utils.hpp"
#include "ro_service_impl.hpp"
namespace ams::ro::impl {
@@ -135,7 +136,7 @@ namespace ams::ro::impl {
R_UNLESS(crypto::VerifyRsa2048PssSha256(sig, sig_size, mod, mod_size, exp, exp_size, msg, msg_size), ro::ResultNotAuthorized());
/* Check ProgramId pattern is valid. */
R_UNLESS(header->IsProgramIdValid(), ResultNotAuthorized());
R_UNLESS(header->IsProgramIdValid(), ro::ResultNotAuthorized());
return ResultSuccess();
}
@@ -159,10 +160,10 @@ namespace ams::ro::impl {
Result ValidateNrr(const NrrHeader *header, u64 size, ncm::ProgramId program_id, NrrKind nrr_kind, bool enforce_nrr_kind) {
/* Check magic. */
R_UNLESS(header->IsMagicValid(), ResultInvalidNrr());
R_UNLESS(header->IsMagicValid(), ro::ResultInvalidNrr());
/* Check size. */
R_UNLESS(header->GetSize() == size, ResultInvalidSize());
R_UNLESS(header->GetSize() == size, ro::ResultInvalidSize());
/* Only perform checks if we must. */
const bool ease_nro_restriction = ShouldEaseNroRestriction();
@@ -180,11 +181,11 @@ namespace ams::ro::impl {
R_TRY(ValidateNrrSignature(header));
/* Check program id. */
R_UNLESS(header->GetProgramId() == program_id, ResultInvalidNrr());
R_UNLESS(header->GetProgramId() == program_id, ro::ResultInvalidNrr());
/* Check nrr kind. */
if (hos::GetVersion() >= hos::Version_7_0_0 && enforce_nrr_kind) {
R_UNLESS(header->GetNrrKind() == nrr_kind, ResultInvalidNrrKind());
R_UNLESS(header->GetNrrKind() == nrr_kind, ro::ResultInvalidNrrKind());
}
}
@@ -195,30 +196,55 @@ namespace ams::ro::impl {
/* Utilities for working with NRRs. */
Result MapAndValidateNrr(NrrHeader **out_header, u64 *out_mapped_code_address, void *out_hash, size_t out_hash_size, os::NativeHandle process_handle, ncm::ProgramId program_id, u64 nrr_heap_address, u64 nrr_heap_size, NrrKind nrr_kind, bool enforce_nrr_kind) {
map::MappedCodeMemory nrr_mcm(ResultInternalError{});
/* Re-map the NRR as code memory in the destination process. */
MappedCodeMemory nrr_mcm;
ProcessRegionInfo region_info(process_handle);
u64 code_address;
{
int i;
for (i = 0; i < RetrySearchCount; ++i) {
/* Get a random address for the nrr. */
code_address = region_info.GetAslrRegion(nrr_heap_size);
R_UNLESS(code_address != 0, ro::ResultOutOfAddressSpace());
/* First, map the NRR. */
R_TRY(map::MapCodeMemoryInProcess(nrr_mcm, process_handle, nrr_heap_address, nrr_heap_size));
/* Map the code memory, retrying if the random address was invalid. */
MappedCodeMemory tmp_mcm(process_handle, code_address, nrr_heap_address, nrr_heap_size);
R_TRY_CATCH(tmp_mcm.GetResult()) {
R_CATCH(svc::ResultInvalidCurrentMemory) { continue; }
} R_END_TRY_CATCH;
const u64 code_address = nrr_mcm.GetDstAddress();
/* Check that we can have guard spaces. */
if (!region_info.CanEmplaceGuardSpaces(process_handle, code_address, nrr_heap_size)) {
continue;
}
/* We succeeded, so save the code memory. */
nrr_mcm = std::move(tmp_mcm);
break;
}
R_UNLESS(i != RetrySearchCount, ro::ResultOutOfAddressSpace());
}
/* Decide where to map the NRR in our process. */
uintptr_t map_address;
R_UNLESS(R_SUCCEEDED(map::LocateMappableSpace(&map_address, nrr_heap_size)), ResultOutOfAddressSpace());
R_UNLESS(R_SUCCEEDED(SearchFreeRegion(std::addressof(map_address), nrr_heap_size)), ro::ResultOutOfAddressSpace());
/* Nintendo...does not check the return value of this map. We will check, instead of aborting if it fails. */
map::AutoCloseMap nrr_map(map_address, process_handle, code_address, nrr_heap_size);
/* NOTE: Nintendo does not check the return value of this map. We will check, instead of aborting if it fails. */
AutoCloseMap nrr_map(map_address, process_handle, code_address, nrr_heap_size);
R_TRY(nrr_map.GetResult());
NrrHeader *nrr_header = reinterpret_cast<NrrHeader *>(map_address);
R_TRY(ValidateNrr(nrr_header, nrr_heap_size, program_id, nrr_kind, enforce_nrr_kind));
/* Invalidation here actually prevents them from unmapping at scope exit. */
nrr_map.Invalidate();
nrr_mcm.Invalidate();
/* Cancel the automatic closing of our mappings. */
nrr_map.Cancel();
nrr_mcm.Cancel();
/* Save a copy of the hash that we verified. */
crypto::GenerateSha256Hash(out_hash, out_hash_size, nrr_header->GetSignedArea(), nrr_header->GetSignedAreaSize());
*out_header = nrr_header;
*out_header = nrr_header;
*out_mapped_code_address = code_address;
return ResultSuccess();
}

View File

@@ -14,6 +14,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stratosphere.hpp>
#include "ro_map_utils.hpp"
#include "ro_nrr_utils.hpp"
#include "ro_nro_utils.hpp"
#include "ro_patcher.hpp"
@@ -99,7 +100,7 @@ namespace ams::ro::impl {
return ResultSuccess();
}
}
return ResultNotRegistered();
return ro::ResultNotRegistered();
}
Result GetFreeNrrInfo(NrrInfo **out) {
@@ -111,7 +112,7 @@ namespace ams::ro::impl {
return ResultSuccess();
}
}
return ResultTooManyNrr();
return ro::ResultTooManyNrr();
}
Result GetNroInfoByAddress(NroInfo **out, u64 nro_address) {
@@ -123,7 +124,7 @@ namespace ams::ro::impl {
return ResultSuccess();
}
}
return ResultNotLoaded();
return ro::ResultNotLoaded();
}
Result GetNroInfoByModuleId(NroInfo **out, const ModuleId *module_id) {
@@ -135,7 +136,7 @@ namespace ams::ro::impl {
return ResultSuccess();
}
}
return ResultNotLoaded();
return ro::ResultNotLoaded();
}
Result GetFreeNroInfo(NroInfo **out) {
@@ -147,7 +148,7 @@ namespace ams::ro::impl {
return ResultSuccess();
}
}
return ResultTooManyNro();
return ro::ResultTooManyNro();
}
Result ValidateHasNroHash(const NroHeader *nro_header) const {
@@ -192,21 +193,21 @@ namespace ams::ro::impl {
return ResultSuccess();
}
return ResultNotAuthorized();
return ro::ResultNotAuthorized();
}
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) {
/* Find space to map the NRO. */
uintptr_t map_address;
R_UNLESS(R_SUCCEEDED(map::LocateMappableSpace(&map_address, expected_nro_size)), ResultOutOfAddressSpace());
R_UNLESS(R_SUCCEEDED(SearchFreeRegion(std::addressof(map_address), expected_nro_size)), ro::ResultOutOfAddressSpace());
/* Actually map the NRO. */
map::AutoCloseMap nro_map(map_address, this->process_handle, base_address, expected_nro_size);
AutoCloseMap nro_map(map_address, this->process_handle, base_address, expected_nro_size);
R_TRY(nro_map.GetResult());
/* Validate header. */
const NroHeader *header = reinterpret_cast<const NroHeader *>(map_address);
R_UNLESS(header->IsMagicValid(), ResultInvalidNro());
R_UNLESS(header->IsMagicValid(), ro::ResultInvalidNro());
/* Read sizes from header. */
const u64 nro_size = header->GetSize();
@@ -219,31 +220,31 @@ namespace ams::ro::impl {
const u64 bss_size = header->GetBssSize();
/* Validate sizes meet expected. */
R_UNLESS(nro_size == expected_nro_size, ResultInvalidNro());
R_UNLESS(bss_size == expected_bss_size, ResultInvalidNro());
R_UNLESS(nro_size == expected_nro_size, ro::ResultInvalidNro());
R_UNLESS(bss_size == expected_bss_size, ro::ResultInvalidNro());
/* Validate all sizes are aligned. */
R_UNLESS(util::IsAligned(text_size, os::MemoryPageSize), ResultInvalidNro());
R_UNLESS(util::IsAligned(ro_size, os::MemoryPageSize), ResultInvalidNro());
R_UNLESS(util::IsAligned(rw_size, os::MemoryPageSize), ResultInvalidNro());
R_UNLESS(util::IsAligned(bss_size, os::MemoryPageSize), ResultInvalidNro());
R_UNLESS(util::IsAligned(text_size, os::MemoryPageSize), ro::ResultInvalidNro());
R_UNLESS(util::IsAligned(ro_size, os::MemoryPageSize), ro::ResultInvalidNro());
R_UNLESS(util::IsAligned(rw_size, os::MemoryPageSize), ro::ResultInvalidNro());
R_UNLESS(util::IsAligned(bss_size, os::MemoryPageSize), ro::ResultInvalidNro());
/* Validate sections are in order. */
R_UNLESS(text_ofs <= ro_ofs, ResultInvalidNro());
R_UNLESS(ro_ofs <= rw_ofs, ResultInvalidNro());
R_UNLESS(text_ofs <= ro_ofs, ro::ResultInvalidNro());
R_UNLESS(ro_ofs <= rw_ofs, ro::ResultInvalidNro());
/* Validate sections are sequential and contiguous. */
R_UNLESS(text_ofs == 0, ResultInvalidNro());
R_UNLESS(text_ofs + text_size == ro_ofs, ResultInvalidNro());
R_UNLESS(ro_ofs + ro_size == rw_ofs, ResultInvalidNro());
R_UNLESS(rw_ofs + rw_size == nro_size, ResultInvalidNro());
R_UNLESS(text_ofs == 0, ro::ResultInvalidNro());
R_UNLESS(text_ofs + text_size == ro_ofs, ro::ResultInvalidNro());
R_UNLESS(ro_ofs + ro_size == rw_ofs, ro::ResultInvalidNro());
R_UNLESS(rw_ofs + rw_size == nro_size, ro::ResultInvalidNro());
/* Verify NRO hash. */
R_TRY(this->ValidateHasNroHash(header));
/* Check if NRO has already been loaded. */
const ModuleId *module_id = header->GetModuleId();
R_UNLESS(R_FAILED(this->GetNroInfoByModuleId(nullptr, module_id)), ResultAlreadyLoaded());
R_UNLESS(R_FAILED(this->GetNroInfoByModuleId(nullptr, module_id)), ro::ResultAlreadyLoaded());
/* Apply patches to NRO. */
LocateAndApplyIpsPatchesToModule(module_id, reinterpret_cast<u8 *>(map_address), nro_size);
@@ -327,17 +328,17 @@ namespace ams::ro::impl {
}
constexpr inline Result ValidateAddressAndNonZeroSize(u64 address, u64 size) {
R_UNLESS(util::IsAligned(address, os::MemoryPageSize), ResultInvalidAddress());
R_UNLESS(size != 0, ResultInvalidSize());
R_UNLESS(util::IsAligned(size, os::MemoryPageSize), ResultInvalidSize());
R_UNLESS(address < address + size, ResultInvalidSize());
R_UNLESS(util::IsAligned(address, os::MemoryPageSize), ro::ResultInvalidAddress());
R_UNLESS(size != 0, ro::ResultInvalidSize());
R_UNLESS(util::IsAligned(size, os::MemoryPageSize), ro::ResultInvalidSize());
R_UNLESS(address < address + size, ro::ResultInvalidSize());
return ResultSuccess();
}
constexpr inline Result ValidateAddressAndSize(u64 address, u64 size) {
R_UNLESS(util::IsAligned(address, os::MemoryPageSize), ResultInvalidAddress());
R_UNLESS(util::IsAligned(size, os::MemoryPageSize), ResultInvalidSize());
R_UNLESS(size == 0 || address < address + size, ResultInvalidSize());
R_UNLESS(util::IsAligned(address, os::MemoryPageSize), ro::ResultInvalidAddress());
R_UNLESS(util::IsAligned(size, os::MemoryPageSize), ro::ResultInvalidSize());
R_UNLESS(size == 0 || address < address + size, ro::ResultInvalidSize());
return ResultSuccess();
}
@@ -378,14 +379,14 @@ namespace ams::ro::impl {
{
/* Validate handle is a valid process handle. */
os::ProcessId handle_pid;
R_UNLESS(R_SUCCEEDED(os::GetProcessId(&handle_pid, process_handle.GetOsHandle())), ResultInvalidProcess());
R_UNLESS(R_SUCCEEDED(os::GetProcessId(&handle_pid, process_handle.GetOsHandle())), ro::ResultInvalidProcess());
/* Validate process id. */
R_UNLESS(handle_pid == process_id, ResultInvalidProcess());
R_UNLESS(handle_pid == process_id, ro::ResultInvalidProcess());
}
/* Check if a process context already exists. */
R_UNLESS(GetContextByProcessId(process_id) == nullptr, ResultInvalidSession());
R_UNLESS(GetContextByProcessId(process_id) == nullptr, ro::ResultInvalidSession());
/* Allocate a context to manage the process handle. */
*out_context_id = AllocateContext(process_handle.GetOsHandle(), process_id);
@@ -396,8 +397,8 @@ namespace ams::ro::impl {
Result ValidateProcess(size_t context_id, os::ProcessId process_id) {
const ProcessContext *ctx = GetContextById(context_id);
R_UNLESS(ctx != nullptr, ResultInvalidProcess());
R_UNLESS(ctx->process_id == process_id, ResultInvalidProcess());
R_UNLESS(ctx != nullptr, ro::ResultInvalidProcess());
R_UNLESS(ctx->process_id == process_id, ro::ResultInvalidProcess());
return ResultSuccess();
}
@@ -453,7 +454,7 @@ namespace ams::ro::impl {
AMS_ABORT_UNLESS(context != nullptr);
/* Validate address. */
R_UNLESS(util::IsAligned(nrr_address, os::MemoryPageSize), ResultInvalidAddress());
R_UNLESS(util::IsAligned(nrr_address, os::MemoryPageSize), ro::ResultInvalidAddress());
/* Check the NRR is loaded. */
NrrInfo *nrr_info = nullptr;
@@ -479,8 +480,8 @@ namespace ams::ro::impl {
R_TRY(ValidateAddressAndSize(bss_address, bss_size));
const u64 total_size = nro_size + bss_size;
R_UNLESS(total_size >= nro_size, ResultInvalidSize());
R_UNLESS(total_size >= bss_size, ResultInvalidSize());
R_UNLESS(total_size >= nro_size, ro::ResultInvalidSize());
R_UNLESS(total_size >= bss_size, ro::ResultInvalidSize());
/* Check we have space for a new NRO. */
NroInfo *nro_info = nullptr;
@@ -521,7 +522,7 @@ namespace ams::ro::impl {
AMS_ABORT_UNLESS(context != nullptr);
/* Validate address. */
R_UNLESS(util::IsAligned(nro_address, os::MemoryPageSize), ResultInvalidAddress());
R_UNLESS(util::IsAligned(nro_address, os::MemoryPageSize), ro::ResultInvalidAddress());
/* Check the NRO is loaded. */
NroInfo *nro_info = nullptr;