mirror of
https://github.com/cemu-project/Cemu.git
synced 2026-07-10 09:34:40 -06:00
Filesystem: harden disc/title parsers against malformed input
- WUD: compute the index-table size in 64-bit and validate it against the file size before allocating, and null-check the allocation. A crafted uncompressedSize could previously overflow a 32-bit size and under-allocate, leading to out-of-bounds access. - WUHB: guard against a zero-sized hash table (division by zero) and cap hash-chain traversal to avoid an infinite loop on cyclic chains. - WUHB directory listing and FSA ReadDir: use bounded, always-NUL-terminated name copies (a 128-255 byte filename could overflow the guest response).
This commit is contained in:
parent
d973fde40b
commit
125355b7e1
@ -43,8 +43,20 @@ wud_t* wud_open(const fs::path& path)
|
||||
wud->offsetSectorArray = (wud->offsetSectorArray + (long long)(wud->sectorSize-1));
|
||||
wud->offsetSectorArray = wud->offsetSectorArray - (wud->offsetSectorArray%(long long)wud->sectorSize);
|
||||
// read index table
|
||||
unsigned int indexTableSize = sizeof(unsigned int) * wud->indexTableEntryCount;
|
||||
uint64 indexTableSize64 = (uint64)sizeof(unsigned int) * (uint64)wud->indexTableEntryCount;
|
||||
if (indexTableSize64 == 0 || indexTableSize64 > 0x40000000ull || indexTableSize64 > (uint64)inputFileSize)
|
||||
{
|
||||
// reject implausible/crafted index table sizes to avoid integer overflow and over-allocation
|
||||
wud_close(wud);
|
||||
return nullptr;
|
||||
}
|
||||
unsigned int indexTableSize = (unsigned int)indexTableSize64;
|
||||
wud->indexTable = (unsigned int*)malloc(indexTableSize);
|
||||
if (!wud->indexTable)
|
||||
{
|
||||
wud_close(wud);
|
||||
return nullptr;
|
||||
}
|
||||
wud->fs->SetPosition(wud->offsetIndexTable);
|
||||
if( wud->fs->readData(wud->indexTable, indexTableSize) != indexTableSize )
|
||||
{
|
||||
|
||||
@ -115,6 +115,8 @@ uint32 WUHBReader::GetHashTableEntryOffset(uint32 hash, bool isFile) const
|
||||
const uint64 hash_table_ofs = (isFile ? m_header.file_hash_table_ofs : m_header.dir_hash_table_ofs);
|
||||
|
||||
const uint64 hash_table_entry_count = hash_table_size / sizeof(uint32);
|
||||
if (hash_table_entry_count == 0)
|
||||
return ROMFS_ENTRY_EMPTY;
|
||||
const uint64 hash_table_entry_offset = hash_table_ofs + (hash % hash_table_entry_count) * sizeof(uint32);
|
||||
|
||||
m_fileIn->SetPosition(hash_table_entry_offset);
|
||||
@ -131,10 +133,15 @@ uint32 WUHBReader::GetHashTableEntryOffset(uint32 hash, bool isFile) const
|
||||
template<bool T>
|
||||
bool WUHBReader::SearchHashList(uint32& entryOffset, const fs::path& targetName) const
|
||||
{
|
||||
for (;;)
|
||||
for (uint32 iterations = 0; ; iterations++)
|
||||
{
|
||||
if (entryOffset == ROMFS_ENTRY_EMPTY)
|
||||
return false;
|
||||
if (iterations >= 0x100000)
|
||||
{
|
||||
cemuLog_log(LogType::Force, "WUHB: aborting suspected cyclic hash chain");
|
||||
return false;
|
||||
}
|
||||
auto entry = GetEntry<T>(entryOffset);
|
||||
|
||||
if (entry.name == targetName)
|
||||
|
||||
@ -75,7 +75,8 @@ class FSCDeviceWuhbFileCtx : public FSCVirtualFile
|
||||
dirEntry->isDirectory = true;
|
||||
dirEntry->isFile = false;
|
||||
dirEntry->fileSize = 0;
|
||||
std::strncpy(dirEntry->path, entry.name.c_str(), FSC_MAX_DIR_NAME_LENGTH);
|
||||
std::strncpy(dirEntry->path, entry.name.c_str(), FSC_MAX_DIR_NAME_LENGTH - 1);
|
||||
dirEntry->path[FSC_MAX_DIR_NAME_LENGTH - 1] = '\0';
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -88,7 +89,8 @@ class FSCDeviceWuhbFileCtx : public FSCVirtualFile
|
||||
dirEntry->isDirectory = false;
|
||||
dirEntry->isFile = true;
|
||||
dirEntry->fileSize = entry.size;
|
||||
std::strncpy(dirEntry->path, entry.name.c_str(), FSC_MAX_DIR_NAME_LENGTH);
|
||||
std::strncpy(dirEntry->path, entry.name.c_str(), FSC_MAX_DIR_NAME_LENGTH - 1);
|
||||
dirEntry->path[FSC_MAX_DIR_NAME_LENGTH - 1] = '\0';
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -556,7 +556,8 @@ namespace iosu
|
||||
FSCDirEntry fscDirEntry;
|
||||
if (fsc_nextDir(fscFile, &fscDirEntry) == false)
|
||||
return FSA_RESULT::END_OF_DIRECTORY;
|
||||
strcpy(dirEntryOut->name, fscDirEntry.path);
|
||||
strncpy(dirEntryOut->name, fscDirEntry.path, sizeof(dirEntryOut->name));
|
||||
dirEntryOut->name[sizeof(dirEntryOut->name) - 1] = '\0';
|
||||
FSFlag statFlag = FSFlag::NONE;
|
||||
dirEntryOut->stat.size = 0;
|
||||
if (fscDirEntry.isDirectory)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user