NBT: Dynamic list-max-count protection. (#4697)
This commit is contained in:
parent
38080c7cac
commit
dfe7a0adee
@ -10,13 +10,6 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** If a list being loaded has more than this number of items, it's considered corrupted. */
|
|
||||||
static const int MAX_LIST_ITEMS = 10000;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// The number of NBT tags that are reserved when an NBT parsing is started.
|
// The number of NBT tags that are reserved when an NBT parsing is started.
|
||||||
// You can override this by using a cmdline define
|
// You can override this by using a cmdline define
|
||||||
#ifndef NBT_RESERVE_SIZE
|
#ifndef NBT_RESERVE_SIZE
|
||||||
@ -257,7 +250,8 @@ eNBTParseError cParsedNBT::ReadList(eTagType a_ChildrenType)
|
|||||||
NEEDBYTES(4, eNBTParseError::npListMissingLength);
|
NEEDBYTES(4, eNBTParseError::npListMissingLength);
|
||||||
int Count = GetBEInt(m_Data + m_Pos);
|
int Count = GetBEInt(m_Data + m_Pos);
|
||||||
m_Pos += 4;
|
m_Pos += 4;
|
||||||
if ((Count < 0) || (Count > MAX_LIST_ITEMS))
|
auto MinChildSize = GetMinTagSize(a_ChildrenType);
|
||||||
|
if ((Count < 0) || (Count > static_cast<int>((m_Length - m_Pos) / MinChildSize)))
|
||||||
{
|
{
|
||||||
return eNBTParseError::npListInvalidLength;
|
return eNBTParseError::npListInvalidLength;
|
||||||
}
|
}
|
||||||
@ -445,6 +439,30 @@ int cParsedNBT::FindTagByPath(int a_Tag, const AString & a_Path) const
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
size_t cParsedNBT::GetMinTagSize(eTagType a_TagType)
|
||||||
|
{
|
||||||
|
switch (a_TagType)
|
||||||
|
{
|
||||||
|
case TAG_End: return 1;
|
||||||
|
case TAG_Byte: return 1;
|
||||||
|
case TAG_Short: return 2;
|
||||||
|
case TAG_Int: return 4;
|
||||||
|
case TAG_Long: return 8;
|
||||||
|
case TAG_Float: return 4;
|
||||||
|
case TAG_Double: return 8;
|
||||||
|
case TAG_String: return 2; // 2 bytes for the string length
|
||||||
|
case TAG_ByteArray: return 4; // 4 bytes for the count
|
||||||
|
case TAG_List: return 5; // 1 byte list type + 4 bytes count
|
||||||
|
case TAG_Compound: return 1; // Single TAG_End byte
|
||||||
|
case TAG_IntArray: return 4; // 4 bytes for the count
|
||||||
|
}
|
||||||
|
UNREACHABLE("Unsupported nbt tag type");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// cFastNBTWriter:
|
// cFastNBTWriter:
|
||||||
|
|
||||||
|
@ -307,6 +307,10 @@ protected:
|
|||||||
eNBTParseError ReadCompound(void); // Reads the latest tag as a compound
|
eNBTParseError ReadCompound(void); // Reads the latest tag as a compound
|
||||||
eNBTParseError ReadList(eTagType a_ChildrenType); // Reads the latest tag as a list of items of type a_ChildrenType
|
eNBTParseError ReadList(eTagType a_ChildrenType); // Reads the latest tag as a list of items of type a_ChildrenType
|
||||||
eNBTParseError ReadTag(void); // Reads the latest tag, depending on its m_Type setting
|
eNBTParseError ReadTag(void); // Reads the latest tag, depending on its m_Type setting
|
||||||
|
|
||||||
|
/** Returns the minimum size, in bytes, of the specified tag type.
|
||||||
|
Used for sanity-checking. */
|
||||||
|
static size_t GetMinTagSize(eTagType a_TagType);
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
@ -326,7 +326,8 @@ bool cWSSAnvil::LoadChunkFromData(const cChunkCoords & a_Chunk, const AString &
|
|||||||
if (!NBT.IsValid())
|
if (!NBT.IsValid())
|
||||||
{
|
{
|
||||||
// NBT Parsing failed
|
// NBT Parsing failed
|
||||||
ChunkLoadFailed(a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ, "NBT parsing failed", a_Data);
|
auto msg = fmt::format("NBT parsing failed: {}, pos {}", NBT.GetErrorCode().message(), NBT.GetErrorPos());
|
||||||
|
ChunkLoadFailed(a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ, msg, a_Data);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3520,8 +3521,8 @@ bool cWSSAnvil::cMCAFile::GetChunkData(const cChunkCoords & a_Chunk, AString & a
|
|||||||
m_ParentSchema.ChunkLoadFailed(a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ, Printf("Unknown chunk compression: %d", CompressionType).c_str(), a_Data);
|
m_ParentSchema.ChunkLoadFailed(a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ, Printf("Unknown chunk compression: %d", CompressionType).c_str(), a_Data);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user