diff options
| author | Takoroka <137927095+Takoroka@users.noreply.github.com> | 2026-10-30 11:40:49 -0400 |
|---|---|---|
| committer | Takoroka <137927095+Takoroka@users.noreply.github.com> | 2026-10-30 11:40:58 -0400 |
| commit | 37893c68314360071261305a2f8527d8efde8fde (patch) | |
| tree | 3e595ba7a6b3dc132176f4f0a4c9a47657f01fb9 /src | |
| parent | f362528c0447c491bfe00c0bdd5d8c245396a24c (diff) | |
ro: read Switch 2 NRR hash lists where they are
Switch 2 NRRs carry 3072-bit keys and signatures, so the fields after
them (program id, size, kind, hash list offset and count) sit 0x180
bytes later than in a Switch 1 NRR: hash list offset and count at 0x4c0,
hashes from 0x4d0 (Kirby Air Riders, Minecraft, Mario Tennis Fever).
RegisterModuleInfo read signature bytes as the hash count: Kirby Air
Riders read 51 GB of "hashes" (host memory ran out), Minecraft threw
bad_alloc and the process ended.
Read the fields at the Switch 2 offsets for Switch 2 processes, and
reject an NRR whose hash list does not fit inside it.
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/hle/service/ro/ro.cpp | 23 |
1 files changed, 19 insertions, 4 deletions
diff --git a/src/core/hle/service/ro/ro.cpp b/src/core/hle/service/ro/ro.cpp index 335efa3ad3..2af4f1cf58 100644 --- a/src/core/hle/service/ro/ro.cpp +++ b/src/core/hle/service/ro/ro.cpp @@ -356,6 +356,22 @@ public: // Read NRR. NrrHeader header{}; process->GetMemory().ReadBlock(nrr_address, std::addressof(header), sizeof(header)); + size_t hashes_offset = header.GetHashesOffset(); + u32 num_hashes = header.GetNumHashes(); + if (process->IsSwitch2()) { + // Switch 2 NRRs carry 3072-bit keys and signatures: the fields after them (program + // id, size, kind, hash list offset and count) sit 0x180 bytes later, the hash list + // offset and count at 0x4c0. + std::array<u32, 2> fields{}; + process->GetMemory().ReadBlock(nrr_address + 0x4c0, fields.data(), sizeof(fields)); + hashes_offset = fields[0]; + num_hashes = fields[1]; + } + // The hash list lies inside the NRR (read as a Switch 1 header, a Switch 2 one asked for + // 51 GB of hashes). + R_UNLESS(hashes_offset <= nrr_size && + num_hashes <= (nrr_size - hashes_offset) / sizeof(Sha256Hash), + RO::ResultInvalidNrr); // Set NRR info. context->SetNrrInfoInUse(nrr_info, true); @@ -363,10 +379,9 @@ public: nrr_info->nrr_heap_size = nrr_size; // Read NRR hash list. - nrr_info->hashes.resize(header.GetNumHashes()); - process->GetMemory().ReadBlock(nrr_address + header.GetHashesOffset(), - nrr_info->hashes.data(), - sizeof(Sha256Hash) * header.GetNumHashes()); + nrr_info->hashes.resize(num_hashes); + process->GetMemory().ReadBlock(nrr_address + hashes_offset, nrr_info->hashes.data(), + sizeof(Sha256Hash) * num_hashes); R_SUCCEED(); } |
