From 8524f284fd38e19a4168769bccba2e4e89feac5b Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Thu, 26 Apr 2018 20:27:52 -0600 Subject: [PATCH] Loader: Implement ldr:ro->LoadNRR(). NOTE: No sigchecks, at the moment. --- stratosphere/loader/source/ldr_map.hpp | 62 ++++++++++++++++++- stratosphere/loader/source/ldr_nro.cpp | 28 +++++++++ stratosphere/loader/source/ldr_nro.hpp | 33 ++++++++++ .../loader/source/ldr_registration.cpp | 9 +-- .../loader/source/ldr_registration.hpp | 18 ++---- stratosphere/loader/source/ldr_ro_service.cpp | 18 +++++- 6 files changed, 143 insertions(+), 25 deletions(-) create mode 100644 stratosphere/loader/source/ldr_nro.cpp create mode 100644 stratosphere/loader/source/ldr_nro.hpp diff --git a/stratosphere/loader/source/ldr_map.hpp b/stratosphere/loader/source/ldr_map.hpp index 52948f371..3a0c3885f 100644 --- a/stratosphere/loader/source/ldr_map.hpp +++ b/stratosphere/loader/source/ldr_map.hpp @@ -1,8 +1,6 @@ #pragma once #include -#include "ldr_registration.hpp" - class MapUtils { public: struct AddressSpaceInfo { @@ -69,4 +67,64 @@ class AutoCloseMap { this->mapped_address = NULL; } } +}; + +struct MappedCodeMemory { + Handle process_handle; + u64 base_address; + u64 size; + u64 code_memory_address; + void *mapped_address; + + bool IsActive() { + return this->mapped_address != NULL; + } + + /* Utility functions. */ + Result Open(Handle process_h, bool is_64_bit_address_space, u64 address, u64 size) { + Result rc; + u64 try_address; + if (this->IsActive()) { + return 0x19009; + } + + this->process_handle = process_h; + this->base_address = address; + this->size = size; + + if (R_FAILED((rc = MapUtils::MapCodeMemoryForProcess(process_h, is_64_bit_address_space, address, size, &this->code_memory_address)))) { + goto CODE_MEMORY_OPEN_END; + } + + if (R_FAILED(rc = MapUtils::LocateSpaceForMap(&try_address, size))) { + goto CODE_MEMORY_OPEN_END; + } + + if (R_FAILED((rc = svcMapProcessMemory((void *)try_address, process_h, try_address, size)))) { + goto CODE_MEMORY_OPEN_END; + } + + this->mapped_address = (void *)try_address; + + CODE_MEMORY_OPEN_END: + if (R_FAILED(rc)) { + if (this->code_memory_address && R_FAILED(svcUnmapProcessCodeMemory(this->process_handle, this->code_memory_address, this->base_address, this->size))) { + /* TODO: panic(). */ + } + *this = (const MappedCodeMemory){0}; + } + return rc; + } + + void Close() { + if (this->IsActive()) { + if (R_FAILED(svcUnmapProcessMemory(this->mapped_address, this->process_handle, this->base_address, this->size))) { + /* TODO: panic(). */ + } + if (R_FAILED(svcUnmapProcessCodeMemory(this->process_handle, this->code_memory_address, this->base_address, this->size))) { + /* TODO: panic(). */ + } + *this = (const MappedCodeMemory){0}; + } + } }; \ No newline at end of file diff --git a/stratosphere/loader/source/ldr_nro.cpp b/stratosphere/loader/source/ldr_nro.cpp new file mode 100644 index 000000000..611223b16 --- /dev/null +++ b/stratosphere/loader/source/ldr_nro.cpp @@ -0,0 +1,28 @@ +#include +#include +#include +#include +#include +#include "ldr_nro.hpp" +#include "ldr_map.hpp" +#include "ldr_random.hpp" + +Result NroUtils::ValidateNrrHeader(NrrHeader *header, u64 size, u64 title_id_min) { + if (header->magic != MAGIC_NRR0) { + return 0x6A09; + } + if (header->nrr_size != size) { + return 0xA409; + } + + /* TODO: Check NRR signature. */ + if (false) { + return 0x6C09; + } + + if (header->title_id_min != title_id_min) { + return 0x6A09; + } + + return 0x0; +} \ No newline at end of file diff --git a/stratosphere/loader/source/ldr_nro.hpp b/stratosphere/loader/source/ldr_nro.hpp new file mode 100644 index 000000000..ef39d41ae --- /dev/null +++ b/stratosphere/loader/source/ldr_nro.hpp @@ -0,0 +1,33 @@ +#pragma once +#include +#include + +#define MAGIC_NRO0 0x304F524E +#define MAGIC_NRR0 0x3052524E + +class NroUtils { + public: + struct NrrHeader { + u32 magic; + u32 _0x4; + u32 _0x8; + u32 _0xC; + u64 title_id_mask; + u64 title_id_pattern; + u64 _0x20; + u64 _0x28; + u8 modulus[0x100]; + u8 fixed_key_signature[0x100]; + u8 nrr_signature[0x100]; + u64 title_id_min; + u32 nrr_size; + u32 _0x33C; + u32 hash_offset; + u32 num_hashes; + u64 _0x348; + }; + + + static_assert(sizeof(NrrHeader) == 0x350, "Incorrectly defined NrrHeader!"); + static Result ValidateNrrHeader(NrrHeader *header, u64 size, u64 title_id_min); +}; \ No newline at end of file diff --git a/stratosphere/loader/source/ldr_registration.cpp b/stratosphere/loader/source/ldr_registration.cpp index 0299dbc64..a952174c2 100644 --- a/stratosphere/loader/source/ldr_registration.cpp +++ b/stratosphere/loader/source/ldr_registration.cpp @@ -104,7 +104,7 @@ void Registration::AddNsoInfo(u64 index, u64 base_address, u64 size, const unsig } -Result Registration::AddNrrInfo(u64 index, u64 base_address, u64 size, u64 code_memory_address, u64 loader_address) { +Result Registration::AddNrrInfo(u64 index, MappedCodeMemory *nrr_info) { Registration::Process *target_process = GetProcess(index); if (target_process == NULL) { /* TODO: panic() */ @@ -112,11 +112,8 @@ Result Registration::AddNrrInfo(u64 index, u64 base_address, u64 size, u64 code_ } for (unsigned int i = 0; i < NSO_INFO_MAX; i++) { - if (!target_process->nrr_infos[i].in_use) { - target_process->nrr_infos[i].info.base_address = base_address; - target_process->nrr_infos[i].info.size = size; - target_process->nrr_infos[i].info.code_memory_address = code_memory_address; - target_process->nrr_infos[i].info.loader_address = loader_address; + if (!target_process->nrr_infos[i].IsActive()) { + target_process->nrr_infos[i] = *nrr_info; return 0; } } diff --git a/stratosphere/loader/source/ldr_registration.hpp b/stratosphere/loader/source/ldr_registration.hpp index 53deb2aa5..713d56b48 100644 --- a/stratosphere/loader/source/ldr_registration.hpp +++ b/stratosphere/loader/source/ldr_registration.hpp @@ -1,6 +1,8 @@ #pragma once #include +#include "ldr_map.hpp" + #define REGISTRATION_LIST_MAX (0x40) #define NSO_INFO_MAX (0x20) @@ -19,18 +21,6 @@ class Registration { NsoInfo info; }; - struct NrrInfo { - u64 base_address; - u64 size; - u64 code_memory_address; - u64 loader_address; - }; - - struct NrrInfoHolder { - bool in_use; - NrrInfo info; - }; - struct TidSid { u64 title_id; FsStorageId storage_id; @@ -44,7 +34,7 @@ class Registration { u64 title_id_min; Registration::TidSid tid_sid; Registration::NsoInfoHolder nso_infos[NSO_INFO_MAX]; - Registration::NrrInfoHolder nrr_infos[NRR_INFO_MAX]; + MappedCodeMemory nrr_infos[NRR_INFO_MAX]; void *owner_ro_service; }; @@ -61,6 +51,6 @@ class Registration { static bool UnregisterIndex(u64 index); static void SetProcessIdTidMinAndIs64BitAddressSpace(u64 index, u64 process_id, u64 tid_min, bool is_64_bit_addspace); static void AddNsoInfo(u64 index, u64 base_address, u64 size, const unsigned char *build_id); - static Result AddNrrInfo(u64 index, u64 base_address, u64 size, u64 code_memory_address, u64 loader_address); + static Result AddNrrInfo(u64 index, MappedCodeMemory *nrr_info); static Result GetNsoInfosForProcessId(NsoInfo *out, u32 max_out, u64 process_id, u32 *num_written); }; diff --git a/stratosphere/loader/source/ldr_ro_service.cpp b/stratosphere/loader/source/ldr_ro_service.cpp index ff4ad97df..2512d94d7 100644 --- a/stratosphere/loader/source/ldr_ro_service.cpp +++ b/stratosphere/loader/source/ldr_ro_service.cpp @@ -5,6 +5,7 @@ #include "ldr_ro_service.hpp" #include "ldr_registration.hpp" #include "ldr_map.hpp" +#include "ldr_nro.hpp" Result RelocatableObjectsService::dispatch(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, u8 *pointer_buffer, size_t pointer_buffer_size) { Result rc = 0xF601; @@ -44,7 +45,8 @@ std::tuple RelocatableObjectsService::unload_nro(PidDescriptor pid_desc, std::tuple RelocatableObjectsService::load_nrr(PidDescriptor pid_desc, u64 nrr_address, u64 nrr_size) { Result rc; - Registration::Process *target_proc; + Registration::Process *target_proc = NULL; + MappedCodeMemory nrr_info = {0}; if (!this->has_initialized || this->process_id != pid_desc.pid) { rc = 0xAE09; goto LOAD_NRR_END; @@ -65,11 +67,21 @@ std::tuple RelocatableObjectsService::load_nrr(PidDescriptor pid_desc, u } target_proc->owner_ro_service = this; + if (R_FAILED((rc = nrr_info.Open(this->process_handle, target_proc->is_64_bit_addspace, nrr_address, nrr_size)))) { + goto LOAD_NRR_END; + } - /* TODO: Implement remainder of fucntion */ - rc = 0xDED09; + rc = NroUtils::ValidateNrrHeader((NroUtils::NrrHeader *)nrr_info.mapped_address, nrr_size, target_proc->title_id_min); + if (R_SUCCEEDED(rc)) { + Registration::AddNrrInfo(target_proc->index, &nrr_info); + } LOAD_NRR_END: + if (R_FAILED(rc)) { + if (nrr_info.IsActive()) { + nrr_info.Close(); + } + } return std::make_tuple(rc); }