diff --git a/libraries/libstratosphere/include/stratosphere/ro/ro_types.hpp b/libraries/libstratosphere/include/stratosphere/ro/ro_types.hpp index 31abdfe59..44856cc34 100644 --- a/libraries/libstratosphere/include/stratosphere/ro/ro_types.hpp +++ b/libraries/libstratosphere/include/stratosphere/ro/ro_types.hpp @@ -119,14 +119,14 @@ namespace ams::ro { } size_t GetSignedAreaSize() const { - return this->size - this->GetSignedAreaOffset(); + return this->size - GetSignedAreaOffset(); } - size_t GetSignedAreaOffset() const; + static constexpr size_t GetSignedAreaOffset(); }; static_assert(sizeof(NrrHeader) == 0x350, "NrrHeader definition!"); - inline size_t NrrHeader::GetSignedAreaOffset() const { + constexpr size_t NrrHeader::GetSignedAreaOffset() { return OFFSETOF(NrrHeader, program_id); } diff --git a/stratosphere/ro/source/impl/ro_nrr_utils.cpp b/stratosphere/ro/source/impl/ro_nrr_utils.cpp index db398cf7c..c814df6db 100644 --- a/stratosphere/ro/source/impl/ro_nrr_utils.cpp +++ b/stratosphere/ro/source/impl/ro_nrr_utils.cpp @@ -228,19 +228,17 @@ namespace ams::ro::impl { return ResultSuccess(); } - bool ValidateNrrHashTableEntry(const void *nrr_hash, const NrrHeader *header, const u8 *hash_table, const void *desired_hash) { + bool ValidateNrrHashTableEntry(const void *signed_area, size_t signed_area_size, size_t hashes_offset, size_t num_hashes, const void *nrr_hash, const u8 *hash_table, const void *desired_hash) { crypto::Sha256Generator sha256; sha256.Initialize(); - const size_t size = header->GetSignedAreaSize(); - const size_t pre_hash_table_size = header->GetHashesOffset() - header->GetSignedAreaOffset(); - const size_t num_hashes = header->GetNumHashes(); /* Hash data before the hash table. */ - sha256.Update(header->GetSignedArea(), pre_hash_table_size); + const size_t pre_hash_table_size = hashes_offset - NrrHeader::GetSignedAreaOffset(); + sha256.Update(signed_area, pre_hash_table_size); /* Hash the hash table, checking if the desired hash exists inside it. */ - size_t remaining_size = size - pre_hash_table_size; + size_t remaining_size = signed_area_size - pre_hash_table_size; bool found_hash = false; for (size_t i = 0; i < num_hashes; i++) { /* Get the current hash. */ diff --git a/stratosphere/ro/source/impl/ro_nrr_utils.hpp b/stratosphere/ro/source/impl/ro_nrr_utils.hpp index 67e9e582d..3a675ad8f 100644 --- a/stratosphere/ro/source/impl/ro_nrr_utils.hpp +++ b/stratosphere/ro/source/impl/ro_nrr_utils.hpp @@ -23,6 +23,6 @@ namespace ams::ro::impl { Result MapAndValidateNrr(NrrHeader **out_header, u64 *out_mapped_code_address, void *out_hash, size_t out_hash_size, Handle process_handle, ncm::ProgramId program_id, u64 nrr_heap_address, u64 nrr_heap_size, ModuleType expected_type, bool enforce_type); Result UnmapNrr(Handle process_handle, const NrrHeader *header, u64 nrr_heap_address, u64 nrr_heap_size, u64 mapped_code_address); - bool ValidateNrrHashTableEntry(const void *nrr_hash, const NrrHeader *header, const u8 *hash_table, const void *desired_hash); + bool ValidateNrrHashTableEntry(const void *signed_area, size_t signed_area_size, size_t hashes_offset, size_t num_hashes, const void *nrr_hash, const u8 *hash_table, const void *desired_hash); } \ No newline at end of file diff --git a/stratosphere/ro/source/impl/ro_service_impl.cpp b/stratosphere/ro/source/impl/ro_service_impl.cpp index 934d16252..88ddee35a 100644 --- a/stratosphere/ro/source/impl/ro_service_impl.cpp +++ b/stratosphere/ro/source/impl/ro_service_impl.cpp @@ -62,7 +62,12 @@ namespace ams::ro::impl { u64 nrr_heap_address; u64 nrr_heap_size; u64 mapped_code_address; - NrrHeader cached_header; + + /* Verification. */ + u32 cached_signed_area_size; + u32 cached_hashes_offset; + u32 cached_num_hashes; + u8 cached_signed_area[sizeof(NrrHeader) - NrrHeader::GetSignedAreaOffset()]; Sha256Hash signed_area_hash; }; @@ -165,7 +170,6 @@ namespace ams::ro::impl { } /* Get the mapped header, ensure that it has hashes. */ - const NrrHeader *cached_nrr_header = std::addressof(this->nrr_infos[i].cached_header); const NrrHeader *mapped_nrr_header = this->nrr_infos[i].mapped_header; const size_t mapped_num_hashes = mapped_nrr_header->GetNumHashes(); if (mapped_num_hashes == 0) { @@ -182,9 +186,13 @@ namespace ams::ro::impl { } /* Check that the hash entry is valid, since our heuristic passed. */ - const void *nrr_hash = std::addressof(this->nrr_infos[i].signed_area_hash); - const u8 *hash_table = reinterpret_cast(mapped_nro_hashes_start); - if (!ValidateNrrHashTableEntry(nrr_hash, cached_nrr_header, hash_table, std::addressof(hash))) { + const void *nrr_hash = std::addressof(this->nrr_infos[i].signed_area_hash); + const void *signed_area = this->nrr_infos[i].cached_signed_area; + const size_t signed_area_size = this->nrr_infos[i].cached_signed_area_size; + const size_t hashes_offset = this->nrr_infos[i].cached_hashes_offset; + const size_t num_hashes = this->nrr_infos[i].cached_num_hashes; + const u8 *hash_table = reinterpret_cast(mapped_nro_hashes_start); + if (!ValidateNrrHashTableEntry(signed_area, signed_area_size, hashes_offset, num_hashes, nrr_hash, hash_table, std::addressof(hash))) { continue; } @@ -434,7 +442,12 @@ namespace ams::ro::impl { nrr_info->nrr_heap_address = nrr_address; nrr_info->nrr_heap_size = nrr_size; nrr_info->mapped_code_address = mapped_code_address; - nrr_info->cached_header = *header; + + nrr_info->cached_signed_area_size = header->GetSignedAreaSize(); + nrr_info->cached_hashes_offset = header->GetHashesOffset(); + nrr_info->cached_num_hashes = header->GetNumHashes(); + + std::memcpy(nrr_info->cached_signed_area, header->GetSignedArea(), std::min(sizeof(nrr_info->cached_signed_area), header->GetHashesOffset() - header->GetSignedAreaOffset())); std::memcpy(std::addressof(nrr_info->signed_area_hash), std::addressof(signed_area_hash), sizeof(signed_area_hash)); return ResultSuccess();