diff --git a/stratosphere/loader/source/ldr_map.hpp b/stratosphere/loader/source/ldr_map.hpp index 7a623b5cd..dea945638 100644 --- a/stratosphere/loader/source/ldr_map.hpp +++ b/stratosphere/loader/source/ldr_map.hpp @@ -151,13 +151,15 @@ struct MappedCodeMemory { return rc; } - void Unmap() { + Result Unmap() { + Result rc = 0; if (this->IsMapped()) { - if (R_FAILED(svcUnmapProcessMemory(this->mapped_address, this->process_handle, this->code_memory_address, this->size))) { + if (R_FAILED((rc = svcUnmapProcessMemory(this->mapped_address, this->process_handle, this->code_memory_address, this->size)))) { /* TODO: panic(). */ } } this->mapped_address = NULL; + return rc; } void Close() { diff --git a/stratosphere/loader/source/ldr_nro.cpp b/stratosphere/loader/source/ldr_nro.cpp index 06d93a464..7bc177dfe 100644 --- a/stratosphere/loader/source/ldr_nro.cpp +++ b/stratosphere/loader/source/ldr_nro.cpp @@ -15,6 +15,7 @@ */ #include +#include #include #include #include @@ -46,16 +47,26 @@ Result NroUtils::ValidateNrrHeader(NrrHeader *header, u64 size, u64 title_id_min } Result NroUtils::LoadNro(Registration::Process *target_proc, Handle process_h, u64 nro_heap_address, u64 nro_heap_size, u64 bss_heap_address, u64 bss_heap_size, u64 *out_address) { - NroHeader *nro; + NroHeader nro_hdr = {0}; MappedCodeMemory mcm_nro = {0}; MappedCodeMemory mcm_bss = {0}; unsigned int i; - Result rc; + Result rc = 0; u8 nro_hash[0x20]; struct sha256_state sha_ctx; + + /* Perform cleanup on failure. */ + ON_SCOPE_EXIT { + if (R_FAILED(rc)) { + mcm_nro.Close(); + mcm_bss.Close(); + } + }; + /* Ensure there is an available NRO slot. */ if (std::all_of(target_proc->nro_infos.begin(), target_proc->nro_infos.end(), std::mem_fn(&Registration::NroInfo::in_use))) { - return 0x6E09; + rc = 0x6E09; + return rc; } for (i = 0; i < 0x200; i++) { if (R_SUCCEEDED(mcm_nro.Open(process_h, target_proc->is_64_bit_addspace, nro_heap_address, nro_heap_size))) { @@ -67,68 +78,72 @@ Result NroUtils::LoadNro(Registration::Process *target_proc, Handle process_h, u } } if (i >= 0x200) { - return 0x6609; + rc = 0x6609; + return rc; } + + /* Map the NRO. */ if (R_FAILED((rc = mcm_nro.Map()))) { - goto LOAD_NRO_END; + return rc; } - nro = (NroHeader *)mcm_nro.mapped_address; - if (nro->magic != MAGIC_NRO0) { - rc = 0x6809; - goto LOAD_NRO_END; + /* Read data from NRO while it's mapped. */ + { + nro_hdr = *((NroHeader *)mcm_nro.mapped_address); + + if (nro_hdr.magic != MAGIC_NRO0) { + rc = 0x6809; + return rc; + } + if (nro_hdr.nro_size != nro_heap_size || nro_hdr.bss_size != bss_heap_size) { + rc = 0x6809; + return rc; + } + if ((nro_hdr.text_size & 0xFFF) || (nro_hdr.ro_size & 0xFFF) || (nro_hdr.rw_size & 0xFFF) || (nro_hdr.bss_size & 0xFFF)) { + rc = 0x6809; + return rc; + } + if (nro_hdr.text_offset != 0 || nro_hdr.text_offset + nro_hdr.text_size != nro_hdr.ro_offset || nro_hdr.ro_offset + nro_hdr.ro_size != nro_hdr.rw_offset || nro_hdr.rw_offset + nro_hdr.rw_size != nro_hdr.nro_size) { + rc = 0x6809; + return rc; + } + + sha256_init(&sha_ctx); + sha256_update(&sha_ctx, (u8 *)mcm_nro.mapped_address, nro_hdr.nro_size); + sha256_finalize(&sha_ctx); + sha256_finish(&sha_ctx, nro_hash); } - if (nro->nro_size != nro_heap_size || nro->bss_size != bss_heap_size) { - rc = 0x6809; - goto LOAD_NRO_END; + + /* Unmap the NRO. */ + if (R_FAILED((rc = mcm_nro.Unmap()))) { + return rc; } - if ((nro->text_size & 0xFFF) || (nro->ro_size & 0xFFF) || (nro->rw_size & 0xFFF) || (nro->bss_size & 0xFFF)) { - rc = 0x6809; - goto LOAD_NRO_END; - } - if (nro->text_offset != 0 || nro->text_offset + nro->text_size != nro->ro_offset || nro->ro_offset + nro->ro_size != nro->rw_offset || nro->rw_offset + nro->rw_size != nro->nro_size) { - rc = 0x6809; - goto LOAD_NRO_END; - } - - - sha256_init(&sha_ctx); - sha256_update(&sha_ctx, (u8 *)nro, nro->nro_size); - sha256_finalize(&sha_ctx); - sha256_finish(&sha_ctx, nro_hash); if (!Registration::IsNroHashPresent(target_proc->index, nro_hash)) { rc = 0x6C09; - goto LOAD_NRO_END; + return rc; } if (Registration::IsNroAlreadyLoaded(target_proc->index, nro_hash)) { rc = 0x7209; - goto LOAD_NRO_END; + return rc; } - if (R_FAILED((rc = svcSetProcessMemoryPermission(process_h, mcm_nro.code_memory_address, nro->text_size, 5)))) { - goto LOAD_NRO_END; + if (R_FAILED((rc = svcSetProcessMemoryPermission(process_h, mcm_nro.code_memory_address, nro_hdr.text_size, 5)))) { + return rc; } - if (R_FAILED((rc = svcSetProcessMemoryPermission(process_h, mcm_nro.code_memory_address + nro->ro_offset, nro->ro_size, 1)))) { - goto LOAD_NRO_END; + if (R_FAILED((rc = svcSetProcessMemoryPermission(process_h, mcm_nro.code_memory_address + nro_hdr.ro_offset, nro_hdr.ro_size, 1)))) { + return rc; } - if (R_FAILED((rc = svcSetProcessMemoryPermission(process_h, mcm_nro.code_memory_address + nro->rw_offset, nro->rw_size + nro->bss_size, 3)))) { - goto LOAD_NRO_END; + if (R_FAILED((rc = svcSetProcessMemoryPermission(process_h, mcm_nro.code_memory_address + nro_hdr.rw_offset, nro_hdr.rw_size + nro_hdr.bss_size, 3)))) { + return rc; } - Registration::AddNroToProcess(target_proc->index, &mcm_nro, &mcm_bss, nro->text_size, nro->ro_size, nro->rw_size, nro->build_id); + Registration::AddNroToProcess(target_proc->index, &mcm_nro, &mcm_bss, nro_hdr.text_size, nro_hdr.ro_size, nro_hdr.rw_size, nro_hdr.build_id); *out_address = mcm_nro.code_memory_address; - mcm_nro.Unmap(); - mcm_bss.Unmap(); rc = 0x0; -LOAD_NRO_END: - if (R_FAILED(rc)) { - mcm_nro.Close(); - mcm_bss.Close(); - } - return 0x0; + return rc; }