mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-12-22 12:21:18 +00:00
strat: remove map namespace, svc: add address space defs
This commit is contained in:
parent
69777cf792
commit
719ead824e
17 changed files with 643 additions and 494 deletions
|
@ -22,19 +22,19 @@ namespace ams::kern {
|
|||
constexpr uintptr_t Invalid = std::numeric_limits<uintptr_t>::max();
|
||||
|
||||
constexpr KAddressSpaceInfo AddressSpaceInfos[] = {
|
||||
{ 32, 2_MB, 1_GB - 2_MB, KAddressSpaceInfo::Type_MapSmall, },
|
||||
{ 32, 1_GB, 4_GB - 1_GB, KAddressSpaceInfo::Type_MapLarge, },
|
||||
{ 32, Invalid, 1_GB, KAddressSpaceInfo::Type_Heap, },
|
||||
{ 32, Invalid, 1_GB, KAddressSpaceInfo::Type_Alias, },
|
||||
{ 36, 128_MB, 2_GB - 128_MB, KAddressSpaceInfo::Type_MapSmall, },
|
||||
{ 36, 2_GB, 64_GB - 2_GB, KAddressSpaceInfo::Type_MapLarge, },
|
||||
{ 36, Invalid, 6_GB, KAddressSpaceInfo::Type_Heap, },
|
||||
{ 36, Invalid, 6_GB, KAddressSpaceInfo::Type_Alias, },
|
||||
{ 39, 128_MB, 512_GB - 128_MB, KAddressSpaceInfo::Type_Map39Bit, },
|
||||
{ 39, Invalid, 64_GB, KAddressSpaceInfo::Type_MapSmall, },
|
||||
{ 39, Invalid, 6_GB, KAddressSpaceInfo::Type_Heap, },
|
||||
{ 39, Invalid, 64_GB, KAddressSpaceInfo::Type_Alias, },
|
||||
{ 39, Invalid, 2_GB, KAddressSpaceInfo::Type_Stack, },
|
||||
{ 32, ams::svc::AddressSmallMap32Start, ams::svc::AddressSmallMap32Size, KAddressSpaceInfo::Type_MapSmall, },
|
||||
{ 32, ams::svc::AddressLargeMap32Start, ams::svc::AddressLargeMap32Size, KAddressSpaceInfo::Type_MapLarge, },
|
||||
{ 32, Invalid, ams::svc::AddressMemoryRegionHeap32Size, KAddressSpaceInfo::Type_Heap, },
|
||||
{ 32, Invalid, ams::svc::AddressMemoryRegionAlias32Size, KAddressSpaceInfo::Type_Alias, },
|
||||
{ 36, ams::svc::AddressSmallMap36Start, ams::svc::AddressSmallMap36Size, KAddressSpaceInfo::Type_MapSmall, },
|
||||
{ 36, ams::svc::AddressLargeMap36Start, ams::svc::AddressLargeMap36Size, KAddressSpaceInfo::Type_MapLarge, },
|
||||
{ 36, Invalid, ams::svc::AddressMemoryRegionHeap36Size, KAddressSpaceInfo::Type_Heap, },
|
||||
{ 36, Invalid, ams::svc::AddressMemoryRegionAlias36Size, KAddressSpaceInfo::Type_Alias, },
|
||||
{ 39, ams::svc::AddressMap39Start, ams::svc::AddressMap39Size, KAddressSpaceInfo::Type_Map39Bit, },
|
||||
{ 39, Invalid, ams::svc::AddressMemoryRegionSmall39Size, KAddressSpaceInfo::Type_MapSmall, },
|
||||
{ 39, Invalid, ams::svc::AddressMemoryRegionHeap39Size, KAddressSpaceInfo::Type_Heap, },
|
||||
{ 39, Invalid, ams::svc::AddressMemoryRegionAlias39Size, KAddressSpaceInfo::Type_Alias, },
|
||||
{ 39, Invalid, ams::svc::AddressMemoryRegionStack39Size, KAddressSpaceInfo::Type_Stack, },
|
||||
};
|
||||
|
||||
constexpr bool IsAllowedIndexForAddress(size_t index) {
|
||||
|
|
|
@ -66,7 +66,6 @@
|
|||
#include <stratosphere/ldr.hpp>
|
||||
#include <stratosphere/lr.hpp>
|
||||
#include <stratosphere/lm.hpp>
|
||||
#include <stratosphere/map.hpp>
|
||||
#include <stratosphere/ncm.hpp>
|
||||
#include <stratosphere/nim.hpp>
|
||||
#include <stratosphere/ns.hpp>
|
||||
|
|
|
@ -1,28 +0,0 @@
|
|||
/*
|
||||
* 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/map/map_types.hpp>
|
||||
|
||||
namespace ams::map {
|
||||
|
||||
/* Public API. */
|
||||
Result GetProcessAddressSpaceInfo(AddressSpaceInfo *out, os::NativeHandle process_h);
|
||||
Result LocateMappableSpace(uintptr_t *out_address, size_t size);
|
||||
Result MapCodeMemoryInProcess(MappedCodeMemory &out_mcm, os::NativeHandle process_handle, uintptr_t base_address, size_t size);
|
||||
bool CanAddGuardRegionsInProcess(os::NativeHandle process_handle, uintptr_t address, size_t size);
|
||||
|
||||
}
|
|
@ -1,123 +0,0 @@
|
|||
/*
|
||||
* 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 <vapours.hpp>
|
||||
#include <stratosphere/os/os_native_handle.hpp>
|
||||
|
||||
namespace ams::map {
|
||||
|
||||
/* Types. */
|
||||
struct AddressSpaceInfo {
|
||||
uintptr_t heap_base;
|
||||
size_t heap_size;
|
||||
uintptr_t heap_end;
|
||||
uintptr_t alias_base;
|
||||
size_t alias_size;
|
||||
uintptr_t alias_end;
|
||||
uintptr_t aslr_base;
|
||||
size_t aslr_size;
|
||||
uintptr_t aslr_end;
|
||||
};
|
||||
|
||||
static constexpr uintptr_t AslrBase32Bit = 0x0000200000ul;
|
||||
static constexpr size_t AslrSize32Bit = 0x003FE00000ul;
|
||||
static constexpr uintptr_t AslrBase64BitDeprecated = 0x0008000000ul;
|
||||
static constexpr size_t AslrSize64BitDeprecated = 0x0078000000ul;
|
||||
static constexpr uintptr_t AslrBase64Bit = 0x0008000000ul;
|
||||
static constexpr size_t AslrSize64Bit = 0x7FF8000000ul;
|
||||
|
||||
class AutoCloseMap {
|
||||
private:
|
||||
os::NativeHandle process_handle;
|
||||
Result result;
|
||||
uintptr_t mapped_address;
|
||||
uintptr_t base_address;
|
||||
size_t size;
|
||||
public:
|
||||
AutoCloseMap(uintptr_t mp, os::NativeHandle p_h, uintptr_t ba, size_t sz) : process_handle(p_h), mapped_address(mp), base_address(ba), size(sz) {
|
||||
this->result = svc::MapProcessMemory(this->mapped_address, this->process_handle, this->base_address, this->size);
|
||||
}
|
||||
|
||||
~AutoCloseMap() {
|
||||
if (this->process_handle != os::InvalidNativeHandle && R_SUCCEEDED(this->result)) {
|
||||
R_ABORT_UNLESS(svc::UnmapProcessMemory(this->mapped_address, this->process_handle, this->base_address, this->size));
|
||||
}
|
||||
}
|
||||
|
||||
Result GetResult() const {
|
||||
return this->result;
|
||||
}
|
||||
|
||||
bool IsSuccess() const {
|
||||
return R_SUCCEEDED(this->result);
|
||||
}
|
||||
|
||||
void Invalidate() {
|
||||
this->process_handle = os::InvalidNativeHandle;
|
||||
}
|
||||
};
|
||||
|
||||
class MappedCodeMemory {
|
||||
private:
|
||||
os::NativeHandle process_handle;
|
||||
Result result;
|
||||
uintptr_t dst_address;
|
||||
uintptr_t src_address;
|
||||
size_t size;
|
||||
public:
|
||||
MappedCodeMemory(Result init_res) : process_handle(os::InvalidNativeHandle), result(init_res), dst_address(0), src_address(0), size(0) {
|
||||
/* ... */
|
||||
}
|
||||
|
||||
MappedCodeMemory(os::NativeHandle p_h, uintptr_t dst, uintptr_t src, size_t sz) : process_handle(p_h), dst_address(dst), src_address(src), size(sz) {
|
||||
this->result = svc::MapProcessCodeMemory(this->process_handle, this->dst_address, this->src_address, this->size);
|
||||
}
|
||||
|
||||
~MappedCodeMemory() {
|
||||
if (this->process_handle != os::InvalidNativeHandle && R_SUCCEEDED(this->result) && this->size > 0) {
|
||||
R_ABORT_UNLESS(svc::UnmapProcessCodeMemory(this->process_handle, this->dst_address, this->src_address, this->size));
|
||||
}
|
||||
}
|
||||
|
||||
uintptr_t GetDstAddress() const {
|
||||
return this->dst_address;
|
||||
}
|
||||
|
||||
Result GetResult() const {
|
||||
return this->result;
|
||||
}
|
||||
|
||||
bool IsSuccess() const {
|
||||
return R_SUCCEEDED(this->result);
|
||||
}
|
||||
|
||||
void Invalidate() {
|
||||
this->process_handle = os::InvalidNativeHandle;
|
||||
}
|
||||
|
||||
MappedCodeMemory &operator=(MappedCodeMemory &&o) {
|
||||
this->process_handle = o.process_handle;
|
||||
this->result = o.result;
|
||||
this->dst_address = o.dst_address;
|
||||
this->src_address = o.src_address;
|
||||
this->size = o.size;
|
||||
o.Invalidate();
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
|
@ -1,205 +0,0 @@
|
|||
/*
|
||||
* 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>
|
||||
|
||||
namespace ams::map {
|
||||
|
||||
namespace {
|
||||
|
||||
/* Convenience defines. */
|
||||
constexpr size_t GuardRegionSize = 0x4000;
|
||||
constexpr size_t LocateRetryCount = 0x200;
|
||||
|
||||
/* Deprecated/Modern implementations. */
|
||||
Result LocateMappableSpaceDeprecated(uintptr_t *out_address, size_t size) {
|
||||
svc::MemoryInfo mem_info;
|
||||
svc::PageInfo page_info;
|
||||
uintptr_t cur_base = 0;
|
||||
|
||||
AddressSpaceInfo address_space;
|
||||
R_TRY(GetProcessAddressSpaceInfo(&address_space, dd::GetCurrentProcessHandle()));
|
||||
cur_base = address_space.aslr_base;
|
||||
|
||||
do {
|
||||
R_TRY(svc::QueryMemory(&mem_info, &page_info, cur_base));
|
||||
|
||||
if (mem_info.state == svc::MemoryState_Free && mem_info.addr - cur_base + mem_info.size >= size) {
|
||||
*out_address = cur_base;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
const uintptr_t mem_end = mem_info.addr + mem_info.size;
|
||||
R_UNLESS(mem_info.state != svc::MemoryState_Inaccessible, svc::ResultOutOfMemory());
|
||||
R_UNLESS(cur_base <= mem_end, svc::ResultOutOfMemory());
|
||||
R_UNLESS(mem_end <= static_cast<uintptr_t>(std::numeric_limits<s32>::max()), svc::ResultOutOfMemory());
|
||||
|
||||
cur_base = mem_end;
|
||||
} while (true);
|
||||
}
|
||||
|
||||
Result LocateMappableSpaceModern(uintptr_t *out_address, size_t size) {
|
||||
svc::MemoryInfo mem_info;
|
||||
svc::PageInfo page_info;
|
||||
uintptr_t cur_base = 0, cur_end = 0;
|
||||
|
||||
AddressSpaceInfo address_space;
|
||||
R_TRY(GetProcessAddressSpaceInfo(&address_space, dd::GetCurrentProcessHandle()));
|
||||
cur_base = address_space.aslr_base;
|
||||
cur_end = cur_base + size;
|
||||
|
||||
R_UNLESS(cur_base < cur_end, svc::ResultOutOfMemory());
|
||||
|
||||
while (true) {
|
||||
if (address_space.heap_size && (address_space.heap_base <= cur_end - 1 && cur_base <= address_space.heap_end - 1)) {
|
||||
/* If we overlap the heap region, go to the end of the heap region. */
|
||||
R_UNLESS(cur_base != address_space.heap_end, svc::ResultOutOfMemory());
|
||||
cur_base = address_space.heap_end;
|
||||
} else if (address_space.alias_size && (address_space.alias_base <= cur_end - 1 && cur_base <= address_space.alias_end - 1)) {
|
||||
/* If we overlap the alias region, go to the end of the alias region. */
|
||||
R_UNLESS(cur_base != address_space.alias_end, svc::ResultOutOfMemory());
|
||||
cur_base = address_space.alias_end;
|
||||
} else {
|
||||
R_ABORT_UNLESS(svc::QueryMemory(&mem_info, &page_info, cur_base));
|
||||
if (mem_info.state == svc::MemoryState_Free && mem_info.addr - cur_base + mem_info.size >= size) {
|
||||
*out_address = cur_base;
|
||||
return ResultSuccess();
|
||||
}
|
||||
R_UNLESS(cur_base < mem_info.addr + mem_info.size, svc::ResultOutOfMemory());
|
||||
|
||||
cur_base = mem_info.addr + mem_info.size;
|
||||
R_UNLESS(cur_base < address_space.aslr_end, svc::ResultOutOfMemory());
|
||||
}
|
||||
cur_end = cur_base + size;
|
||||
R_UNLESS(cur_base < cur_base + size, svc::ResultOutOfMemory());
|
||||
}
|
||||
}
|
||||
|
||||
Result MapCodeMemoryInProcessDeprecated(MappedCodeMemory &out_mcm, os::NativeHandle process_handle, uintptr_t base_address, size_t size) {
|
||||
AddressSpaceInfo address_space;
|
||||
R_TRY(GetProcessAddressSpaceInfo(&address_space, process_handle));
|
||||
|
||||
R_UNLESS(size <= address_space.aslr_size, ro::ResultOutOfAddressSpace());
|
||||
|
||||
uintptr_t try_address;
|
||||
for (unsigned int i = 0; i < LocateRetryCount; i++) {
|
||||
try_address = address_space.aslr_base + (os::GenerateRandomU64(static_cast<u64>(address_space.aslr_size - size) / os::MemoryPageSize) * os::MemoryPageSize);
|
||||
|
||||
MappedCodeMemory tmp_mcm(process_handle, try_address, base_address, size);
|
||||
R_TRY_CATCH(tmp_mcm.GetResult()) {
|
||||
R_CATCH(svc::ResultInvalidCurrentMemory) { continue; }
|
||||
} R_END_TRY_CATCH;
|
||||
|
||||
if (!CanAddGuardRegionsInProcess(process_handle, try_address, size)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* We're done searching. */
|
||||
out_mcm = std::move(tmp_mcm);
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
return ro::ResultOutOfAddressSpace();
|
||||
}
|
||||
|
||||
Result MapCodeMemoryInProcessModern(MappedCodeMemory &out_mcm, os::NativeHandle process_handle, uintptr_t base_address, size_t size) {
|
||||
AddressSpaceInfo address_space;
|
||||
R_TRY(GetProcessAddressSpaceInfo(&address_space, process_handle));
|
||||
|
||||
R_UNLESS(size <= address_space.aslr_size, ro::ResultOutOfAddressSpace());
|
||||
|
||||
uintptr_t try_address;
|
||||
for (unsigned int i = 0; i < LocateRetryCount; i++) {
|
||||
while (true) {
|
||||
try_address = address_space.aslr_base + (os::GenerateRandomU64(static_cast<u64>(address_space.aslr_size - size) / os::MemoryPageSize) * os::MemoryPageSize);
|
||||
if (address_space.heap_size && (address_space.heap_base <= try_address + size - 1 && try_address <= address_space.heap_end - 1)) {
|
||||
continue;
|
||||
}
|
||||
if (address_space.alias_size && (address_space.alias_base <= try_address + size - 1 && try_address <= address_space.alias_end - 1)) {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
MappedCodeMemory tmp_mcm(process_handle, try_address, base_address, size);
|
||||
R_TRY_CATCH(tmp_mcm.GetResult()) {
|
||||
R_CATCH(svc::ResultInvalidCurrentMemory) { continue; }
|
||||
} R_END_TRY_CATCH;
|
||||
|
||||
if (!CanAddGuardRegionsInProcess(process_handle, try_address, size)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* We're done searching. */
|
||||
out_mcm = std::move(tmp_mcm);
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
return ro::ResultOutOfAddressSpace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Public API. */
|
||||
Result GetProcessAddressSpaceInfo(AddressSpaceInfo *out, os::NativeHandle process_h) {
|
||||
/* Clear output. */
|
||||
std::memset(out, 0, sizeof(*out));
|
||||
|
||||
/* Retrieve info from kernel. */
|
||||
R_TRY(svc::GetInfo(&out->heap_base, svc::InfoType_HeapRegionAddress, process_h, 0));
|
||||
R_TRY(svc::GetInfo(&out->heap_size, svc::InfoType_HeapRegionSize, process_h, 0));
|
||||
R_TRY(svc::GetInfo(&out->alias_base, svc::InfoType_AliasRegionAddress, process_h, 0));
|
||||
R_TRY(svc::GetInfo(&out->alias_size, svc::InfoType_AliasRegionSize, process_h, 0));
|
||||
R_TRY(svc::GetInfo(&out->aslr_base, svc::InfoType_AslrRegionAddress, process_h, 0));
|
||||
R_TRY(svc::GetInfo(&out->aslr_size, svc::InfoType_AslrRegionSize, process_h, 0));
|
||||
|
||||
out->heap_end = out->heap_base + out->heap_size;
|
||||
out->alias_end = out->alias_base + out->alias_size;
|
||||
out->aslr_end = out->aslr_base + out->aslr_size;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result LocateMappableSpace(uintptr_t *out_address, size_t size) {
|
||||
if (hos::GetVersion() >= hos::Version_2_0_0) {
|
||||
return LocateMappableSpaceModern(out_address, size);
|
||||
} else {
|
||||
return LocateMappableSpaceDeprecated(out_address, size);
|
||||
}
|
||||
}
|
||||
|
||||
Result MapCodeMemoryInProcess(MappedCodeMemory &out_mcm, os::NativeHandle process_handle, uintptr_t base_address, size_t size) {
|
||||
if (hos::GetVersion() >= hos::Version_2_0_0) {
|
||||
return MapCodeMemoryInProcessModern(out_mcm, process_handle, base_address, size);
|
||||
} else {
|
||||
return MapCodeMemoryInProcessDeprecated(out_mcm, process_handle, base_address, size);
|
||||
}
|
||||
}
|
||||
|
||||
bool CanAddGuardRegionsInProcess(os::NativeHandle process_handle, uintptr_t address, size_t size) {
|
||||
svc::MemoryInfo mem_info;
|
||||
svc::PageInfo page_info;
|
||||
|
||||
/* Nintendo doesn't validate SVC return values at all. */
|
||||
/* TODO: Should we allow these to fail? */
|
||||
R_ABORT_UNLESS(svc::QueryProcessMemory(&mem_info, &page_info, process_handle, address - 1));
|
||||
if (mem_info.state == svc::MemoryState_Free && address - GuardRegionSize >= mem_info.addr) {
|
||||
R_ABORT_UNLESS(svc::QueryProcessMemory(&mem_info, &page_info, process_handle, address + size));
|
||||
return mem_info.state == svc::MemoryState_Free && address + size + GuardRegionSize <= mem_info.addr + mem_info.size;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
|
@ -21,5 +21,6 @@
|
|||
|
||||
#include <vapours/svc/svc_types.hpp>
|
||||
#include <vapours/svc/svc_definitions.hpp>
|
||||
#include <vapours/svc/svc_memory_map.hpp>
|
||||
#include <vapours/svc/svc_version.hpp>
|
||||
#include <vapours/svc/ipc/svc_message_buffer.hpp>
|
||||
|
|
100
libraries/libvapours/include/vapours/svc/svc_memory_map.hpp
Normal file
100
libraries/libvapours/include/vapours/svc/svc_memory_map.hpp
Normal file
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
* 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 <vapours/common.hpp>
|
||||
|
||||
namespace ams::svc {
|
||||
|
||||
#if defined(ATMOSPHERE_ARCH_ARM64)
|
||||
|
||||
constexpr inline size_t AddressMemoryRegionSmall32Size = 1_GB;
|
||||
constexpr inline size_t AddressMemoryRegionLarge32Size = 4_GB - AddressMemoryRegionSmall32Size;
|
||||
constexpr inline size_t AddressMemoryRegionHeap32Size = 1_GB;
|
||||
constexpr inline size_t AddressMemoryRegionAlias32Size = 1_GB;
|
||||
|
||||
constexpr inline size_t AddressMemoryRegionSmall36Size = 2_GB;
|
||||
constexpr inline size_t AddressMemoryRegionLarge36Size = 64_GB - AddressMemoryRegionSmall36Size;
|
||||
constexpr inline size_t AddressMemoryRegionHeap36Size = 6_GB;
|
||||
constexpr inline size_t AddressMemoryRegionAlias36Size = 6_GB;
|
||||
|
||||
constexpr inline size_t AddressMemoryRegionSmall39Size = 64_GB;
|
||||
constexpr inline size_t AddressMemoryRegionHeap39Size = 6_GB;
|
||||
constexpr inline size_t AddressMemoryRegionAlias39Size = 64_GB;
|
||||
constexpr inline size_t AddressMemoryRegionStack39Size = 2_GB;
|
||||
|
||||
constexpr inline size_t AddressMemoryRegion39Size = 512_GB;
|
||||
|
||||
#elif defined(ATMOSPHERE_ARCH_ARM)
|
||||
|
||||
constexpr inline size_t AddressMemoryRegionSmall32Size = 512_MB;
|
||||
constexpr inline size_t AddressMemoryRegionLarge32Size = 2_GB - AddressMemoryRegionSmall32Size;
|
||||
constexpr inline size_t AddressMemoryRegionHeap32Size = 1_GB;
|
||||
constexpr inline size_t AddressMemoryRegionAlias32Size = 512_MB;
|
||||
|
||||
constexpr inline size_t AddressMemoryRegionSmall36Size = 0;
|
||||
constexpr inline size_t AddressMemoryRegionLarge36Size = 0;
|
||||
constexpr inline size_t AddressMemoryRegionHeap36Size = 0;
|
||||
constexpr inline size_t AddressMemoryRegionAlias36Size = 0;
|
||||
|
||||
constexpr inline size_t AddressMemoryRegionSmall39Size = 0;
|
||||
constexpr inline size_t AddressMemoryRegionHeap39Size = 0;
|
||||
constexpr inline size_t AddressMemoryRegionAlias39Size = 0;
|
||||
constexpr inline size_t AddressMemoryRegionStack39Size = 0;
|
||||
|
||||
constexpr inline size_t AddressMemoryRegion39Size = 0;
|
||||
|
||||
#else
|
||||
|
||||
#error "Unknown architecture for svc::AddressMemoryRegion*Size"
|
||||
|
||||
#endif
|
||||
|
||||
constexpr inline size_t AddressNullGuard32Size = 2_MB;
|
||||
constexpr inline size_t AddressNullGuard64Size = 128_MB;
|
||||
|
||||
constexpr inline uintptr_t AddressMemoryRegionSmall32Start = 0;
|
||||
constexpr inline uintptr_t AddressMemoryRegionSmall32End = AddressMemoryRegionSmall32Start + AddressMemoryRegionSmall32Size;
|
||||
|
||||
constexpr inline uintptr_t AddressMemoryRegionLarge32Start = AddressMemoryRegionSmall32End;
|
||||
constexpr inline uintptr_t AddressMemoryRegionLarge32End = AddressMemoryRegionLarge32Start + AddressMemoryRegionLarge32Size;
|
||||
|
||||
constexpr inline uintptr_t AddressSmallMap32Start = AddressMemoryRegionSmall32Start + AddressNullGuard32Size;
|
||||
constexpr inline uintptr_t AddressSmallMap32End = AddressMemoryRegionSmall32End;
|
||||
constexpr inline size_t AddressSmallMap32Size = AddressSmallMap32End - AddressSmallMap32Start;
|
||||
|
||||
constexpr inline uintptr_t AddressLargeMap32Start = AddressMemoryRegionLarge32Start;
|
||||
constexpr inline uintptr_t AddressLargeMap32End = AddressMemoryRegionLarge32End;
|
||||
constexpr inline size_t AddressLargeMap32Size = AddressLargeMap32End - AddressLargeMap32Start;
|
||||
|
||||
constexpr inline uintptr_t AddressMemoryRegionSmall36Start = 0;
|
||||
constexpr inline uintptr_t AddressMemoryRegionSmall36End = AddressMemoryRegionSmall36Start + AddressMemoryRegionSmall36Size;
|
||||
|
||||
constexpr inline uintptr_t AddressMemoryRegionLarge36Start = AddressMemoryRegionSmall36End;
|
||||
constexpr inline uintptr_t AddressMemoryRegionLarge36End = AddressMemoryRegionLarge36Start + AddressMemoryRegionLarge36Size;
|
||||
|
||||
constexpr inline uintptr_t AddressSmallMap36Start = AddressMemoryRegionSmall36Start + AddressNullGuard64Size;
|
||||
constexpr inline uintptr_t AddressSmallMap36End = AddressMemoryRegionSmall36End;
|
||||
constexpr inline size_t AddressSmallMap36Size = AddressSmallMap36End - AddressSmallMap36Start;
|
||||
|
||||
constexpr inline uintptr_t AddressLargeMap36Start = AddressMemoryRegionLarge36Start;
|
||||
constexpr inline uintptr_t AddressLargeMap36End = AddressMemoryRegionLarge36End;
|
||||
constexpr inline size_t AddressLargeMap36Size = AddressLargeMap36End - AddressLargeMap36Start;
|
||||
|
||||
constexpr inline uintptr_t AddressMap39Start = 0 + AddressNullGuard64Size;
|
||||
constexpr inline uintptr_t AddressMap39End = AddressMemoryRegion39Size;
|
||||
constexpr inline size_t AddressMap39Size = AddressMap39End - AddressMap39Start;
|
||||
|
||||
}
|
|
@ -810,16 +810,12 @@ namespace ams::dmnt::cheat::impl {
|
|||
R_ABORT_UNLESS_IF_NEW_PROCESS(pm::dmnt::AtmosphereGetProcessInfo(&proc_h, &loc, &status, this->cheat_process_metadata.process_id));
|
||||
this->cheat_process_metadata.program_id = loc.program_id;
|
||||
|
||||
{
|
||||
map::AddressSpaceInfo as_info;
|
||||
R_ABORT_UNLESS(map::GetProcessAddressSpaceInfo(&as_info, proc_h));
|
||||
this->cheat_process_metadata.heap_extents.base = as_info.heap_base;
|
||||
this->cheat_process_metadata.heap_extents.size = as_info.heap_size;
|
||||
this->cheat_process_metadata.alias_extents.base = as_info.alias_base;
|
||||
this->cheat_process_metadata.alias_extents.size = as_info.alias_size;
|
||||
this->cheat_process_metadata.aslr_extents.base = as_info.aslr_base;
|
||||
this->cheat_process_metadata.aslr_extents.size = as_info.aslr_size;
|
||||
}
|
||||
R_ABORT_UNLESS(svc::GetInfo(std::addressof(this->cheat_process_metadata.heap_extents.base), svc::InfoType_HeapRegionAddress, svc::PseudoHandle::CurrentProcess, 0));
|
||||
R_ABORT_UNLESS(svc::GetInfo(std::addressof(this->cheat_process_metadata.heap_extents.size), svc::InfoType_HeapRegionSize, svc::PseudoHandle::CurrentProcess, 0));
|
||||
R_ABORT_UNLESS(svc::GetInfo(std::addressof(this->cheat_process_metadata.alias_extents.base), svc::InfoType_AliasRegionAddress, svc::PseudoHandle::CurrentProcess, 0));
|
||||
R_ABORT_UNLESS(svc::GetInfo(std::addressof(this->cheat_process_metadata.alias_extents.size), svc::InfoType_AliasRegionSize, svc::PseudoHandle::CurrentProcess, 0));
|
||||
R_ABORT_UNLESS(svc::GetInfo(std::addressof(this->cheat_process_metadata.aslr_extents.base), svc::InfoType_AslrRegionAddress, svc::PseudoHandle::CurrentProcess, 0));
|
||||
R_ABORT_UNLESS(svc::GetInfo(std::addressof(this->cheat_process_metadata.aslr_extents.size), svc::InfoType_AslrRegionSize, svc::PseudoHandle::CurrentProcess, 0));
|
||||
|
||||
/* If new process launch, we may not want to actually attach. */
|
||||
if (on_process_launch) {
|
||||
|
|
54
stratosphere/loader/source/ldr_auto_close.hpp
Normal file
54
stratosphere/loader/source/ldr_auto_close.hpp
Normal file
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* 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::ldr {
|
||||
|
||||
class AutoCloseMap {
|
||||
NON_COPYABLE(AutoCloseMap);
|
||||
NON_MOVEABLE(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;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
|
@ -14,6 +14,7 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <stratosphere.hpp>
|
||||
#include "ldr_auto_close.hpp"
|
||||
#include "ldr_capabilities.hpp"
|
||||
#include "ldr_content_management.hpp"
|
||||
#include "ldr_development_manager.hpp"
|
||||
|
@ -367,6 +368,63 @@ namespace ams::ldr {
|
|||
return ResultSuccess();
|
||||
}
|
||||
|
||||
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, svc::ResultOutOfMemory());
|
||||
|
||||
/* 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, svc::ResultOutOfMemory());
|
||||
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, svc::ResultOutOfMemory());
|
||||
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, svc::ResultOutOfMemory());
|
||||
R_UNLESS(mem_info.addr + mem_info.size - 1 < aslr_start + aslr_size - 1, svc::ResultOutOfMemory());
|
||||
|
||||
/* Advance. */
|
||||
address = mem_info.addr + mem_info.size;
|
||||
}
|
||||
}
|
||||
|
||||
Result DecideAddressSpaceLayout(ProcessInfo *out, svc::CreateProcessParameter *out_param, const NsoHeader *nso_headers, const bool *has_nso, const args::ArgumentInfo *arg_info) {
|
||||
/* Clear output. */
|
||||
out->args_address = 0;
|
||||
|
@ -401,39 +459,39 @@ namespace ams::ldr {
|
|||
|
||||
/* Calculate ASLR. */
|
||||
uintptr_t aslr_start = 0;
|
||||
uintptr_t aslr_size = 0;
|
||||
size_t aslr_size = 0;
|
||||
if (hos::GetVersion() >= hos::Version_2_0_0) {
|
||||
switch (out_param->flags & svc::CreateProcessFlag_AddressSpaceMask) {
|
||||
case svc::CreateProcessFlag_AddressSpace32Bit:
|
||||
case svc::CreateProcessFlag_AddressSpace32BitWithoutAlias:
|
||||
aslr_start = map::AslrBase32Bit;
|
||||
aslr_size = map::AslrSize32Bit;
|
||||
aslr_start = svc::AddressSmallMap32Start;
|
||||
aslr_size = svc::AddressSmallMap32Size;
|
||||
break;
|
||||
case svc::CreateProcessFlag_AddressSpace64BitDeprecated:
|
||||
aslr_start = map::AslrBase64BitDeprecated;
|
||||
aslr_size = map::AslrSize64BitDeprecated;
|
||||
aslr_start = svc::AddressSmallMap36Start;
|
||||
aslr_size = svc::AddressSmallMap36Size;
|
||||
break;
|
||||
case svc::CreateProcessFlag_AddressSpace64Bit:
|
||||
aslr_start = map::AslrBase64Bit;
|
||||
aslr_size = map::AslrSize64Bit;
|
||||
aslr_start = svc::AddressMap39Start;
|
||||
aslr_size = svc::AddressMap39Size;
|
||||
break;
|
||||
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||
}
|
||||
} else {
|
||||
/* On 1.0.0, only 2 address space types existed. */
|
||||
if (out_param->flags & svc::CreateProcessFlag_AddressSpace64BitDeprecated) {
|
||||
aslr_start = map::AslrBase64BitDeprecated;
|
||||
aslr_size = map::AslrSize64BitDeprecated;
|
||||
aslr_start = svc::AddressSmallMap36Start;
|
||||
aslr_size = svc::AddressSmallMap36Size;
|
||||
} else {
|
||||
aslr_start = map::AslrBase32Bit;
|
||||
aslr_size = map::AslrSize32Bit;
|
||||
aslr_start = svc::AddressSmallMap32Start;
|
||||
aslr_size = svc::AddressSmallMap32Size;
|
||||
}
|
||||
}
|
||||
R_UNLESS(total_size <= aslr_size, svc::ResultOutOfMemory());
|
||||
|
||||
/* Set Create Process output. */
|
||||
uintptr_t aslr_slide = 0;
|
||||
uintptr_t free_size = (aslr_size - total_size);
|
||||
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;
|
||||
|
@ -450,7 +508,7 @@ namespace ams::ldr {
|
|||
out->args_address += aslr_start;
|
||||
}
|
||||
|
||||
out_param->code_address = aslr_start;
|
||||
out_param->code_address = aslr_start;
|
||||
out_param->code_num_pages = total_size >> 12;
|
||||
|
||||
return ResultSuccess();
|
||||
|
@ -510,8 +568,8 @@ namespace ams::ldr {
|
|||
Result LoadNsoIntoProcessMemory(os::NativeHandle process_handle, fs::FileHandle file, uintptr_t map_address, const NsoHeader *nso_header, uintptr_t nso_address, size_t nso_size) {
|
||||
/* Map and read data from file. */
|
||||
{
|
||||
map::AutoCloseMap mapper(map_address, process_handle, nso_address, nso_size);
|
||||
R_TRY(mapper.GetResult());
|
||||
AutoCloseMap map(map_address, process_handle, nso_address, nso_size);
|
||||
R_TRY(map.GetResult());
|
||||
|
||||
/* Load NSO segments. */
|
||||
R_TRY(LoadNsoSegment(file, &nso_header->segments[NsoHeader::Segment_Text], nso_header->text_compressed_size, nso_header->text_hash, (nso_header->flags & NsoHeader::Flag_CompressedText) != 0,
|
||||
|
@ -562,8 +620,8 @@ namespace ams::ldr {
|
|||
R_TRY(fs::OpenFile(std::addressof(file), GetNsoPath(i), fs::OpenMode_Read));
|
||||
ON_SCOPE_EXIT { fs::CloseFile(file); };
|
||||
|
||||
uintptr_t map_address = 0;
|
||||
R_TRY(map::LocateMappableSpace(&map_address, process_info->nso_size[i]));
|
||||
uintptr_t map_address;
|
||||
R_TRY(SearchFreeRegion(std::addressof(map_address), process_info->nso_size[i]));
|
||||
|
||||
R_TRY(LoadNsoIntoProcessMemory(process_info->process_handle, file, map_address, nso_headers + i, process_info->nso_address[i], process_info->nso_size[i]));
|
||||
}
|
||||
|
@ -573,11 +631,11 @@ namespace ams::ldr {
|
|||
if (arg_info != nullptr) {
|
||||
/* Write argument data into memory. */
|
||||
{
|
||||
uintptr_t map_address = 0;
|
||||
R_TRY(map::LocateMappableSpace(&map_address, process_info->args_size));
|
||||
uintptr_t map_address;
|
||||
R_TRY(SearchFreeRegion(std::addressof(map_address), process_info->args_size));
|
||||
|
||||
map::AutoCloseMap mapper(map_address, process_info->process_handle, process_info->args_address, process_info->args_size);
|
||||
R_TRY(mapper.GetResult());
|
||||
AutoCloseMap map(map_address, process_info->process_handle, process_info->args_address, process_info->args_size);
|
||||
R_TRY(map.GetResult());
|
||||
|
||||
ProgramArguments *args = reinterpret_cast<ProgramArguments *>(map_address);
|
||||
std::memset(args, 0, sizeof(*args));
|
||||
|
|
|
@ -13,8 +13,9 @@
|
|||
* 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>
|
||||
|
||||
#include <stratosphere/map/map_types.hpp>
|
||||
#include <stratosphere/map/map_api.hpp>
|
||||
namespace ams::ro::impl {
|
||||
|
||||
}
|
83
stratosphere/ro/source/impl/ro_map_utils.cpp
Normal file
83
stratosphere/ro/source/impl/ro_map_utils.cpp
Normal 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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
176
stratosphere/ro/source/impl/ro_map_utils.hpp
Normal file
176
stratosphere/ro/source/impl/ro_map_utils.hpp
Normal 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;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
namespace ams::ro {
|
||||
|
||||
Result DebugMonitorService::GetProcessModuleInfo(sf::Out<u32> out_count, const sf::OutArray<LoaderModuleInfo> &out_infos, os::ProcessId process_id) {
|
||||
R_UNLESS(out_infos.GetSize() <= std::numeric_limits<s32>::max(), ResultInvalidSize());
|
||||
R_UNLESS(out_infos.GetSize() <= std::numeric_limits<s32>::max(), ro::ResultInvalidSize());
|
||||
return impl::GetProcessModuleInfo(out_count.GetPointer(), out_infos.GetPointer(), out_infos.GetSize(), process_id);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue