mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-08-31 09:45:24 +02:00
The "is this an ELF rather than a PBP" test compared against "\nFLE", which is neither ELF's magic (\x7fELF) nor anything else - most likely a \x7f escape that swallowed the E when it was written in 2013. Since no real file matches it, every file that wasn't a PBP was reported as an ELF and the error branch was unreachable. Compares against the real magic now, so something that's neither is reported as neither. That error also printed the 4-byte magic with %s, which isn't NUL-terminated - it's four hex bytes instead. GetSubFileSize subtracted offsets that come straight out of the file without checking they're ordered or even inside it, so a corrupt PBP produced a size from an unsigned underflow - nearly 4GB, which the callers then had to catch by size limit. It returns 0 for anything that doesn't make sense. Also &(*out)[0] on a zero-length subfile, which is UB on an empty vector. Plus one in ParamSFO: GetDataOffset mixed int and u32 for the data offset, so its bounds check ran in whichever type the promotion landed on. It's size_t throughout now, matching how ReadSFO does the same arithmetic. Booted an EBOOT.PBP to check the PBP path end to end - loads, and generates the same fake disc ID as before. pspautotests 314/314, UnitTest 55/55. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GZq8ZtJmFY7bkX5FVkr3P9
113 lines
3.6 KiB
C++
113 lines
3.6 KiB
C++
// Copyright (c) 2013- PPSSPP Project.
|
|
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, version 2.0 or later versions.
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License 2.0 for more details.
|
|
|
|
// A copy of the GPL 2.0 should have been included with the program.
|
|
// If not, see http://www.gnu.org/licenses/
|
|
|
|
// Official git repository and contact information can be found at
|
|
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
|
|
|
#include <string>
|
|
#include <cstring>
|
|
|
|
#include "Common/Log.h"
|
|
#include "Core/Loaders.h"
|
|
#include "Core/ELF/PBPReader.h"
|
|
|
|
PBPReader::PBPReader(FileLoader *fileLoader) {
|
|
if (!fileLoader->Exists()) {
|
|
ERROR_LOG(Log::Loader, "Failed to open PBP file %s", fileLoader->GetPath().c_str());
|
|
return;
|
|
}
|
|
|
|
fileSize_ = (size_t)fileLoader->FileSize();
|
|
if (fileLoader->ReadAt(0, sizeof(header_), &header_) != sizeof(header_)) {
|
|
ERROR_LOG(Log::Loader, "PBP is too small to be valid: %s", fileLoader->GetPath().c_str());
|
|
return;
|
|
}
|
|
if (memcmp(header_.magic, "\0PBP", 4) != 0) {
|
|
// Split string so the \x7f escape doesn't swallow the E. This used to compare against
|
|
// "\nFLE", which is neither ELF's magic nor anything else - so every file that wasn't a PBP
|
|
// was reported as an ELF, and the error branch below was unreachable.
|
|
if (memcmp(header_.magic, "\x7f" "ELF", 4) == 0) {
|
|
VERBOSE_LOG(Log::Loader, "%s: File actually an ELF, not a PBP", fileLoader->GetPath().c_str());
|
|
isELF_ = true;
|
|
} else {
|
|
ERROR_LOG(Log::Loader, "Magic number in %s indicates neither PBP nor ELF: %02x %02x %02x %02x",
|
|
fileLoader->GetPath().c_str(), (u8)header_.magic[0], (u8)header_.magic[1], (u8)header_.magic[2], (u8)header_.magic[3]);
|
|
}
|
|
return;
|
|
}
|
|
|
|
VERBOSE_LOG(Log::Loader, "Loading PBP, version = %08x", header_.version);
|
|
file_ = fileLoader;
|
|
}
|
|
|
|
bool PBPReader::GetSubFile(PBPSubFile file, std::vector<u8> *out) const {
|
|
if (!file_) {
|
|
return false;
|
|
}
|
|
|
|
const size_t expected = GetSubFileSize(file);
|
|
|
|
// This is only used to get the PARAM.SFO, so let's have a strict 256MB file size limit for sanity.
|
|
if (expected > 256 * 1024 * 1024) {
|
|
ERROR_LOG(Log::Loader, "Bad subfile size: %d", (int)expected);
|
|
return false;
|
|
}
|
|
|
|
const u32 off = header_.offsets[(int)file];
|
|
|
|
out->resize(expected);
|
|
if (expected == 0)
|
|
return true;
|
|
size_t bytes = file_->ReadAt(off, expected, out->data());
|
|
if (bytes != expected) {
|
|
ERROR_LOG(Log::Loader, "PBP file read truncated: %d -> %d", (int)expected, (int)bytes);
|
|
if (bytes < expected) {
|
|
out->resize(bytes);
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool PBPReader::GetSubFileAsString(PBPSubFile file, std::string *out) const {
|
|
if (!file_) {
|
|
out->clear();
|
|
return false;
|
|
}
|
|
|
|
const size_t expected = GetSubFileSize(file);
|
|
|
|
// This is only used to get the PNG, AT3 etc, so let's have a strict 256MB file size limit for sanity.
|
|
if (expected > 256 * 1024 * 1024) {
|
|
ERROR_LOG(Log::Loader, "Bad subfile size: %d", (int)expected);
|
|
return false;
|
|
}
|
|
const u32 off = header_.offsets[(int)file];
|
|
|
|
out->resize(expected);
|
|
size_t bytes = file_->ReadAt(off, expected, (void *)out->data());
|
|
if (bytes != expected) {
|
|
ERROR_LOG(Log::Loader, "PBP file read truncated: %d -> %d", (int)expected, (int)bytes);
|
|
if (bytes < expected) {
|
|
out->resize(bytes);
|
|
// should we still return true here?
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
PBPReader::~PBPReader() {
|
|
// Does not take ownership.
|
|
file_ = nullptr;
|
|
}
|