savestates: validate states before load

This commit is contained in:
Vitor Kiguchi 2023-04-05 15:28:56 -03:00
parent 8e8c8fa37a
commit c79acdd88d

View file

@ -49,6 +49,30 @@ std::string GetSaveStatePath(u64 program_id, u32 slot) {
} }
} }
static bool ValidateSaveState(const CSTHeader& header, SaveStateInfo& info, u64 program_id,
u32 slot) {
const auto path = GetSaveStatePath(program_id, slot);
if (header.filetype != header_magic_bytes) {
LOG_WARNING(Core, "Invalid save state file {}", path);
return false;
}
info.time = header.time;
if (header.program_id != program_id) {
LOG_WARNING(Core, "Save state file isn't for the current game {}", path);
return false;
}
const std::string revision = fmt::format("{:02x}", fmt::join(header.revision, ""));
if (revision == Common::g_scm_rev) {
info.status = SaveStateInfo::ValidationStatus::OK;
} else {
LOG_WARNING(Core, "Save state file {} created from a different revision {}", path,
revision);
info.status = SaveStateInfo::ValidationStatus::RevisionDismatch;
}
return true;
}
std::vector<SaveStateInfo> ListSaveStates(u64 program_id) { std::vector<SaveStateInfo> ListSaveStates(u64 program_id) {
std::vector<SaveStateInfo> result; std::vector<SaveStateInfo> result;
for (u32 slot = 1; slot <= SaveStateSlotCount; ++slot) { for (u32 slot = 1; slot <= SaveStateSlotCount; ++slot) {
@ -74,24 +98,10 @@ std::vector<SaveStateInfo> ListSaveStates(u64 program_id) {
LOG_ERROR(Core, "Could not read from file {}", path); LOG_ERROR(Core, "Could not read from file {}", path);
continue; continue;
} }
if (header.filetype != header_magic_bytes) { if (!ValidateSaveState(header, info, program_id, slot)) {
LOG_WARNING(Core, "Invalid save state file {}", path);
continue; continue;
} }
info.time = header.time;
if (header.program_id != program_id) {
LOG_WARNING(Core, "Save state file isn't for the current game {}", path);
continue;
}
const std::string revision = fmt::format("{:02x}", fmt::join(header.revision, ""));
if (revision == Common::g_scm_rev) {
info.status = SaveStateInfo::ValidationStatus::OK;
} else {
LOG_WARNING(Core, "Save state file {} created from a different revision {}", path,
revision);
info.status = SaveStateInfo::ValidationStatus::RevisionDismatch;
}
result.emplace_back(std::move(info)); result.emplace_back(std::move(info));
} }
return result; return result;
@ -146,7 +156,19 @@ void System::LoadState(u32 slot) {
std::vector<u8> buffer(FileUtil::GetSize(path) - sizeof(CSTHeader)); std::vector<u8> buffer(FileUtil::GetSize(path) - sizeof(CSTHeader));
FileUtil::IOFile file(path, "rb"); FileUtil::IOFile file(path, "rb");
file.Seek(sizeof(CSTHeader), SEEK_SET); // Skip header
// load header
CSTHeader header;
if (file.ReadBytes(&header, sizeof(header)) != sizeof(header)) {
throw std::runtime_error("Could not read from file at " + path);
}
// validate header
SaveStateInfo info;
if (!ValidateSaveState(header, info, title_id, slot)) {
throw std::runtime_error("Invalid savestate");
}
if (file.ReadBytes(buffer.data(), buffer.size()) != buffer.size()) { if (file.ReadBytes(buffer.data(), buffer.size()) != buffer.size()) {
throw std::runtime_error("Could not read from file at " + path); throw std::runtime_error("Could not read from file at " + path);
} }