aboutsummaryrefslogtreecommitdiff
path: root/Minecraft.World
diff options
context:
space:
mode:
authorLoki Rautio <lokirautio@gmail.com>2026-03-09 04:45:14 -0500
committerLoki Rautio <lokirautio@gmail.com>2026-03-09 04:45:14 -0500
commitd557ca2dfba5ffcca99ceb41b07d149f871964b5 (patch)
tree89ef5bd5fdb2a86fe10a5dead65b65bce8aa0a1d /Minecraft.World
parent0c4f4599045edad935403e4d79d28f6b9aa95833 (diff)
LCEMP RCE fixes
Based on commit d017bfc30a68888bf5c79b23cf5c4f607cf828bf
Diffstat (limited to 'Minecraft.World')
-rw-r--r--Minecraft.World/AwardStatPacket.cpp2
-rw-r--r--Minecraft.World/BlockRegionUpdatePacket.cpp6
-rw-r--r--Minecraft.World/ByteArrayInputStream.cpp13
-rw-r--r--Minecraft.World/ByteArrayOutputStream.cpp18
-rw-r--r--Minecraft.World/ByteArrayTag.h1
-rw-r--r--Minecraft.World/ComplexItemDataPacket.cpp7
-rw-r--r--Minecraft.World/CompoundTag.h14
-rw-r--r--Minecraft.World/Connection.cpp4
-rw-r--r--Minecraft.World/ContainerSetContentPacket.cpp3
-rw-r--r--Minecraft.World/ContainerSetSlotPacket.cpp2
-rw-r--r--Minecraft.World/CustomPayloadPacket.cpp2
-rw-r--r--Minecraft.World/DataInputStream.cpp4
-rw-r--r--Minecraft.World/ExplodePacket.cpp2
-rw-r--r--Minecraft.World/GameCommandPacket.cpp2
-rw-r--r--Minecraft.World/IntArrayTag.h2
-rw-r--r--Minecraft.World/ListTag.h11
-rw-r--r--Minecraft.World/Packet.cpp50
-rw-r--r--Minecraft.World/PreLoginPacket.cpp1
-rw-r--r--Minecraft.World/RemoveEntitiesPacket.cpp4
-rw-r--r--Minecraft.World/Socket.cpp5
-rw-r--r--Minecraft.World/SynchedEntityData.cpp6
-rw-r--r--Minecraft.World/Tag.cpp39
-rw-r--r--Minecraft.World/TextureAndGeometryPacket.cpp29
-rw-r--r--Minecraft.World/TexturePacket.cpp25
-rw-r--r--Minecraft.World/ThreadName.cpp6
-rw-r--r--Minecraft.World/UpdateGameRuleProgressPacket.cpp2
-rw-r--r--Minecraft.World/compression.cpp42
27 files changed, 222 insertions, 80 deletions
diff --git a/Minecraft.World/AwardStatPacket.cpp b/Minecraft.World/AwardStatPacket.cpp
index 07888541..b2950a0e 100644
--- a/Minecraft.World/AwardStatPacket.cpp
+++ b/Minecraft.World/AwardStatPacket.cpp
@@ -47,7 +47,7 @@ void AwardStatPacket::read(DataInputStream *dis) //throws IOException
// Read parameter blob.
int length = dis->readInt();
- if(length > 0)
+ if (length > 0 && length <= 65536)
{
m_paramData = byteArray(length);
dis->readFully(m_paramData);
diff --git a/Minecraft.World/BlockRegionUpdatePacket.cpp b/Minecraft.World/BlockRegionUpdatePacket.cpp
index 730ce3ed..b91cf4f8 100644
--- a/Minecraft.World/BlockRegionUpdatePacket.cpp
+++ b/Minecraft.World/BlockRegionUpdatePacket.cpp
@@ -105,6 +105,12 @@ void BlockRegionUpdatePacket::read(DataInputStream *dis) //throws IOException
levelIdx = ( size >> 30 ) & 3;
size &= 0x3fffffff;
+ const int MAX_COMPRESSED_CHUNK_SIZE = 5 * 1024 * 1024;
+ if (size < 0 || size > MAX_COMPRESSED_CHUNK_SIZE)
+ {
+ size = 0;
+ }
+
if(size == 0)
{
buffer = byteArray();
diff --git a/Minecraft.World/ByteArrayInputStream.cpp b/Minecraft.World/ByteArrayInputStream.cpp
index d79eff36..9509206d 100644
--- a/Minecraft.World/ByteArrayInputStream.cpp
+++ b/Minecraft.World/ByteArrayInputStream.cpp
@@ -10,8 +10,19 @@
//offset - the offset in the buffer of the first byte to read.
//length - the maximum number of bytes to read from the buffer.
ByteArrayInputStream::ByteArrayInputStream(byteArray buf, unsigned int offset, unsigned int length)
- : pos( offset ), count( min( offset+length, buf.length ) ), mark( offset )
+ : pos(offset), mark(offset)
{
+ if (offset > buf.length)
+ {
+ count = buf.length;
+ }
+ else if (length > buf.length - offset)
+ {
+ count = buf.length;
+ }
+ else
+ {
+ count = offset + length;
this->buf = buf;
}
diff --git a/Minecraft.World/ByteArrayOutputStream.cpp b/Minecraft.World/ByteArrayOutputStream.cpp
index a9f36e04..a6fdad8f 100644
--- a/Minecraft.World/ByteArrayOutputStream.cpp
+++ b/Minecraft.World/ByteArrayOutputStream.cpp
@@ -53,9 +53,25 @@ void ByteArrayOutputStream::write(byteArray b, unsigned int offset, unsigned int
{
assert( b.length >= offset + length );
+ if (offset > b.length || length > b.length - offset)
+ {
+ return;
+ }
+
+ if (length > 0xFFFFFFFF - count)
+ {
+ return;
+
// If we will fill the buffer we need to make it bigger
if( count + length >= buf.length )
- buf.resize( max( count + length + 1, buf.length * 2 ) );
+ {
+ unsigned int newSize = (std::max)(count + length + 1, buf.length * 2);
+ if (newSize <= buf.length)
+ {
+ return;
+ }
+ buf.resize(newSize);
+ }
XMemCpy( &buf[count], &b[offset], length );
//std::copy( b->data+offset, b->data+offset+length, buf->data + count ); // Or this instead?
diff --git a/Minecraft.World/ByteArrayTag.h b/Minecraft.World/ByteArrayTag.h
index 1d3e3875..4d53c63e 100644
--- a/Minecraft.World/ByteArrayTag.h
+++ b/Minecraft.World/ByteArrayTag.h
@@ -21,6 +21,7 @@ public:
void load(DataInput *dis, int tagDepth)
{
int length = dis->readInt();
+ if (length < 0 || length > 2 * 1024 * 1024) length = 0;
if ( data.data ) delete[] data.data;
data = byteArray(length);
diff --git a/Minecraft.World/ComplexItemDataPacket.cpp b/Minecraft.World/ComplexItemDataPacket.cpp
index 38c39cb6..98eeb9de 100644
--- a/Minecraft.World/ComplexItemDataPacket.cpp
+++ b/Minecraft.World/ComplexItemDataPacket.cpp
@@ -32,7 +32,12 @@ void ComplexItemDataPacket::read(DataInputStream *dis) //throws IOException
itemType = dis->readShort();
itemId = dis->readShort();
- data = charArray(dis->readUnsignedShort() & 0xffff);
+ int dataLength = dis->readShort() & 0xffff;
+ if (dataLength > 32767)
+ {
+ dataLength = 0;
+ }
+ data = charArray(dataLength);
dis->readFully(data);
}
diff --git a/Minecraft.World/CompoundTag.h b/Minecraft.World/CompoundTag.h
index 5eaa2a05..8f4d045d 100644
--- a/Minecraft.World/CompoundTag.h
+++ b/Minecraft.World/CompoundTag.h
@@ -42,10 +42,16 @@ public:
}
tags.clear();
Tag *tag;
- while ((tag = Tag::readNamedTag(dis))->getId() != Tag::TAG_End)
- {
- tags[tag->getName()] = tag;
- }
+ int tagCount = 0;
+ const int MAX_COMPOUND_TAGS = 10000;
+ while ((tag = Tag::readNamedTag(dis))->getId() != Tag::TAG_End)
+ {
+ tags[tag->getName()] = tag;
+ if (++tagCount >= MAX_COMPOUND_TAGS)
+ {
+ break;
+ }
+ }
delete tag;
}
diff --git a/Minecraft.World/Connection.cpp b/Minecraft.World/Connection.cpp
index 7f10dc4a..d4450266 100644
--- a/Minecraft.World/Connection.cpp
+++ b/Minecraft.World/Connection.cpp
@@ -108,8 +108,8 @@ Connection::Connection(Socket *socket, const wstring& id, PacketListener *packet
const char *szId = wstringtofilename(id);
char readThreadName[256];
char writeThreadName[256];
- sprintf(readThreadName,"%s read\n",szId);
- sprintf(writeThreadName,"%s write\n",szId);
+ sprintf_s(readThreadName, sizeof(readThreadName), "%.240s read\n", szId);
+ sprintf_s(writeThreadName, sizeof(writeThreadName), "%.240s write\n", szId);
readThread = new C4JThread(runRead, static_cast<void *>(this), readThreadName, READ_STACK_SIZE);
writeThread = new C4JThread(runWrite, this, writeThreadName, WRITE_STACK_SIZE);
diff --git a/Minecraft.World/ContainerSetContentPacket.cpp b/Minecraft.World/ContainerSetContentPacket.cpp
index ae76e0f0..28ce64e9 100644
--- a/Minecraft.World/ContainerSetContentPacket.cpp
+++ b/Minecraft.World/ContainerSetContentPacket.cpp
@@ -32,6 +32,9 @@ void ContainerSetContentPacket::read(DataInputStream *dis) //throws IOException
{
containerId = dis->readByte();
int count = dis->readShort();
+
+ if (count < 0 || count > 256) count = 0;
+
items = ItemInstanceArray(count);
for (int i = 0; i < count; i++)
{
diff --git a/Minecraft.World/ContainerSetSlotPacket.cpp b/Minecraft.World/ContainerSetSlotPacket.cpp
index 6a038244..de8d2680 100644
--- a/Minecraft.World/ContainerSetSlotPacket.cpp
+++ b/Minecraft.World/ContainerSetSlotPacket.cpp
@@ -35,7 +35,7 @@ void ContainerSetSlotPacket::read(DataInputStream *dis) //throws IOException
// 4J Stu - TU-1 hotfix
// Fix for #13142 - Holding down the A button on the furnace ingredient slot causes the UI to display incorrect item counts
BYTE byteId = dis->readByte();
- containerId = *(char *)&byteId;
+ containerId = (char)(signed char)byteId;
slot = dis->readShort();
item = readItem(dis);
}
diff --git a/Minecraft.World/CustomPayloadPacket.cpp b/Minecraft.World/CustomPayloadPacket.cpp
index 46fde5aa..e86f01de 100644
--- a/Minecraft.World/CustomPayloadPacket.cpp
+++ b/Minecraft.World/CustomPayloadPacket.cpp
@@ -43,7 +43,7 @@ void CustomPayloadPacket::read(DataInputStream *dis)
identifier = readUtf(dis, 20);
length = dis->readShort();
- if (length > 0 && length < Short::MAX_VALUE)
+ if (length > 0 && length <= Short::MAX_VALUE)
{
if(data.data != nullptr)
{
diff --git a/Minecraft.World/DataInputStream.cpp b/Minecraft.World/DataInputStream.cpp
index 4e4f5cd1..0cd21a7e 100644
--- a/Minecraft.World/DataInputStream.cpp
+++ b/Minecraft.World/DataInputStream.cpp
@@ -303,6 +303,10 @@ wstring DataInputStream::readUTF()
int b = stream->read();
unsigned short UTFLength = static_cast<unsigned short>(((a & 0xff) << 8) | (b & 0xff));
+ const unsigned short MAX_UTF_LENGTH = 32767;
+ if (UTFLength > MAX_UTF_LENGTH)
+ return outputString;
+
//// 4J Stu - I decided while writing DataOutputStream that we didn't need to bother using the UTF8 format
//// used in the java libs, and just write in/out as wchar_t all the time
diff --git a/Minecraft.World/ExplodePacket.cpp b/Minecraft.World/ExplodePacket.cpp
index 07626161..88bf00c6 100644
--- a/Minecraft.World/ExplodePacket.cpp
+++ b/Minecraft.World/ExplodePacket.cpp
@@ -52,6 +52,8 @@ void ExplodePacket::read(DataInputStream *dis) //throws IOException
r = dis->readFloat();
int count = dis->readInt();
+ if (count < 0 || count > 32768) count = 0;
+
int xp = static_cast<int>(x);
int yp = static_cast<int>(y);
int zp = static_cast<int>(z);
diff --git a/Minecraft.World/GameCommandPacket.cpp b/Minecraft.World/GameCommandPacket.cpp
index 17c5316a..ada5b04c 100644
--- a/Minecraft.World/GameCommandPacket.cpp
+++ b/Minecraft.World/GameCommandPacket.cpp
@@ -40,7 +40,7 @@ void GameCommandPacket::read(DataInputStream *dis)
command = static_cast<EGameCommand>(dis->readInt());
length = dis->readShort();
- if (length > 0 && length < Short::MAX_VALUE)
+ if (length > 0 && length <= Short::MAX_VALUE)
{
if(data.data != nullptr)
{
diff --git a/Minecraft.World/IntArrayTag.h b/Minecraft.World/IntArrayTag.h
index 61ca59d0..64a4d004 100644
--- a/Minecraft.World/IntArrayTag.h
+++ b/Minecraft.World/IntArrayTag.h
@@ -35,6 +35,8 @@ public:
void load(DataInput *dis, int tagDepth)
{
int length = dis->readInt();
+ if (length < 0 || length > 65536)
+ length = 0;
if ( data.data ) delete[] data.data;
data = intArray(length);
diff --git a/Minecraft.World/ListTag.h b/Minecraft.World/ListTag.h
index 2a0fdebc..f6e1c6a0 100644
--- a/Minecraft.World/ListTag.h
+++ b/Minecraft.World/ListTag.h
@@ -26,21 +26,16 @@ public:
void load(DataInput *dis, int tagDepth)
{
- if (tagDepth > MAX_DEPTH)
- {
-#ifndef _CONTENT_PACKAGE
- printf("Tried to read NBT tag with too high complexity, depth > %d", MAX_DEPTH);
- __debugbreak();
-#endif
- return;
- }
type = dis->readByte();
int size = dis->readInt();
+ if (size < 0 || size > MAX_DEPTH)
+ size = 0;
list.clear();
for (int i = 0; i < size; i++)
{
Tag *tag = Tag::newTag(type, L"");
+ if (tag == nullptr) break;
tag->load(dis, tagDepth);
list.push_back(tag);
}
diff --git a/Minecraft.World/Packet.cpp b/Minecraft.World/Packet.cpp
index 129024b7..05bf932d 100644
--- a/Minecraft.World/Packet.cpp
+++ b/Minecraft.World/Packet.cpp
@@ -267,8 +267,12 @@ void Packet::updatePacketStatsPIX()
shared_ptr<Packet> Packet::getPacket(int id)
{
- // 4J: Removed try/catch
- return idToCreateMap[id]();
+ auto it = idToCreateMap.find(id);
+ if (it == idToCreateMap.end())
+ {
+ return nullptr;
+ }
+ return it->second();
}
void Packet::writeBytes(DataOutputStream *dataoutputstream, byteArray bytes)
@@ -334,30 +338,11 @@ shared_ptr<Packet> Packet::readPacket(DataInputStream *dis, bool isServer) // th
if ((isServer && serverReceivedPackets.find(id) == serverReceivedPackets.end()) || (!isServer && clientReceivedPackets.find(id) == clientReceivedPackets.end()))
{
- app.DebugPrintf("*** BAD PACKET ID %d (0x%02X) isServer=%d totalPacketsRead=%d\n", id, id, isServer ? 1 : 0, s_packetCount);
- app.DebugPrintf("*** Last %d good packet IDs (oldest first): ", 8);
- for (int dbg = 0; dbg < 8; dbg++)
- {
- int idx = (s_lastIdPos + dbg) % 8;
- app.DebugPrintf("%d ", s_lastIds[idx]);
- }
- app.DebugPrintf("\n");
- // Dump the next 32 bytes from the stream to see what follows
- app.DebugPrintf("*** Next bytes in stream: ");
- for (int dbg = 0; dbg < 32; dbg++)
- {
- int b = dis->read();
- if (b == -1) { app.DebugPrintf("[EOS] "); break; }
- app.DebugPrintf("%02X ", b);
- }
- app.DebugPrintf("\n");
- __debugbreak();
- assert(false);
- // throw new IOException(wstring(L"Bad packet id ") + std::to_wstring(id));
+ return nullptr;
}
packet = getPacket(id);
- if (packet == nullptr) assert(false);//throw new IOException(wstring(L"Bad packet id ") + std::to_wstring(id));
+ if (packet == nullptr) return nullptr;//throw new IOException(wstring(L"Bad packet id ") + std::to_wstring(id));
s_lastIds[s_lastIdPos] = id;
s_lastIdPos = (s_lastIdPos + 1) % 8;
@@ -418,11 +403,9 @@ wstring Packet::readUtf(DataInputStream *dis, int maxLength) // throws IOExcepti
{
short stringLength = dis->readShort();
- if (stringLength > maxLength)
+ if (stringLength > maxLength || stringLength <= 0)
{
- wstringstream stream;
- stream << L"Received string length longer than maximum allowed (" << stringLength << " > " << maxLength << ")";
- assert(false);
+ return L"";
// throw new IOException( stream.str() );
}
if (stringLength < 0)
@@ -531,7 +514,7 @@ shared_ptr<ItemInstance> Packet::readItem(DataInputStream *dis)
{
shared_ptr<ItemInstance> item = nullptr;
int id = dis->readShort();
- if (id >= 0)
+ if (id >= 0 && id < 32000) // todo: should turn Item::ITEM_NUM_COUNT into a global define
{
int count = dis->readByte();
int damage = dis->readShort();
@@ -569,9 +552,16 @@ void Packet::writeItem(shared_ptr<ItemInstance> item, DataOutputStream *dos)
CompoundTag *Packet::readNbt(DataInputStream *dis)
{
int size = dis->readShort();
- if (size < 0) return nullptr;
+ if (size <= 0) return nullptr;
+
+ const int MAX_NBT_SIZE = 32767;
+ if (size > MAX_NBT_SIZE) return nullptr;
byteArray buff(size);
- dis->readFully(buff);
+ if (!dis->readFully(buff))
+ {
+ delete [] buff.data;
+ return nullptr;
+ }
CompoundTag *result = (CompoundTag *) NbtIo::decompress(buff);
delete [] buff.data;
return result;
diff --git a/Minecraft.World/PreLoginPacket.cpp b/Minecraft.World/PreLoginPacket.cpp
index aa6832ca..a88b9641 100644
--- a/Minecraft.World/PreLoginPacket.cpp
+++ b/Minecraft.World/PreLoginPacket.cpp
@@ -62,6 +62,7 @@ void PreLoginPacket::read(DataInputStream *dis) //throws IOException
m_friendsOnlyBits = dis->readByte();
m_ugcPlayersVersion = dis->readInt();
m_dwPlayerCount = dis->readByte();
+ if( m_dwPlayerCount > MINECRAFT_NET_MAX_PLAYERS ) m_dwPlayerCount = MINECRAFT_NET_MAX_PLAYERS;
if( m_dwPlayerCount > 0 )
{
m_playerXuids = new PlayerUID[m_dwPlayerCount];
diff --git a/Minecraft.World/RemoveEntitiesPacket.cpp b/Minecraft.World/RemoveEntitiesPacket.cpp
index 609cfa77..4c5e3313 100644
--- a/Minecraft.World/RemoveEntitiesPacket.cpp
+++ b/Minecraft.World/RemoveEntitiesPacket.cpp
@@ -21,7 +21,9 @@ RemoveEntitiesPacket::~RemoveEntitiesPacket()
void RemoveEntitiesPacket::read(DataInputStream *dis) //throws IOException
{
- ids = intArray(dis->readByte());
+ int count = dis->readByte();
+ if(count < 0) count = 0;
+ ids = intArray(count);
for(unsigned int i = 0; i < ids.length; ++i)
{
ids[i] = dis->readInt();
diff --git a/Minecraft.World/Socket.cpp b/Minecraft.World/Socket.cpp
index 2d5b257d..41ac3702 100644
--- a/Minecraft.World/Socket.cpp
+++ b/Minecraft.World/Socket.cpp
@@ -141,6 +141,11 @@ void Socket::pushDataToQueue(const BYTE * pbData, DWORD dwDataSize, bool fromHos
// dwDataSize, queueIdx, dwDataSize > 0 ? pbData[0] : 0, networkPlayerSmallId);
EnterCriticalSection(&m_queueLockNetwork[queueIdx]);
+ if (m_queueNetwork[queueIdx].size() + dwDataSize > 2 * 1024 * 1024)
+ {
+ LeaveCriticalSection(&m_queueLockNetwork[queueIdx]);
+ return;
+ }
for( unsigned int i = 0; i < dwDataSize; i++ )
{
m_queueNetwork[queueIdx].push(*pbData++);
diff --git a/Minecraft.World/SynchedEntityData.cpp b/Minecraft.World/SynchedEntityData.cpp
index 69d419b0..67b9597b 100644
--- a/Minecraft.World/SynchedEntityData.cpp
+++ b/Minecraft.World/SynchedEntityData.cpp
@@ -342,7 +342,10 @@ vector<shared_ptr<SynchedEntityData::DataItem> > *SynchedEntityData::unpack(Data
int currentHeader = input->readByte();
- while (currentHeader != EOF_MARKER)
+ int itemCount = 0;
+ const int MAX_ENTITY_DATA_ITEMS = 256;
+
+ while (currentHeader != EOF_MARKER && itemCount < MAX_ENTITY_DATA_ITEMS)
{
if (result == nullptr)
@@ -397,6 +400,7 @@ vector<shared_ptr<SynchedEntityData::DataItem> > *SynchedEntityData::unpack(Data
break;
}
result->push_back(item);
+ itemCount++;
currentHeader = input->readByte();
}
diff --git a/Minecraft.World/Tag.cpp b/Minecraft.World/Tag.cpp
index b594bb0e..eafdc9e8 100644
--- a/Minecraft.World/Tag.cpp
+++ b/Minecraft.World/Tag.cpp
@@ -84,27 +84,56 @@ Tag *Tag::readNamedTag(DataInput *dis)
Tag *Tag::readNamedTag(DataInput *dis, int tagDepth)
{
+ static __declspec(thread) int depth = 0;
+ static __declspec(thread) int totalTagCount = 0;
+
+ if (depth == 0)
+ {
+ totalTagCount = 0;
+ }
+
+ depth++;
+
+ if (depth > 256)
+ {
+ depth--;
+ return new EndTag();
+ }
+
+ totalTagCount++;
+ const int MAX_TOTAL_TAGS = 32768;
+ if (totalTagCount > MAX_TOTAL_TAGS)
+ {
+ depth--;
+ return new EndTag();
+ }
+
byte type = dis->readByte();
- if (type == 0) return new EndTag();
+ if (type == 0) {
+ depth--;
+ return new EndTag();
+ }
// 4J Stu - readByte can return -1, so if it's that then also mark as the end tag
if(type == 255)
{
- app.DebugPrintf("readNamedTag read a type of 255\n");
-#ifndef _CONTENT_PACKAGE
- __debugbreak();
-#endif
+ depth--;
return new EndTag();
}
wstring name = dis->readUTF();//new String(bytes, "UTF-8");
Tag *tag = newTag(type, name);
+ if (tag == nullptr) {
+ depth--;
+ return new EndTag();
+ }
// short length = dis.readShort();
// byte[] bytes = new byte[length];
// dis.readFully(bytes);
tag->load(dis, tagDepth);
+ depth--;
return tag;
}
diff --git a/Minecraft.World/TextureAndGeometryPacket.cpp b/Minecraft.World/TextureAndGeometryPacket.cpp
index bf5eccdb..1c920ee7 100644
--- a/Minecraft.World/TextureAndGeometryPacket.cpp
+++ b/Minecraft.World/TextureAndGeometryPacket.cpp
@@ -121,7 +121,20 @@ void TextureAndGeometryPacket::read(DataInputStream *dis) //throws IOException
{
textureName = dis->readUTF();
dwSkinID = static_cast<DWORD>(dis->readInt());
- dwTextureBytes = static_cast<DWORD>(dis->readShort());
+
+ short rawTextureBytes = dis->readShort();
+ if (rawTextureBytes <= 0)
+ {
+ dwTextureBytes = 0;
+ }
+ else
+ {
+ dwTextureBytes = (DWORD)(unsigned short)rawTextureBytes;
+ if (dwTextureBytes > 65536)
+ {
+ dwTextureBytes = 0;
+ }
+ }
if(dwTextureBytes>0)
{
@@ -134,7 +147,19 @@ void TextureAndGeometryPacket::read(DataInputStream *dis) //throws IOException
}
uiAnimOverrideBitmask = dis->readInt();
- dwBoxC = static_cast<DWORD>(dis->readShort());
+ short rawBoxC = dis->readShort();
+ if (rawBoxC <= 0)
+ {
+ dwBoxC = 0;
+ }
+ else
+ {
+ dwBoxC = (DWORD)(unsigned short)rawBoxC;
+ if (dwBoxC > 256)
+ {
+ dwBoxC = 0; // sane limit for skin boxes
+ }
+ }
if(dwBoxC>0)
{
diff --git a/Minecraft.World/TexturePacket.cpp b/Minecraft.World/TexturePacket.cpp
index eadcb3ed..94c195a0 100644
--- a/Minecraft.World/TexturePacket.cpp
+++ b/Minecraft.World/TexturePacket.cpp
@@ -37,17 +37,26 @@ void TexturePacket::handle(PacketListener *listener)
void TexturePacket::read(DataInputStream *dis) //throws IOException
{
textureName = dis->readUTF();
- dwBytes = static_cast<DWORD>(dis->readShort());
+ short rawBytes = dis->readShort();
+ if (rawBytes <= 0)
+ {
+ dwBytes = 0;
+ return;
+ }
+ dwBytes = (DWORD)(unsigned short)rawBytes;
+ if (dwBytes > 65536)
+ {
+ dwBytes = 0;
+ return;
+ }
+
+ this->pbData= new BYTE [dwBytes];
- if(dwBytes>0)
+ for(DWORD i=0;i<dwBytes;i++)
{
- this->pbData= new BYTE [dwBytes];
-
- for(DWORD i=0;i<dwBytes;i++)
- {
- this->pbData[i] = dis->readByte();
- }
+ this->pbData[i] = dis->readByte();
}
+
}
void TexturePacket::write(DataOutputStream *dos) //throws IOException
diff --git a/Minecraft.World/ThreadName.cpp b/Minecraft.World/ThreadName.cpp
index f41beb61..1f63aaf0 100644
--- a/Minecraft.World/ThreadName.cpp
+++ b/Minecraft.World/ThreadName.cpp
@@ -22,9 +22,9 @@ void SetThreadName( DWORD dwThreadID, LPCSTR szThreadName )
#if ( defined _WINDOWS64 | defined _DURANGO )
__try
{
- RaiseException( 0x406D1388, 0, sizeof(info)/sizeof(DWORD), (ULONG_PTR *)&info );
- }
- __except( GetExceptionCode()==0x406D1388 ? EXCEPTION_CONTINUE_EXECUTION : EXCEPTION_EXECUTE_HANDLER )
+ RaiseException(0x406D1388, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR *)&info);
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
{
}
#endif
diff --git a/Minecraft.World/UpdateGameRuleProgressPacket.cpp b/Minecraft.World/UpdateGameRuleProgressPacket.cpp
index d8856011..5bb1b301 100644
--- a/Minecraft.World/UpdateGameRuleProgressPacket.cpp
+++ b/Minecraft.World/UpdateGameRuleProgressPacket.cpp
@@ -18,7 +18,7 @@ UpdateGameRuleProgressPacket::UpdateGameRuleProgressPacket(ConsoleGameRules::EGa
m_auxValue = auxValue;
m_dataTag = dataTag;
- if(dataLength > 0)
+ if (dataLength > 0 && dataLength <= 65536)
{
m_data = byteArray(dataLength);
memcpy(m_data.data,data,dataLength);
diff --git a/Minecraft.World/compression.cpp b/Minecraft.World/compression.cpp
index 8c2e51c0..4122922b 100644
--- a/Minecraft.World/compression.cpp
+++ b/Minecraft.World/compression.cpp
@@ -237,9 +237,19 @@ HRESULT Compression::DecompressLZXRLE(void *pDestination, unsigned int *pDestSiz
unsigned char *dynamicRleBuf = nullptr;
HRESULT decompressResult;
- if(*pDestSize > rleSize)
+ unsigned int safeRleSize = max(rleSize, *pDestSize);
+
+ const unsigned int MAX_RLE_ALLOC = 16 * 1024 * 1024; // 16 MB
+ if (safeRleSize > MAX_RLE_ALLOC)
+ {
+ LeaveCriticalSection(&rleDecompressLock);
+ *pDestSize = 0;
+ return E_FAIL;
+ }
+
+ if (safeRleSize > staticRleSize)
{
- rleSize = *pDestSize;
+ rleSize = safeRleSize;
dynamicRleBuf = new unsigned char[rleSize];
decompressResult = Decompress(dynamicRleBuf, &rleSize, pSource, SrcSize);
pucIn = (unsigned char *)dynamicRleBuf;
@@ -263,7 +273,7 @@ HRESULT Compression::DecompressLZXRLE(void *pDestination, unsigned int *pDestSiz
//unsigned char *pucIn = (unsigned char *)rleDecompressBuf;
const unsigned char *pucEnd = pucIn + rleSize;
unsigned char *pucOut = static_cast<unsigned char*>(pDestination);
- const unsigned char *pucOutEnd = pucOut + *pDestSize;
+ unsigned char *pucOutEnd = pucOut + *pDestSize;
while( pucIn != pucEnd )
{
@@ -275,7 +285,11 @@ HRESULT Compression::DecompressLZXRLE(void *pDestination, unsigned int *pDestSiz
if( count < 3 )
{
count++;
- if( pucOut + count > pucOutEnd ) break;
+ if (pucOut + count > pucOutEnd)
+ {
+ pucOut = pucOutEnd;
+ break;
+ }
for( unsigned int i = 0; i < count; i++ )
{
*pucOut++ = 255;
@@ -286,7 +300,11 @@ HRESULT Compression::DecompressLZXRLE(void *pDestination, unsigned int *pDestSiz
count++;
if( pucIn >= pucEnd ) break;
const unsigned char data = *pucIn++;
- if( pucOut + count > pucOutEnd ) break;
+ if (pucOut + count > pucOutEnd)
+ {
+ pucOut = pucOutEnd;
+ break;
+ }
for( unsigned int i = 0; i < count; i++ )
{
*pucOut++ = data;
@@ -317,7 +335,7 @@ HRESULT Compression::DecompressRLE(void *pDestination, unsigned int *pDestSize,
unsigned char *pucIn = static_cast<unsigned char *>(pSource);
const unsigned char *pucEnd = pucIn + SrcSize;
unsigned char *pucOut = static_cast<unsigned char*>(pDestination);
- const unsigned char *pucOutEnd = pucOut + *pDestSize;
+ unsigned char *pucOutEnd = pucOut + *pDestSize;
while( pucIn != pucEnd )
{
@@ -329,7 +347,11 @@ HRESULT Compression::DecompressRLE(void *pDestination, unsigned int *pDestSize,
if( count < 3 )
{
count++;
- if( pucOut + count > pucOutEnd ) break;
+ if (pucOut + count > pucOutEnd)
+ {
+ pucOut = pucOutEnd;
+ break;
+ }
for( unsigned int i = 0; i < count; i++ )
{
*pucOut++ = 255;
@@ -340,7 +362,11 @@ HRESULT Compression::DecompressRLE(void *pDestination, unsigned int *pDestSize,
count++;
if( pucIn >= pucEnd ) break;
const unsigned char data = *pucIn++;
- if( pucOut + count > pucOutEnd ) break;
+ if (pucOut + count > pucOutEnd)
+ {
+ pucOut = pucOutEnd;
+ break;
+ }
for( unsigned int i = 0; i < count; i++ )
{
*pucOut++ = data;