mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-11-12 17:19:28 +01:00
Firmware, PS1, PKG: Fix wrapping offsets
- PSAR: an entry's chunk size could wrap the u32 position back to an earlier entry, looping forever (this runs on a disc's DATA.BIN at boot). Entries must now end inside the archive. - MDS: the session offset check wrapped in u32, and the track name block wasn't checked at all, both reading gigabytes past the file. - PKG: check the data range without the u64 sum that could wrap. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
50e9b6691c
commit
c5673294ab
3 files changed
+11
-3
No files matched your search
@@ -428,13 +428,13 @@ bool PS1EbootFileLoader::ParseMds(const Path &mdsPath, const std::string &data)
|
||||
const u8 *d = (const u8 *)data.data();
|
||||
const size_t size = data.size();
|
||||
auto read32 = [&](size_t offset) -> u32 {
|
||||
return offset + 4 <= size ? (d[offset] | (d[offset + 1] << 8) | (d[offset + 2] << 16) | ((u32)d[offset + 3] << 24)) : 0;
|
||||
return offset <= size && size - offset >= 4 ? (d[offset] | (d[offset + 1] << 8) | (d[offset + 2] << 16) | ((u32)d[offset + 3] << 24)) : 0;
|
||||
};
|
||||
if (size < 0x58 || memcmp(d, "MEDIA DESCRIPTOR", 16) != 0) {
|
||||
return false;
|
||||
}
|
||||
const u32 session = read32(0x50);
|
||||
if (session + 0x18 > size) {
|
||||
if ((size_t)session + 0x18 > size) {
|
||||
return false;
|
||||
}
|
||||
const u32 numBlocks = d[session + 0x0A];
|
||||
@@ -466,6 +466,9 @@ bool PS1EbootFileLoader::ParseMds(const Path &mdsPath, const std::string &data)
|
||||
if (file < 0) {
|
||||
// "*.mdf" is the .mds's own name.
|
||||
const u32 nameBlock = read32(b + 0x34);
|
||||
if ((size_t)nameBlock + 5 > size) {
|
||||
return false;
|
||||
}
|
||||
const u32 nameOffset = read32(nameBlock);
|
||||
std::string name;
|
||||
for (u32 p = nameOffset; p < size && d[p] != 0; p += d[nameBlock + 4] ? 2 : 1) {
|
||||
|
||||
@@ -697,6 +697,11 @@ int PSARReader::NextEntry(std::string *error) {
|
||||
|
||||
const u32 chunkSize = ReadU32(block_.data() + 0x104);
|
||||
const u32 expandedSize = ReadU32(block_.data() + 0x108);
|
||||
// pos_ is a u32, so a huge chunk would wrap it back to an earlier entry and loop forever.
|
||||
if (chunkSize > limit_ - std::min((size_t)pos_, limit_)) {
|
||||
*error = StringFromFormat("Entry '%s' runs past the end of the archive (%u bytes)", entryName_.c_str(), chunkSize);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (expandedSize == 0) {
|
||||
entryIsDirectory_ = true;
|
||||
|
||||
@@ -187,7 +187,7 @@ bool PkgReader::Open(FileLoader *loader, std::string *error) {
|
||||
info_.contentId = contentId;
|
||||
|
||||
const s64 fileSize = loader->FileSize();
|
||||
if (fileSize < 0 || (u64)fileSize < totalSize || dataOffset_ + dataSize_ > (u64)fileSize) {
|
||||
if (fileSize < 0 || (u64)fileSize < totalSize || dataOffset_ > (u64)fileSize || dataSize_ > (u64)fileSize - dataOffset_) {
|
||||
*error = "PKG file is truncated";
|
||||
return false;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user