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

This fixes the integrity check validation for new updates.

Reviewed-on: #395
Reviewed-by: Shinmegumi <shinmegumi@eden-emu.dev>
Reviewed-by: crueter <crueter@eden-emu.dev>
Co-authored-by: MaranBr <maranbr@outlook.com>
Co-committed-by: MaranBr <maranbr@outlook.com>
This commit is contained in:
MaranBr 2025-09-12 16:02:12 +02:00 committed by crueter
parent 13ecc1e481
commit 3fbfd64722
Signed by: crueter
GPG key ID: 425ACD2D4830EBC6
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());
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>(
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>();