From cbbf3505e70a1aad5bd8c2b3766cb55291269877 Mon Sep 17 00:00:00 2001 From: Paris Oplopoios Date: Mon, 30 Sep 2024 12:42:59 +0300 Subject: [PATCH] Fix path bugs & wrap seeks in an if (#1154) * Fix path bugs * Wrap most seeks in an if --- src/common/io_file.cpp | 12 +++++++ src/core/file_format/pkg.cpp | 39 ++++++++++++++++++----- src/core/file_format/pkg.h | 2 +- src/core/file_format/trp.cpp | 26 ++++++++++++--- src/core/libraries/kernel/file_system.cpp | 15 +++++++-- src/core/loader/elf.cpp | 15 +++++++-- src/qt_gui/gui_context_menus.h | 5 +-- src/qt_gui/main_window.cpp | 17 ++++------ src/qt_gui/main_window.h | 5 +-- src/qt_gui/pkg_viewer.cpp | 11 ++++--- src/qt_gui/trophy_viewer.cpp | 5 +-- 11 files changed, 105 insertions(+), 47 deletions(-) diff --git a/src/common/io_file.cpp b/src/common/io_file.cpp index c1d9cc59..33dce563 100644 --- a/src/common/io_file.cpp +++ b/src/common/io_file.cpp @@ -372,6 +372,18 @@ bool IOFile::Seek(s64 offset, SeekOrigin origin) const { return false; } + u64 size = GetSize(); + if (origin == SeekOrigin::CurrentPosition && Tell() + offset > size) { + LOG_ERROR(Common_Filesystem, "Seeking past the end of the file"); + return false; + } else if (origin == SeekOrigin::SetOrigin && (u64)offset > size) { + LOG_ERROR(Common_Filesystem, "Seeking past the end of the file"); + return false; + } else if (origin == SeekOrigin::End && offset > 0) { + LOG_ERROR(Common_Filesystem, "Seeking past the end of the file"); + return false; + } + errno = 0; const auto seek_result = fseeko(file, offset, ToSeekOrigin(origin)) == 0; diff --git a/src/core/file_format/pkg.cpp b/src/core/file_format/pkg.cpp index f329e81a..8d038b06 100644 --- a/src/core/file_format/pkg.cpp +++ b/src/core/file_format/pkg.cpp @@ -44,7 +44,7 @@ PKG::PKG() = default; PKG::~PKG() = default; -bool PKG::Open(const std::filesystem::path& filepath) { +bool PKG::Open(const std::filesystem::path& filepath, std::string& failreason) { Common::FS::IOFile file(filepath, Common::FS::FileAccessMode::Read); if (!file.IsOpen()) { return false; @@ -70,7 +70,11 @@ bool PKG::Open(const std::filesystem::path& filepath) { u32 offset = pkgheader.pkg_table_entry_offset; u32 n_files = pkgheader.pkg_table_entry_count; - file.Seek(offset); + if (!file.Seek(offset)) { + failreason = "Failed to seek to PKG table entry offset"; + return false; + } + for (int i = 0; i < n_files; i++) { PKGEntry entry{}; file.Read(entry.id); @@ -85,7 +89,10 @@ bool PKG::Open(const std::filesystem::path& filepath) { const auto name = GetEntryNameByType(entry.id); if (name == "param.sfo") { sfo.clear(); - file.Seek(entry.offset); + if (!file.Seek(entry.offset)) { + failreason = "Failed to seek to param.sfo offset"; + return false; + } sfo.resize(entry.size); file.ReadRaw(sfo.data(), entry.size); } @@ -127,7 +134,11 @@ bool PKG::Extract(const std::filesystem::path& filepath, const std::filesystem:: std::array, 7> key1; std::array imgkeydata; - file.Seek(offset); + if (!file.Seek(offset)) { + failreason = "Failed to seek to PKG table entry offset"; + return false; + } + for (int i = 0; i < n_files; i++) { PKGEntry entry{}; file.Read(entry.id); @@ -149,7 +160,10 @@ bool PKG::Extract(const std::filesystem::path& filepath, const std::filesystem:: // Just print with id Common::FS::IOFile out(extract_path / "sce_sys" / std::to_string(entry.id), Common::FS::FileAccessMode::Write); - file.Seek(entry.offset); + if (!file.Seek(entry.offset)) { + failreason = "Failed to seek to PKG entry offset"; + return false; + } std::vector data; data.resize(entry.size); @@ -195,7 +209,10 @@ bool PKG::Extract(const std::filesystem::path& filepath, const std::filesystem:: } Common::FS::IOFile out(extract_path / "sce_sys" / name, Common::FS::FileAccessMode::Write); - file.Seek(entry.offset); + if (!file.Seek(entry.offset)) { + failreason = "Failed to seek to PKG entry offset"; + return false; + } std::vector data; data.resize(entry.size); @@ -207,7 +224,10 @@ bool PKG::Extract(const std::filesystem::path& filepath, const std::filesystem:: if (entry.id == 0x400 || entry.id == 0x401 || entry.id == 0x402 || entry.id == 0x403) { // somehow 0x401 is not decrypting decNp.resize(entry.size); - file.Seek(entry.offset); + if (!file.Seek(entry.offset)) { + failreason = "Failed to seek to PKG entry offset"; + return false; + } std::vector data; data.resize(entry.size); @@ -237,7 +257,10 @@ bool PKG::Extract(const std::filesystem::path& filepath, const std::filesystem:: // Read the seed std::array seed; - file.Seek(pkgheader.pfs_image_offset + 0x370); + if (!file.Seek(pkgheader.pfs_image_offset + 0x370)) { + failreason = "Failed to seek to PFS image offset"; + return false; + } file.Read(seed); // Get data and tweak keys. diff --git a/src/core/file_format/pkg.h b/src/core/file_format/pkg.h index d30d50b4..a488a2df 100644 --- a/src/core/file_format/pkg.h +++ b/src/core/file_format/pkg.h @@ -103,7 +103,7 @@ public: PKG(); ~PKG(); - bool Open(const std::filesystem::path& filepath); + bool Open(const std::filesystem::path& filepath, std::string& failreason); void ExtractFiles(const int index); bool Extract(const std::filesystem::path& filepath, const std::filesystem::path& extract, std::string& failreason); diff --git a/src/core/file_format/trp.cpp b/src/core/file_format/trp.cpp index 724f9078..a1b47dfc 100644 --- a/src/core/file_format/trp.cpp +++ b/src/core/file_format/trp.cpp @@ -1,6 +1,7 @@ // SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include "common/logging/log.h" #include "common/path_util.h" #include "trp.h" @@ -13,7 +14,10 @@ void TRP::GetNPcommID(const std::filesystem::path& trophyPath, int index) { if (!npbindFile.IsOpen()) { return; } - npbindFile.Seek(0x84 + (index * 0x180)); + if (!npbindFile.Seek(0x84 + (index * 0x180))) { + LOG_CRITICAL(Common_Filesystem, "Failed to seek to NPbind offset"); + return; + } npbindFile.ReadRaw(np_comm_id.data(), 12); std::fill(np_comm_id.begin() + 12, np_comm_id.end(), 0); // fill with 0, we need 16 bytes. } @@ -56,26 +60,38 @@ bool TRP::Extract(const std::filesystem::path& trophyPath) { std::filesystem::create_directory(trpFilesPath / "Xml"); for (int i = 0; i < header.entry_num; i++) { - file.Seek(seekPos); + if (!file.Seek(seekPos)) { + LOG_CRITICAL(Common_Filesystem, "Failed to seek to TRP entry offset"); + return false; + } seekPos += (s64)header.entry_size; TrpEntry entry; file.Read(entry); std::string_view name(entry.entry_name); if (entry.flag == 0 && name.find("TROP") != std::string::npos) { // PNG - file.Seek(entry.entry_pos); + if (file.Seek(entry.entry_pos)) { + LOG_CRITICAL(Common_Filesystem, "Failed to seek to TRP entry offset"); + return false; + } std::vector icon(entry.entry_len); file.Read(icon); Common::FS::IOFile::WriteBytes(trpFilesPath / "Icons" / name, icon); } if (entry.flag == 3 && np_comm_id[0] == 'N' && np_comm_id[1] == 'P') { // ESFM, encrypted. - file.Seek(entry.entry_pos); + if (file.Seek(entry.entry_pos)) { + LOG_CRITICAL(Common_Filesystem, "Failed to seek to TRP entry offset"); + return false; + } file.Read(esfmIv); // get iv key. // Skip the first 16 bytes which are the iv key on every entry as we want a // clean xml file. std::vector ESFM(entry.entry_len - iv_len); std::vector XML(entry.entry_len - iv_len); - file.Seek(entry.entry_pos + iv_len); + if (file.Seek(entry.entry_pos + iv_len)) { + LOG_CRITICAL(Common_Filesystem, "Failed to seek to TRP entry + iv offset"); + return false; + } file.Read(ESFM); crypto.decryptEFSM(np_comm_id, esfmIv, ESFM, XML); // decrypt removePadding(XML); diff --git a/src/core/libraries/kernel/file_system.cpp b/src/core/libraries/kernel/file_system.cpp index 91fc7846..7f88fc45 100644 --- a/src/core/libraries/kernel/file_system.cpp +++ b/src/core/libraries/kernel/file_system.cpp @@ -229,7 +229,10 @@ s64 PS4_SYSV_ABI sceKernelLseek(int d, s64 offset, int whence) { } std::scoped_lock lk{file->m_mutex}; - file->f.Seek(offset, origin); + if (!file->f.Seek(offset, origin)) { + LOG_CRITICAL(Kernel_Fs, "sceKernelLseek: failed to seek"); + return SCE_KERNEL_ERROR_EINVAL; + } return file->f.Tell(); } @@ -380,7 +383,10 @@ s64 PS4_SYSV_ABI sceKernelPread(int d, void* buf, size_t nbytes, s64 offset) { SCOPE_EXIT { file->f.Seek(pos); }; - file->f.Seek(offset); + if (!file->f.Seek(offset)) { + LOG_CRITICAL(Kernel_Fs, "sceKernelPread: failed to seek"); + return ORBIS_KERNEL_ERROR_EINVAL; + } return file->f.ReadRaw(buf, nbytes); } @@ -514,7 +520,10 @@ s64 PS4_SYSV_ABI sceKernelPwrite(int d, void* buf, size_t nbytes, s64 offset) { SCOPE_EXIT { file->f.Seek(pos); }; - file->f.Seek(offset); + if (!file->f.Seek(offset)) { + LOG_CRITICAL(Kernel_Fs, "sceKernelPwrite: failed to seek"); + return ORBIS_KERNEL_ERROR_EINVAL; + } return file->f.WriteRaw(buf, nbytes); } diff --git a/src/core/loader/elf.cpp b/src/core/loader/elf.cpp index 6d7c8773..4de20436 100644 --- a/src/core/loader/elf.cpp +++ b/src/core/loader/elf.cpp @@ -204,7 +204,10 @@ void Elf::Open(const std::filesystem::path& file_name) { } out.resize(num); - m_f.Seek(offset, SeekOrigin::SetOrigin); + if (!m_f.Seek(offset, SeekOrigin::SetOrigin)) { + LOG_CRITICAL(Loader, "Failed to seek to header tables"); + return; + } m_f.Read(out); }; @@ -465,7 +468,10 @@ std::string Elf::ElfPHeaderStr(u16 no) { void Elf::LoadSegment(u64 virtual_addr, u64 file_offset, u64 size) { if (!is_self) { // It's elf file - m_f.Seek(file_offset, SeekOrigin::SetOrigin); + if (!m_f.Seek(file_offset, SeekOrigin::SetOrigin)) { + LOG_CRITICAL(Loader, "Failed to seek to ELF header"); + return; + } m_f.ReadRaw(reinterpret_cast(virtual_addr), size); return; } @@ -479,7 +485,10 @@ void Elf::LoadSegment(u64 virtual_addr, u64 file_offset, u64 size) { if (file_offset >= phdr.p_offset && file_offset < phdr.p_offset + phdr.p_filesz) { auto offset = file_offset - phdr.p_offset; - m_f.Seek(offset + seg.file_offset, SeekOrigin::SetOrigin); + if (!m_f.Seek(offset + seg.file_offset, SeekOrigin::SetOrigin)) { + LOG_CRITICAL(Loader, "Failed to seek to segment"); + return; + } m_f.ReadRaw(reinterpret_cast(virtual_addr), size); return; } diff --git a/src/qt_gui/gui_context_menus.h b/src/qt_gui/gui_context_menus.h index 3218884d..4eb65757 100644 --- a/src/qt_gui/gui_context_menus.h +++ b/src/qt_gui/gui_context_menus.h @@ -312,10 +312,7 @@ public: if (selected == &installPackage) { QStringList pkg_app_ = m_pkg_app_list[itemIndex].split(";;"); - std::filesystem::path path(pkg_app_[9].toStdString()); -#ifdef _WIN32 - path = std::filesystem::path(pkg_app_[9].toStdWString()); -#endif + std::filesystem::path path = Common::FS::PathFromQString(pkg_app_[9]); InstallDragDropPkg(path, 1, 1); } } diff --git a/src/qt_gui/main_window.cpp b/src/qt_gui/main_window.cpp index 2981da3a..837cdece 100644 --- a/src/qt_gui/main_window.cpp +++ b/src/qt_gui/main_window.cpp @@ -625,10 +625,7 @@ void MainWindow::InstallPkg() { int pkgNum = 0; for (const QString& file : fileNames) { ++pkgNum; - std::filesystem::path path(file.toStdString()); -#ifdef _WIN64 - path = std::filesystem::path(file.toStdWString()); -#endif + std::filesystem::path path = Common::FS::PathFromQString(file); MainWindow::InstallDragDropPkg(path, pkgNum, nPkg); } } @@ -646,10 +643,7 @@ void MainWindow::BootGame() { QMessageBox::critical(nullptr, tr("Game Boot"), QString(tr("Only one file can be selected!"))); } else { - std::filesystem::path path(fileNames[0].toStdString()); -#ifdef _WIN64 - path = std::filesystem::path(fileNames[0].toStdWString()); -#endif + std::filesystem::path path = Common::FS::PathFromQString(fileNames[0]); Core::Emulator emulator; if (!std::filesystem::exists(path)) { QMessageBox::critical(nullptr, tr("Run Game"), @@ -663,9 +657,12 @@ void MainWindow::BootGame() { void MainWindow::InstallDragDropPkg(std::filesystem::path file, int pkgNum, int nPkg) { if (Loader::DetectFileType(file) == Loader::FileTypes::Pkg) { - pkg = PKG(); - pkg.Open(file); std::string failreason; + pkg = PKG(); + if (!pkg.Open(file, failreason)) { + QMessageBox::critical(this, tr("PKG ERROR"), QString::fromStdString(failreason)); + return; + } auto extract_path = Config::getGameInstallDir() / pkg.GetTitleID(); QString pkgType = QString::fromStdString(pkg.GetPkgFlags()); QString gameDirPath; diff --git a/src/qt_gui/main_window.h b/src/qt_gui/main_window.h index c1d5cc26..a428f431 100644 --- a/src/qt_gui/main_window.h +++ b/src/qt_gui/main_window.h @@ -110,10 +110,7 @@ protected: int nPkg = urlList.size(); for (const QUrl& url : urlList) { pkgNum++; - std::filesystem::path path(url.toLocalFile().toStdString()); -#ifdef _WIN64 - path = std::filesystem::path(url.toLocalFile().toStdWString()); -#endif + std::filesystem::path path = Common::FS::PathFromQString(url.toLocalFile()); InstallDragDropPkg(path, pkgNum, nPkg); } } diff --git a/src/qt_gui/pkg_viewer.cpp b/src/qt_gui/pkg_viewer.cpp index 8f20f692..0ffb9b57 100644 --- a/src/qt_gui/pkg_viewer.cpp +++ b/src/qt_gui/pkg_viewer.cpp @@ -104,11 +104,12 @@ void PKGViewer::ProcessPKGInfo() { m_pkg_patch_list.clear(); m_full_pkg_list.clear(); for (int i = 0; i < m_pkg_list.size(); i++) { - std::filesystem::path path(m_pkg_list[i].toStdString()); -#ifdef _WIN32 - path = std::filesystem::path(m_pkg_list[i].toStdWString()); -#endif - package.Open(path); + std::filesystem::path path = Common::FS::PathFromQString(m_pkg_list[i]); + std::string failreason; + if (!package.Open(path, failreason)) { + QMessageBox::critical(this, tr("PKG ERROR"), QString::fromStdString(failreason)); + return; + } psf.Open(package.sfo); QString title_name = QString::fromStdString(std::string{psf.GetString("TITLE").value_or("Unknown")}); diff --git a/src/qt_gui/trophy_viewer.cpp b/src/qt_gui/trophy_viewer.cpp index 528beee0..e4394c7e 100644 --- a/src/qt_gui/trophy_viewer.cpp +++ b/src/qt_gui/trophy_viewer.cpp @@ -28,10 +28,7 @@ void TrophyViewer::PopulateTrophyWidget(QString title) { QDir dir(trophyDirQt); if (!dir.exists()) { - std::filesystem::path path(gameTrpPath_.toStdString()); -#ifdef _WIN64 - path = std::filesystem::path(gameTrpPath_.toStdWString()); -#endif + std::filesystem::path path = Common::FS::PathFromQString(gameTrpPath_); if (!trp.Extract(path)) return; }