diff --git a/rpcs3/Emu/Memory/vm.cpp b/rpcs3/Emu/Memory/vm.cpp index 769a31a494..69e9d0b871 100644 --- a/rpcs3/Emu/Memory/vm.cpp +++ b/rpcs3/Emu/Memory/vm.cpp @@ -2256,7 +2256,15 @@ namespace vm void load(utils::serial& ar) { std::vector> shared; - shared.resize(ar.pop()); + + const usz shared_size = ar.pop(); + + if (!shared_size || ar.get_size(umax) / 4096 < shared_size) + { + fmt::throw_exception("Invalid VM serialization state: shared_size=0x%x, ar=%s", shared_size, ar); + } + + shared.resize(shared_size); for (auto& shm : shared) { diff --git a/rpcs3/Emu/System.cpp b/rpcs3/Emu/System.cpp index 0969cf5a5c..3130b6cefe 100644 --- a/rpcs3/Emu/System.cpp +++ b/rpcs3/Emu/System.cpp @@ -1056,7 +1056,13 @@ game_boot_result Emulator::Load(const std::string& title_id, bool is_disc_patch, auto load_tar = [&](const std::string& path) { - const usz size = *m_ar; + const usz size = m_ar->pop(); + const usz max_data_size = m_ar->get_size(utils::add_saturate(size, m_ar->pos)); + + if (size % 512 || max_data_size < size || max_data_size - size < m_ar->pos) + { + fmt::throw_exception("TAR desrialization failed: Invalid size. TAR size: 0x%x, path='%s', ar: %s", size, path, *m_ar); + } fs::remove_all(path, size == 0); @@ -1065,7 +1071,12 @@ game_boot_result Emulator::Load(const std::string& title_id, bool is_disc_patch, m_ar->breathe(true); m_ar->m_max_data = m_ar->pos + size; ensure(tar_object(*m_ar).extract(path)); - m_ar->seek_pos(m_ar->m_max_data, size >= 4096); + + if (m_ar->m_max_data != m_ar->pos) + { + fmt::throw_exception("TAR desrialization failed: read bytes: 0x%x, expected: 0x%x, path='%s', ar: %s", m_ar->pos - (m_ar->m_max_data - size), size, path, *m_ar); + } + m_ar->m_max_data = umax; m_ar->breathe(); } @@ -1079,13 +1090,19 @@ game_boot_result Emulator::Load(const std::string& title_id, bool is_disc_patch, for (const std::string hdd0_game = rpcs3::utils::get_hdd0_dir() + "game/";;) { - const std::string game_data = *m_ar; + const std::string game_data = m_ar->pop(); if (game_data.empty()) { break; } + if (game_data.find_first_of('\0') != umax || !sysutil_check_name_string(game_data.c_str(), 1, CELL_GAME_DIRNAME_SIZE)) + { + const std::basic_string_view dirname{reinterpret_cast(game_data.data()), game_data.size()}; + fmt::throw_exception("HDD0 deserialization failed: Invalid directory name: %s, ar=%s", dirname.substr(0, CELL_GAME_DIRNAME_SIZE + 1), *m_ar); + } + load_tar(hdd0_game + game_data); } @@ -2993,7 +3010,7 @@ void Emulator::Kill(bool allow_autoexit, bool savestate, savestate_stage* save_s const usz tar_size = new_pos - old_pos; - if (tar_size != ar_null.pos) + if (tar_size % 512 || tar_size != ar_null.pos) { fmt::throw_exception("Unexpected TAR entry size (size=0x%x, expected=0x%x, entries=0x%x)", tar_size, ar_null.pos, dir_entries.size()); } diff --git a/rpcs3/Emu/savestate_utils.cpp b/rpcs3/Emu/savestate_utils.cpp index fa95603435..413cc392da 100644 --- a/rpcs3/Emu/savestate_utils.cpp +++ b/rpcs3/Emu/savestate_utils.cpp @@ -23,7 +23,12 @@ void fmt_class_string::format(std::string& out, u64 arg) { const utils::serial& ar = get_object(arg); - fmt::append(out, "{ %s, 0x%x/0x%x, memory=0x%x }", ar.is_writing() ? "writing" : "reading", ar.pos, ar.data_offset + ar.data.size(), ar.data.size()); + + be_t sample64 = 0; + const usz read_size = std::min(ar.data.size(), sizeof(sample64)); + std::memcpy(&sample64, ar.data.data() + ar.data.size() - read_size, read_size); + + fmt::append(out, "{ %s, 0x%x/0x%x, memory=0x%x, sample64=0x%016x }", ar.is_writing() ? "writing" : "reading", ar.pos, ar.data_offset + ar.data.size(), ar.data.size(), sample64); } struct serial_ver_t diff --git a/rpcs3/Loader/TAR.cpp b/rpcs3/Loader/TAR.cpp index 4734061ad3..cc777229a5 100644 --- a/rpcs3/Loader/TAR.cpp +++ b/rpcs3/Loader/TAR.cpp @@ -139,7 +139,7 @@ std::unique_ptr tar_object::get_file(const std::string& path, std } else { - tar_log.trace("tar_object::get_file() failed to parse header: offset=0x%x, filesize=0x%x", largest_offset, max_size); + tar_log.error("tar_object::get_file() failed to parse header: offset=0x%x, filesize=0x%x", largest_offset, max_size); } return { size, {} };