mirror of
https://github.com/OpenMW/openmw.git
synced 2025-10-17 20:16:39 +00:00
Fix potential overflows on reading BSA header
This commit is contained in:
parent
c87cc643d1
commit
16abb436e2
1 changed files with 16 additions and 9 deletions
|
@ -115,7 +115,8 @@ void BSAFile::readHeader(std::istream& input)
|
|||
fail("File too small to be a valid BSA archive");
|
||||
|
||||
// Get essential header numbers
|
||||
size_t dirsize, filenum;
|
||||
std::streamsize dirsize;
|
||||
std::streamsize filenum;
|
||||
{
|
||||
// First 12 bytes
|
||||
uint32_t head[3];
|
||||
|
@ -139,7 +140,7 @@ void BSAFile::readHeader(std::istream& input)
|
|||
// Each file must take up at least 21 bytes of data in the bsa. So
|
||||
// if files*21 overflows the file size then we are guaranteed that
|
||||
// the archive is corrupt.
|
||||
if ((filenum * 21 > unsigned(fsize - 12)) || (dirsize + 8 * filenum > unsigned(fsize - 12)))
|
||||
if (filenum * 21 > fsize - 12 || dirsize + 8 * filenum > fsize - 12)
|
||||
fail("Directory information larger than entire archive");
|
||||
|
||||
// Read the offset info into a temporary buffer
|
||||
|
@ -168,20 +169,22 @@ void BSAFile::readHeader(std::istream& input)
|
|||
// Calculate the offset of the data buffer. All file offsets are
|
||||
// relative to this. 12 header bytes + directory + hash table
|
||||
// (skipped)
|
||||
size_t fileDataOffset = 12 + dirsize + 8 * filenum;
|
||||
const std::streamsize fileDataOffset = 12 + dirsize + 8 * filenum;
|
||||
|
||||
// Set up the the FileStruct table
|
||||
mFiles.reserve(filenum);
|
||||
size_t endOfNameBuffer = 0;
|
||||
for (size_t i = 0; i < filenum; i++)
|
||||
for (std::streamsize i = 0; i < filenum; i++)
|
||||
{
|
||||
FileStruct& fs = mFiles.emplace_back();
|
||||
|
||||
const uint32_t fileSize = offsets[i * 2];
|
||||
const uint32_t offset = offsets[i * 2 + 1] + static_cast<uint32_t>(fileDataOffset);
|
||||
const std::streamsize offset = static_cast<std::streamsize>(offsets[i * 2 + 1]) + fileDataOffset;
|
||||
|
||||
if (fileSize + offset > fsize)
|
||||
fail("Archive contains offsets outside itself");
|
||||
fail(std::format("Archive contains offsets outside itself: {} + {} > {}", fileSize, offset, fsize));
|
||||
|
||||
if (offset > std::numeric_limits<uint32_t>::max())
|
||||
fail(std::format(
|
||||
"Absolute file {} offset is too large: {} > {}", i, offset, std::numeric_limits<uint32_t>::max()));
|
||||
|
||||
const uint32_t nameOffset = offsets[2 * filenum + i];
|
||||
|
||||
|
@ -196,13 +199,17 @@ void BSAFile::readHeader(std::istream& input)
|
|||
|
||||
const std::size_t nameSize = end - begin;
|
||||
|
||||
FileStruct fs;
|
||||
|
||||
fs.mFileSize = fileSize;
|
||||
fs.mOffset = offset;
|
||||
fs.mOffset = static_cast<uint32_t>(offset);
|
||||
fs.mHash = hashes[i];
|
||||
fs.mNameOffset = nameOffset;
|
||||
fs.mNameSize = static_cast<uint32_t>(nameSize);
|
||||
fs.mNamesBuffer = &mStringBuf;
|
||||
|
||||
mFiles.push_back(fs);
|
||||
|
||||
endOfNameBuffer = std::max(endOfNameBuffer, nameOffset + nameSize + 1);
|
||||
assert(endOfNameBuffer <= mStringBuf.size());
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue