Fix path bugs & wrap seeks in an if (#1154)

* Fix path bugs

* Wrap most seeks in an if
This commit is contained in:
Paris Oplopoios 2024-09-30 12:42:59 +03:00 committed by GitHub
parent c7ff0419ad
commit cbbf3505e7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 105 additions and 47 deletions

View file

@ -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;

View file

@ -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<u8>(sfo.data(), entry.size);
}
@ -127,7 +134,11 @@ bool PKG::Extract(const std::filesystem::path& filepath, const std::filesystem::
std::array<std::array<u8, 256>, 7> key1;
std::array<u8, 256> 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<u8> 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<u8> 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<u8> 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<u8, 16> 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.

View file

@ -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);

View file

@ -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<u8>(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<u8> 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<u8> ESFM(entry.entry_len - iv_len);
std::vector<u8> 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);

View file

@ -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<u8>(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<u8>(buf, nbytes);
}

View file

@ -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<u8>(reinterpret_cast<u8*>(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<u8>(reinterpret_cast<u8*>(virtual_addr), size);
return;
}

View file

@ -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);
}
}

View file

@ -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;

View file

@ -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);
}
}

View file

@ -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")});

View file

@ -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;
}