[fs] Fix integrity check validation for new updates #395

Merged
crueter merged 16 commits from improve-integrity-check into master 2025-09-12 16:02:13 +02:00
3 changed files with 17 additions and 40 deletions

View file

@ -34,12 +34,9 @@ NCA::NCA(VirtualFile file_, const NCA* base_nca)
} }
reader = std::make_shared<NcaReader>(); reader = std::make_shared<NcaReader>();
if (Result rc = if (Result rc = reader->Initialize(file, GetCryptoConfiguration(), GetNcaCompressionConfiguration()); R_FAILED(rc)) {
reader->Initialize(file, GetCryptoConfiguration(), GetNcaCompressionConfiguration());
R_FAILED(rc)) {
if (rc != ResultInvalidNcaSignature) { if (rc != ResultInvalidNcaSignature) {
LOG_ERROR(Loader, "File reader errored out during header read: {:#x}", LOG_ERROR(Loader, "File reader errored out during header read: {:#x}", rc.GetInnerValue());
rc.GetInnerValue());
} }
status = Loader::ResultStatus::ErrorBadNCAHeader; status = Loader::ResultStatus::ErrorBadNCAHeader;
return; return;
@ -84,10 +81,8 @@ NCA::NCA(VirtualFile file_, const NCA* base_nca)
std::vector<VirtualFile> filesystems(fs_count); std::vector<VirtualFile> filesystems(fs_count);
for (s32 i = 0; i < fs_count; i++) { for (s32 i = 0; i < fs_count; i++) {
NcaFsHeaderReader header_reader; NcaFsHeaderReader header_reader;
const Result rc = fs.OpenStorage(&filesystems[i], &header_reader, i); if (Result rc = fs.OpenStorage(&filesystems[i], &header_reader, i); R_FAILED(rc)) {
if (R_FAILED(rc)) { LOG_DEBUG(Loader, "File reader errored out during read of section {}: {:#x}", i, rc.GetInnerValue());
LOG_ERROR(Loader, "File reader errored out during read of section {}: {:#x}", i,
rc.GetInnerValue());
status = Loader::ResultStatus::ErrorBadNCAHeader; status = Loader::ResultStatus::ErrorBadNCAHeader;
return; return;
} }

View file

@ -4,23 +4,18 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include "core/file_sys/fssystem/fssystem_integrity_verification_storage.h"
#include "common/alignment.h" #include "common/alignment.h"
#include "core/file_sys/fssystem/fssystem_integrity_verification_storage.h"
namespace FileSys { namespace FileSys {
constexpr inline u32 ILog2(u32 val) constexpr inline u32 ILog2(u32 val) {
{
ASSERT(val > 0); ASSERT(val > 0);
return static_cast<u32>((sizeof(u32) * 8) - 1 - std::countl_zero<u32>(val)); return static_cast<u32>((sizeof(u32) * 8) - 1 - std::countl_zero<u32>(val));
} }
void IntegrityVerificationStorage::Initialize(VirtualFile hs, void IntegrityVerificationStorage::Initialize(VirtualFile hs, VirtualFile ds, s64 verif_block_size,
VirtualFile ds, s64 upper_layer_verif_block_size, bool is_real_data) {
s64 verif_block_size,
s64 upper_layer_verif_block_size,
bool is_real_data)
{
// Validate preconditions. // Validate preconditions.
ASSERT(verif_block_size >= HashSize); ASSERT(verif_block_size >= HashSize);
@ -40,28 +35,22 @@ void IntegrityVerificationStorage::Initialize(VirtualFile hs,
ASSERT(m_upper_layer_verification_block_size == 1ll << m_upper_layer_verification_block_order); ASSERT(m_upper_layer_verification_block_size == 1ll << m_upper_layer_verification_block_order);
// Validate sizes. // Validate sizes.
if (m_data_storage != nullptr) { {
s64 hash_size = m_hash_storage->GetSize(); s64 hash_size = m_hash_storage->GetSize();
s64 data_size = m_data_storage->GetSize(); s64 data_size = m_data_storage->GetSize();
ASSERT(((hash_size / HashSize) * m_verification_block_size) >= data_size); ASSERT(((hash_size / HashSize) * m_verification_block_size) >= data_size);
} else {
LOG_ERROR(Loader,
"Failed to initialize integrity verification store. Game, update, or DLC may not "
"work.");
} }
// Set data. // Set data.
m_is_real_data = is_real_data; m_is_real_data = is_real_data;
} }
void IntegrityVerificationStorage::Finalize() void IntegrityVerificationStorage::Finalize() {
{
m_hash_storage = VirtualFile(); m_hash_storage = VirtualFile();
m_data_storage = VirtualFile(); m_data_storage = VirtualFile();
} }
size_t IntegrityVerificationStorage::Read(u8* buffer, size_t size, size_t offset) const size_t IntegrityVerificationStorage::Read(u8* buffer, size_t size, size_t offset) const {
{
// Succeed if zero size. // Succeed if zero size.
if (size == 0) { if (size == 0) {
return size; return size;
@ -70,13 +59,7 @@ size_t IntegrityVerificationStorage::Read(u8* buffer, size_t size, size_t offset
// Validate arguments. // Validate arguments.
ASSERT(buffer != nullptr); ASSERT(buffer != nullptr);
if (m_data_storage == nullptr) { // Validate the offset.
LOG_ERROR(Loader,
"Integrity verification store failed read operation. Game, update or DLC may not "
"work.");
return 0;
}
s64 data_size = m_data_storage->GetSize(); s64 data_size = m_data_storage->GetSize();
ASSERT(offset <= static_cast<size_t>(data_size)); ASSERT(offset <= static_cast<size_t>(data_size));
@ -104,8 +87,7 @@ size_t IntegrityVerificationStorage::Read(u8* buffer, size_t size, size_t offset
return m_data_storage->Read(buffer, read_size, offset); return m_data_storage->Read(buffer, read_size, offset);
} }
size_t IntegrityVerificationStorage::GetSize() const size_t IntegrityVerificationStorage::GetSize() const {
{
return m_data_storage->GetSize(); return m_data_storage->GetSize();
} }

View file

@ -1051,8 +1051,8 @@ Result NcaFileSystemDriver::CreatePatchMetaStorage(
ASSERT(out_aes_ctr_ex_meta != nullptr); ASSERT(out_aes_ctr_ex_meta != nullptr);
ASSERT(out_indirect_meta != nullptr); ASSERT(out_indirect_meta != nullptr);
ASSERT(base_storage != nullptr); ASSERT(base_storage != nullptr);
ASSERT(patch_info.HasAesCtrExTable()); //ASSERT(patch_info.HasAesCtrExTable());
MaranBr marked this conversation as resolved

What's this for?

What's this for?

These two asserts are not needed at this point in the code.

These two asserts are not needed at this point in the code.
ASSERT(patch_info.HasIndirectTable()); //ASSERT(patch_info.HasIndirectTable());
ASSERT(Common::IsAligned<s64>(patch_info.aes_ctr_ex_size, NcaHeader::XtsBlockSize)); ASSERT(Common::IsAligned<s64>(patch_info.aes_ctr_ex_size, NcaHeader::XtsBlockSize));
// Validate patch info extents. // Validate patch info extents.
@ -1334,8 +1334,8 @@ Result NcaFileSystemDriver::CreateIntegrityVerificationStorageImpl(
R_UNLESS(last_layer_info_offset + layer_info.size <= layer_info_offset, R_UNLESS(last_layer_info_offset + layer_info.size <= layer_info_offset,
ResultRomNcaInvalidIntegrityLayerInfoOffset); ResultRomNcaInvalidIntegrityLayerInfoOffset);
} }
storage_info.SetDataStorage(std::make_shared<OffsetVfsFile>( storage_info[level_hash_info.max_layers - 1] = std::make_shared<OffsetVfsFile>(
MaranBr marked this conversation as resolved

Seems interesting, what's in SetDataStorage that caused issues?

Seems interesting, what's in SetDataStorage that caused issues?

This is something I will look into further when I have more time. It's safe for now.

This is something I will look into further when I have more time. It's safe for now.
std::move(base_storage), layer_info.size, last_layer_info_offset)); std::move(base_storage), layer_info.size, last_layer_info_offset);
// Make the integrity romfs storage. // Make the integrity romfs storage.
auto integrity_storage = std::make_shared<IntegrityRomFsStorage>(); auto integrity_storage = std::make_shared<IntegrityRomFsStorage>();