diff --git a/Source/Core/Core/IOS/ES/Formats.cpp b/Source/Core/Core/IOS/ES/Formats.cpp index 49ae0e3918..97eba84154 100644 --- a/Source/Core/Core/IOS/ES/Formats.cpp +++ b/Source/Core/Core/IOS/ES/Formats.cpp @@ -57,6 +57,11 @@ bool Content::IsShared() const return (type & 0x8000) != 0; } +bool IsValidTMDSize(size_t size) +{ + return size <= 0x49e4; +} + TMDReader::TMDReader(const std::vector& bytes) : m_bytes(bytes) { } diff --git a/Source/Core/Core/IOS/ES/Formats.h b/Source/Core/Core/IOS/ES/Formats.h index 0c43809b52..e90cb089b4 100644 --- a/Source/Core/Core/IOS/ES/Formats.h +++ b/Source/Core/Core/IOS/ES/Formats.h @@ -130,6 +130,8 @@ struct Ticket static_assert(sizeof(Ticket) == 0x2A4, "Ticket has the wrong size"); #pragma pack(pop) +bool IsValidTMDSize(size_t size); + class TMDReader final { public: diff --git a/Source/Core/Core/IOS/ES/TitleManagement.cpp b/Source/Core/Core/IOS/ES/TitleManagement.cpp index 79b625ce59..487b799d99 100644 --- a/Source/Core/Core/IOS/ES/TitleManagement.cpp +++ b/Source/Core/Core/IOS/ES/TitleManagement.cpp @@ -91,6 +91,9 @@ IPCCommandResult ES::ImportTmd(Context& context, const IOCtlVRequest& request) if (!request.HasNumberOfValidVectors(1, 0)) return GetDefaultReply(ES_EINVAL); + if (!IOS::ES::IsValidTMDSize(request.in_vectors[0].size)) + return GetDefaultReply(ES_EINVAL); + std::vector tmd(request.in_vectors[0].size); Memory::CopyFromEmu(tmd.data(), request.in_vectors[0].address, request.in_vectors[0].size); return GetDefaultReply(ImportTmd(context, tmd)); @@ -131,6 +134,9 @@ IPCCommandResult ES::ImportTitleInit(Context& context, const IOCtlVRequest& requ if (!request.HasNumberOfValidVectors(4, 0)) return GetDefaultReply(ES_EINVAL); + if (!IOS::ES::IsValidTMDSize(request.in_vectors[0].size)) + return GetDefaultReply(ES_EINVAL); + std::vector tmd(request.in_vectors[0].size); Memory::CopyFromEmu(tmd.data(), request.in_vectors[0].address, request.in_vectors[0].size); return GetDefaultReply(ImportTitleInit(context, tmd)); diff --git a/Source/Core/DiscIO/VolumeWad.cpp b/Source/Core/DiscIO/VolumeWad.cpp index f170abdd47..86932f897b 100644 --- a/Source/Core/DiscIO/VolumeWad.cpp +++ b/Source/Core/DiscIO/VolumeWad.cpp @@ -41,7 +41,7 @@ CVolumeWAD::CVolumeWAD(std::unique_ptr reader) : m_reader(std::move m_opening_bnr_offset = m_tmd_offset + Common::AlignUp(m_tmd_size, 0x40) + Common::AlignUp(m_data_size, 0x40); - if (m_tmd_size > 1024 * 1024 * 4) + if (!IOS::ES::IsValidTMDSize(m_tmd_size)) { ERROR_LOG(DISCIO, "TMD is too large: %u bytes", m_tmd_size); return; diff --git a/Source/Core/DiscIO/VolumeWiiCrypted.cpp b/Source/Core/DiscIO/VolumeWiiCrypted.cpp index c2826c6515..5e088a9422 100644 --- a/Source/Core/DiscIO/VolumeWiiCrypted.cpp +++ b/Source/Core/DiscIO/VolumeWiiCrypted.cpp @@ -81,13 +81,11 @@ CVolumeWiiCrypted::CVolumeWiiCrypted(std::unique_ptr reader) if (!m_pReader->ReadSwapped(partition_offset + 0x2a8, &tmd_address)) continue; tmd_address <<= 2; - if (tmd_size > 1024 * 1024 * 4) + if (!IOS::ES::IsValidTMDSize(tmd_size)) { - // The size is checked so that a malicious or corrupt ISO - // can't force Dolphin to allocate up to 4 GiB of memory. - // 4 MiB should be much bigger than the size of TMDs and much smaller - // than the amount of RAM in a computer that can run Dolphin. - PanicAlert("TMD > 4 MiB"); + // This check is normally done by ES in ES_DiVerify, but that would happen too late + // (after allocating the buffer), so we do the check here. + PanicAlert("Invalid TMD size"); continue; } std::vector tmd_buffer(tmd_size);