From d557ca2dfba5ffcca99ceb41b07d149f871964b5 Mon Sep 17 00:00:00 2001 From: Loki Rautio Date: Mon, 9 Mar 2026 04:45:14 -0500 Subject: LCEMP RCE fixes Based on commit d017bfc30a68888bf5c79b23cf5c4f607cf828bf --- Minecraft.World/ThreadName.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'Minecraft.World/ThreadName.cpp') 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 -- cgit v1.2.3 From a358a3caaee2a4781f910cfb440bd822ae73a7e5 Mon Sep 17 00:00:00 2001 From: Loki Rautio Date: Mon, 9 Mar 2026 04:46:56 -0500 Subject: Revert accidentally pushed "LCEMP RCE fixes" This reverts commit d557ca2dfba5ffcca99ceb41b07d149f871964b5. --- Minecraft.World/AwardStatPacket.cpp | 2 +- Minecraft.World/BlockRegionUpdatePacket.cpp | 6 --- Minecraft.World/ByteArrayInputStream.cpp | 13 +----- Minecraft.World/ByteArrayOutputStream.cpp | 18 +-------- Minecraft.World/ByteArrayTag.h | 1 - Minecraft.World/ComplexItemDataPacket.cpp | 7 +--- Minecraft.World/CompoundTag.h | 14 ++----- Minecraft.World/Connection.cpp | 4 +- Minecraft.World/ContainerSetContentPacket.cpp | 3 -- Minecraft.World/ContainerSetSlotPacket.cpp | 2 +- Minecraft.World/CustomPayloadPacket.cpp | 2 +- Minecraft.World/DataInputStream.cpp | 4 -- Minecraft.World/ExplodePacket.cpp | 2 - Minecraft.World/GameCommandPacket.cpp | 2 +- Minecraft.World/IntArrayTag.h | 2 - Minecraft.World/ListTag.h | 11 ++++-- Minecraft.World/Packet.cpp | 50 ++++++++++++++---------- Minecraft.World/PreLoginPacket.cpp | 1 - Minecraft.World/RemoveEntitiesPacket.cpp | 4 +- Minecraft.World/Socket.cpp | 5 --- Minecraft.World/SynchedEntityData.cpp | 6 +-- Minecraft.World/Tag.cpp | 39 +++--------------- Minecraft.World/TextureAndGeometryPacket.cpp | 29 +------------- Minecraft.World/TexturePacket.cpp | 25 ++++-------- Minecraft.World/ThreadName.cpp | 6 +-- Minecraft.World/UpdateGameRuleProgressPacket.cpp | 2 +- Minecraft.World/compression.cpp | 42 ++++---------------- 27 files changed, 80 insertions(+), 222 deletions(-) (limited to 'Minecraft.World/ThreadName.cpp') diff --git a/Minecraft.World/AwardStatPacket.cpp b/Minecraft.World/AwardStatPacket.cpp index b2950a0e..07888541 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 && length <= 65536) + if(length > 0) { m_paramData = byteArray(length); dis->readFully(m_paramData); diff --git a/Minecraft.World/BlockRegionUpdatePacket.cpp b/Minecraft.World/BlockRegionUpdatePacket.cpp index b91cf4f8..730ce3ed 100644 --- a/Minecraft.World/BlockRegionUpdatePacket.cpp +++ b/Minecraft.World/BlockRegionUpdatePacket.cpp @@ -105,12 +105,6 @@ 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 9509206d..d79eff36 100644 --- a/Minecraft.World/ByteArrayInputStream.cpp +++ b/Minecraft.World/ByteArrayInputStream.cpp @@ -10,19 +10,8 @@ //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), mark(offset) + : pos( offset ), count( min( offset+length, buf.length ) ), 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 a6fdad8f..a9f36e04 100644 --- a/Minecraft.World/ByteArrayOutputStream.cpp +++ b/Minecraft.World/ByteArrayOutputStream.cpp @@ -53,25 +53,9 @@ 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 ) - { - unsigned int newSize = (std::max)(count + length + 1, buf.length * 2); - if (newSize <= buf.length) - { - return; - } - buf.resize(newSize); - } + buf.resize( max( count + length + 1, buf.length * 2 ) ); 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 4d53c63e..1d3e3875 100644 --- a/Minecraft.World/ByteArrayTag.h +++ b/Minecraft.World/ByteArrayTag.h @@ -21,7 +21,6 @@ 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 98eeb9de..38c39cb6 100644 --- a/Minecraft.World/ComplexItemDataPacket.cpp +++ b/Minecraft.World/ComplexItemDataPacket.cpp @@ -32,12 +32,7 @@ void ComplexItemDataPacket::read(DataInputStream *dis) //throws IOException itemType = dis->readShort(); itemId = dis->readShort(); - int dataLength = dis->readShort() & 0xffff; - if (dataLength > 32767) - { - dataLength = 0; - } - data = charArray(dataLength); + data = charArray(dis->readUnsignedShort() & 0xffff); dis->readFully(data); } diff --git a/Minecraft.World/CompoundTag.h b/Minecraft.World/CompoundTag.h index 8f4d045d..5eaa2a05 100644 --- a/Minecraft.World/CompoundTag.h +++ b/Minecraft.World/CompoundTag.h @@ -42,16 +42,10 @@ public: } tags.clear(); Tag *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; - } - } + while ((tag = Tag::readNamedTag(dis))->getId() != Tag::TAG_End) + { + tags[tag->getName()] = tag; + } delete tag; } diff --git a/Minecraft.World/Connection.cpp b/Minecraft.World/Connection.cpp index d4450266..7f10dc4a 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_s(readThreadName, sizeof(readThreadName), "%.240s read\n", szId); - sprintf_s(writeThreadName, sizeof(writeThreadName), "%.240s write\n", szId); + sprintf(readThreadName,"%s read\n",szId); + sprintf(writeThreadName,"%s write\n",szId); readThread = new C4JThread(runRead, static_cast(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 28ce64e9..ae76e0f0 100644 --- a/Minecraft.World/ContainerSetContentPacket.cpp +++ b/Minecraft.World/ContainerSetContentPacket.cpp @@ -32,9 +32,6 @@ 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 de8d2680..6a038244 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)(signed char)byteId; + containerId = *(char *)&byteId; slot = dis->readShort(); item = readItem(dis); } diff --git a/Minecraft.World/CustomPayloadPacket.cpp b/Minecraft.World/CustomPayloadPacket.cpp index e86f01de..46fde5aa 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 0cd21a7e..4e4f5cd1 100644 --- a/Minecraft.World/DataInputStream.cpp +++ b/Minecraft.World/DataInputStream.cpp @@ -303,10 +303,6 @@ wstring DataInputStream::readUTF() int b = stream->read(); unsigned short UTFLength = static_cast(((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 88bf00c6..07626161 100644 --- a/Minecraft.World/ExplodePacket.cpp +++ b/Minecraft.World/ExplodePacket.cpp @@ -52,8 +52,6 @@ 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(x); int yp = static_cast(y); int zp = static_cast(z); diff --git a/Minecraft.World/GameCommandPacket.cpp b/Minecraft.World/GameCommandPacket.cpp index ada5b04c..17c5316a 100644 --- a/Minecraft.World/GameCommandPacket.cpp +++ b/Minecraft.World/GameCommandPacket.cpp @@ -40,7 +40,7 @@ void GameCommandPacket::read(DataInputStream *dis) command = static_cast(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 64a4d004..61ca59d0 100644 --- a/Minecraft.World/IntArrayTag.h +++ b/Minecraft.World/IntArrayTag.h @@ -35,8 +35,6 @@ 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 f6e1c6a0..2a0fdebc 100644 --- a/Minecraft.World/ListTag.h +++ b/Minecraft.World/ListTag.h @@ -26,16 +26,21 @@ 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 05bf932d..129024b7 100644 --- a/Minecraft.World/Packet.cpp +++ b/Minecraft.World/Packet.cpp @@ -267,12 +267,8 @@ void Packet::updatePacketStatsPIX() shared_ptr Packet::getPacket(int id) { - auto it = idToCreateMap.find(id); - if (it == idToCreateMap.end()) - { - return nullptr; - } - return it->second(); + // 4J: Removed try/catch + return idToCreateMap[id](); } void Packet::writeBytes(DataOutputStream *dataoutputstream, byteArray bytes) @@ -338,11 +334,30 @@ shared_ptr Packet::readPacket(DataInputStream *dis, bool isServer) // th if ((isServer && serverReceivedPackets.find(id) == serverReceivedPackets.end()) || (!isServer && clientReceivedPackets.find(id) == clientReceivedPackets.end())) { - return nullptr; + 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)); } packet = getPacket(id); - if (packet == nullptr) return nullptr;//throw new IOException(wstring(L"Bad packet id ") + std::to_wstring(id)); + if (packet == nullptr) assert(false);//throw new IOException(wstring(L"Bad packet id ") + std::to_wstring(id)); s_lastIds[s_lastIdPos] = id; s_lastIdPos = (s_lastIdPos + 1) % 8; @@ -403,9 +418,11 @@ wstring Packet::readUtf(DataInputStream *dis, int maxLength) // throws IOExcepti { short stringLength = dis->readShort(); - if (stringLength > maxLength || stringLength <= 0) + if (stringLength > maxLength) { - return L""; + wstringstream stream; + stream << L"Received string length longer than maximum allowed (" << stringLength << " > " << maxLength << ")"; + assert(false); // throw new IOException( stream.str() ); } if (stringLength < 0) @@ -514,7 +531,7 @@ shared_ptr Packet::readItem(DataInputStream *dis) { shared_ptr item = nullptr; int id = dis->readShort(); - if (id >= 0 && id < 32000) // todo: should turn Item::ITEM_NUM_COUNT into a global define + if (id >= 0) { int count = dis->readByte(); int damage = dis->readShort(); @@ -552,16 +569,9 @@ void Packet::writeItem(shared_ptr item, DataOutputStream *dos) CompoundTag *Packet::readNbt(DataInputStream *dis) { int size = dis->readShort(); - if (size <= 0) return nullptr; - - const int MAX_NBT_SIZE = 32767; - if (size > MAX_NBT_SIZE) return nullptr; + if (size < 0) return nullptr; byteArray buff(size); - if (!dis->readFully(buff)) - { - delete [] buff.data; - return nullptr; - } + dis->readFully(buff); CompoundTag *result = (CompoundTag *) NbtIo::decompress(buff); delete [] buff.data; return result; diff --git a/Minecraft.World/PreLoginPacket.cpp b/Minecraft.World/PreLoginPacket.cpp index a88b9641..aa6832ca 100644 --- a/Minecraft.World/PreLoginPacket.cpp +++ b/Minecraft.World/PreLoginPacket.cpp @@ -62,7 +62,6 @@ 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 4c5e3313..609cfa77 100644 --- a/Minecraft.World/RemoveEntitiesPacket.cpp +++ b/Minecraft.World/RemoveEntitiesPacket.cpp @@ -21,9 +21,7 @@ RemoveEntitiesPacket::~RemoveEntitiesPacket() void RemoveEntitiesPacket::read(DataInputStream *dis) //throws IOException { - int count = dis->readByte(); - if(count < 0) count = 0; - ids = intArray(count); + ids = intArray(dis->readByte()); 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 41ac3702..2d5b257d 100644 --- a/Minecraft.World/Socket.cpp +++ b/Minecraft.World/Socket.cpp @@ -141,11 +141,6 @@ 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 67b9597b..69d419b0 100644 --- a/Minecraft.World/SynchedEntityData.cpp +++ b/Minecraft.World/SynchedEntityData.cpp @@ -342,10 +342,7 @@ vector > *SynchedEntityData::unpack(Data int currentHeader = input->readByte(); - int itemCount = 0; - const int MAX_ENTITY_DATA_ITEMS = 256; - - while (currentHeader != EOF_MARKER && itemCount < MAX_ENTITY_DATA_ITEMS) + while (currentHeader != EOF_MARKER) { if (result == nullptr) @@ -400,7 +397,6 @@ vector > *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 eafdc9e8..b594bb0e 100644 --- a/Minecraft.World/Tag.cpp +++ b/Minecraft.World/Tag.cpp @@ -84,56 +84,27 @@ 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) { - depth--; - return new EndTag(); - } + if (type == 0) return new EndTag(); // 4J Stu - readByte can return -1, so if it's that then also mark as the end tag if(type == 255) { - depth--; + app.DebugPrintf("readNamedTag read a type of 255\n"); +#ifndef _CONTENT_PACKAGE + __debugbreak(); +#endif 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 1c920ee7..bf5eccdb 100644 --- a/Minecraft.World/TextureAndGeometryPacket.cpp +++ b/Minecraft.World/TextureAndGeometryPacket.cpp @@ -121,20 +121,7 @@ void TextureAndGeometryPacket::read(DataInputStream *dis) //throws IOException { textureName = dis->readUTF(); dwSkinID = static_cast(dis->readInt()); - - short rawTextureBytes = dis->readShort(); - if (rawTextureBytes <= 0) - { - dwTextureBytes = 0; - } - else - { - dwTextureBytes = (DWORD)(unsigned short)rawTextureBytes; - if (dwTextureBytes > 65536) - { - dwTextureBytes = 0; - } - } + dwTextureBytes = static_cast(dis->readShort()); if(dwTextureBytes>0) { @@ -147,19 +134,7 @@ void TextureAndGeometryPacket::read(DataInputStream *dis) //throws IOException } uiAnimOverrideBitmask = dis->readInt(); - 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 - } - } + dwBoxC = static_cast(dis->readShort()); if(dwBoxC>0) { diff --git a/Minecraft.World/TexturePacket.cpp b/Minecraft.World/TexturePacket.cpp index 94c195a0..eadcb3ed 100644 --- a/Minecraft.World/TexturePacket.cpp +++ b/Minecraft.World/TexturePacket.cpp @@ -37,26 +37,17 @@ void TexturePacket::handle(PacketListener *listener) void TexturePacket::read(DataInputStream *dis) //throws IOException { textureName = dis->readUTF(); - 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]; + dwBytes = static_cast(dis->readShort()); - for(DWORD i=0;i0) { - this->pbData[i] = dis->readByte(); + this->pbData= new BYTE [dwBytes]; + + for(DWORD i=0;ipbData[i] = dis->readByte(); + } } - } void TexturePacket::write(DataOutputStream *dos) //throws IOException diff --git a/Minecraft.World/ThreadName.cpp b/Minecraft.World/ThreadName.cpp index 1f63aaf0..f41beb61 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(ULONG_PTR), (ULONG_PTR *)&info); - } - __except (EXCEPTION_EXECUTE_HANDLER) + RaiseException( 0x406D1388, 0, sizeof(info)/sizeof(DWORD), (ULONG_PTR *)&info ); + } + __except( GetExceptionCode()==0x406D1388 ? EXCEPTION_CONTINUE_EXECUTION : EXCEPTION_EXECUTE_HANDLER ) { } #endif diff --git a/Minecraft.World/UpdateGameRuleProgressPacket.cpp b/Minecraft.World/UpdateGameRuleProgressPacket.cpp index 5bb1b301..d8856011 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 && dataLength <= 65536) + if(dataLength > 0) { m_data = byteArray(dataLength); memcpy(m_data.data,data,dataLength); diff --git a/Minecraft.World/compression.cpp b/Minecraft.World/compression.cpp index 4122922b..8c2e51c0 100644 --- a/Minecraft.World/compression.cpp +++ b/Minecraft.World/compression.cpp @@ -237,19 +237,9 @@ HRESULT Compression::DecompressLZXRLE(void *pDestination, unsigned int *pDestSiz unsigned char *dynamicRleBuf = nullptr; HRESULT decompressResult; - 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) + if(*pDestSize > rleSize) { - rleSize = safeRleSize; + rleSize = *pDestSize; dynamicRleBuf = new unsigned char[rleSize]; decompressResult = Decompress(dynamicRleBuf, &rleSize, pSource, SrcSize); pucIn = (unsigned char *)dynamicRleBuf; @@ -273,7 +263,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(pDestination); - unsigned char *pucOutEnd = pucOut + *pDestSize; + const unsigned char *pucOutEnd = pucOut + *pDestSize; while( pucIn != pucEnd ) { @@ -285,11 +275,7 @@ HRESULT Compression::DecompressLZXRLE(void *pDestination, unsigned int *pDestSiz if( count < 3 ) { count++; - if (pucOut + count > pucOutEnd) - { - pucOut = pucOutEnd; - break; - } + if( pucOut + count > pucOutEnd ) break; for( unsigned int i = 0; i < count; i++ ) { *pucOut++ = 255; @@ -300,11 +286,7 @@ HRESULT Compression::DecompressLZXRLE(void *pDestination, unsigned int *pDestSiz count++; if( pucIn >= pucEnd ) break; const unsigned char data = *pucIn++; - if (pucOut + count > pucOutEnd) - { - pucOut = pucOutEnd; - break; - } + if( pucOut + count > pucOutEnd ) break; for( unsigned int i = 0; i < count; i++ ) { *pucOut++ = data; @@ -335,7 +317,7 @@ HRESULT Compression::DecompressRLE(void *pDestination, unsigned int *pDestSize, unsigned char *pucIn = static_cast(pSource); const unsigned char *pucEnd = pucIn + SrcSize; unsigned char *pucOut = static_cast(pDestination); - unsigned char *pucOutEnd = pucOut + *pDestSize; + const unsigned char *pucOutEnd = pucOut + *pDestSize; while( pucIn != pucEnd ) { @@ -347,11 +329,7 @@ HRESULT Compression::DecompressRLE(void *pDestination, unsigned int *pDestSize, if( count < 3 ) { count++; - if (pucOut + count > pucOutEnd) - { - pucOut = pucOutEnd; - break; - } + if( pucOut + count > pucOutEnd ) break; for( unsigned int i = 0; i < count; i++ ) { *pucOut++ = 255; @@ -362,11 +340,7 @@ HRESULT Compression::DecompressRLE(void *pDestination, unsigned int *pDestSize, count++; if( pucIn >= pucEnd ) break; const unsigned char data = *pucIn++; - if (pucOut + count > pucOutEnd) - { - pucOut = pucOutEnd; - break; - } + if( pucOut + count > pucOutEnd ) break; for( unsigned int i = 0; i < count; i++ ) { *pucOut++ = data; -- cgit v1.2.3 From bda3b1078ac357b805156a8802a0649f7021716e Mon Sep 17 00:00:00 2001 From: Loki Date: Mon, 9 Mar 2026 06:53:08 -0500 Subject: Port over RCE Patches from LCEMP (#1023) * LCEMP RCE Fixes WIP Based on https://github.com/LCEMP/LCEMP/commit/d017bfc30a68888bf5c79b23cf5c4f607cf828bf * Update to LCEMP's ByteArrayIO version Fixes compilation since ours was missing some revisions from LCEMP * Add additional safety checks missed in first pass * Remove duplicate recipe count check --- Minecraft.Client/Chunk.cpp | 5 +- Minecraft.Client/PlayerConnection.cpp | 8 +- Minecraft.Client/ServerLevel.cpp | 7 +- .../Windows64/Network/WinsockNetLayer.cpp | 2 +- Minecraft.World/AbstractContainerMenu.cpp | 6 +- Minecraft.World/AwardStatPacket.cpp | 2 +- Minecraft.World/BlockRegionUpdatePacket.cpp | 6 + Minecraft.World/ByteArrayInputStream.cpp | 176 ++++++++++++--------- Minecraft.World/ByteArrayOutputStream.cpp | 99 +++++++----- Minecraft.World/ByteArrayTag.h | 1 + Minecraft.World/ComplexItemDataPacket.cpp | 7 +- Minecraft.World/CompoundTag.h | 14 +- Minecraft.World/Connection.cpp | 4 +- Minecraft.World/ContainerSetContentPacket.cpp | 3 + Minecraft.World/ContainerSetSlotPacket.cpp | 2 +- Minecraft.World/CustomPayloadPacket.cpp | 2 +- Minecraft.World/DataInputStream.cpp | 4 + Minecraft.World/ExplodePacket.cpp | 2 + Minecraft.World/GameCommandPacket.cpp | 2 +- Minecraft.World/IntArrayTag.h | 2 + Minecraft.World/ListTag.h | 11 +- Minecraft.World/Packet.cpp | 50 +++--- Minecraft.World/PreLoginPacket.cpp | 2 + Minecraft.World/RemoveEntitiesPacket.cpp | 4 +- Minecraft.World/Socket.cpp | 5 + Minecraft.World/SynchedEntityData.cpp | 6 +- Minecraft.World/Tag.cpp | 39 ++++- Minecraft.World/TextureAndGeometryPacket.cpp | 29 +++- Minecraft.World/TexturePacket.cpp | 25 ++- Minecraft.World/ThreadName.cpp | 6 +- Minecraft.World/UpdateGameRuleProgressPacket.cpp | 2 +- Minecraft.World/compression.cpp | 42 ++++- 32 files changed, 372 insertions(+), 203 deletions(-) (limited to 'Minecraft.World/ThreadName.cpp') diff --git a/Minecraft.Client/Chunk.cpp b/Minecraft.Client/Chunk.cpp index 6f0ad736..0a63b874 100644 --- a/Minecraft.Client/Chunk.cpp +++ b/Minecraft.Client/Chunk.cpp @@ -739,9 +739,9 @@ void Chunk::rebuild_SPU() { // 4J - get tile from those copied into our local array in earlier optimisation unsigned char tileId = pOutData->getTile(x,y,z); - if (tileId > 0) + if (tileId > 0 && tileId != 0xff) { - if (currentLayer == 0 && Tile::tiles[tileId]->isEntityTile()) + if (currentLayer == 0 && Tile::tiles[tileId] && Tile::tiles[tileId]->isEntityTile()) { shared_ptr et = region.getTileEntity(x, y, z); if (TileEntityRenderDispatcher::instance->hasRenderer(et)) @@ -754,6 +754,7 @@ void Chunk::rebuild_SPU() { Tile *tile = Tile::tiles[tileId]; + if (!tile) continue; int renderLayer = tile->getRenderLayer(); if (renderLayer != currentLayer) diff --git a/Minecraft.Client/PlayerConnection.cpp b/Minecraft.Client/PlayerConnection.cpp index 8e056cd8..d9915cf6 100644 --- a/Minecraft.Client/PlayerConnection.cpp +++ b/Minecraft.Client/PlayerConnection.cpp @@ -1588,13 +1588,13 @@ void PlayerConnection::handleCraftItem(shared_ptr packet) if(iRecipe == -1) return; + int recipeCount = (int)Recipes::getInstance()->getRecipies()->size(); + if(iRecipe < 0 || iRecipe >= recipeCount) + return; + Recipy::INGREDIENTS_REQUIRED *pRecipeIngredientsRequired=Recipes::getInstance()->getRecipeIngredientsArray(); shared_ptr pTempItemInst=pRecipeIngredientsRequired[iRecipe].pRecipy->assemble(nullptr); - size_t recipeCount = Recipes::getInstance()->getRecipies()->size(); - if (iRecipe < 0 || iRecipe >= (int)recipeCount) - return; - if(app.DebugSettingsOn() && (player->GetDebugOptions()&(1L<onCraftedBy(player->level, dynamic_pointer_cast( player->shared_from_this() ), pTempItemInst->count ); diff --git a/Minecraft.Client/ServerLevel.cpp b/Minecraft.Client/ServerLevel.cpp index d322d9b6..a2596911 100644 --- a/Minecraft.Client/ServerLevel.cpp +++ b/Minecraft.Client/ServerLevel.cpp @@ -1077,7 +1077,12 @@ void ServerLevel::entityRemoved(shared_ptr e) shared_ptr ServerLevel::getEntity(int id) { - return entitiesById[id]; + auto it = entitiesById.find(id); + if (it != entitiesById.end()) + { + return it->second; + } + return nullptr; } bool ServerLevel::addGlobalEntity(shared_ptr e) diff --git a/Minecraft.Client/Windows64/Network/WinsockNetLayer.cpp b/Minecraft.Client/Windows64/Network/WinsockNetLayer.cpp index e82118cd..28d29504 100644 --- a/Minecraft.Client/Windows64/Network/WinsockNetLayer.cpp +++ b/Minecraft.Client/Windows64/Network/WinsockNetLayer.cpp @@ -404,7 +404,7 @@ bool WinsockNetLayer::JoinGame(const char* ip, int port) bool WinsockNetLayer::SendOnSocket(SOCKET sock, const void* data, int dataSize) { - if (sock == INVALID_SOCKET || dataSize <= 0) return false; + if (sock == INVALID_SOCKET || dataSize <= 0 || dataSize > WIN64_NET_MAX_PACKET_SIZE) return false; // TODO: s_sendLock is a single global lock for ALL sockets. If one client's // send() blocks (TCP window full, slow WiFi), every other write thread stalls diff --git a/Minecraft.World/AbstractContainerMenu.cpp b/Minecraft.World/AbstractContainerMenu.cpp index 10d8afdc..c98fc22c 100644 --- a/Minecraft.World/AbstractContainerMenu.cpp +++ b/Minecraft.World/AbstractContainerMenu.cpp @@ -157,6 +157,9 @@ shared_ptr AbstractContainerMenu::clicked(int slotIndex, int butto shared_ptr clickedEntity = nullptr; shared_ptr inventory = player->inventory; + if (slotIndex < 0 || slotIndex >= (int)slots.size()) + return nullptr; + if (clickType == CLICK_QUICK_CRAFT) { int expectedStatus = quickcraftStatus; @@ -558,12 +561,13 @@ bool AbstractContainerMenu::isPauseScreen() void AbstractContainerMenu::setItem(unsigned int slot, shared_ptr item) { + if (slot >= slots.size()) return; getSlot(slot)->set(item); } void AbstractContainerMenu::setAll(ItemInstanceArray *items) { - for (unsigned int i = 0; i < items->length; i++) + for (unsigned int i = 0; i < items->length && i < slots.size(); i++) { getSlot(i)->set( (*items)[i] ); } 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..29f6fc26 100644 --- a/Minecraft.World/ByteArrayInputStream.cpp +++ b/Minecraft.World/ByteArrayInputStream.cpp @@ -2,117 +2,141 @@ #include "InputOutputStream.h" -//Creates ByteArrayInputStream that uses buf as its buffer array. The initial value of pos is offset and -//the initial value of count is the minimum of offset+length and buf.length. The buffer array is not copied. -//The buffer's mark is set to the specified offset. -//Parameters: -//buf - the input buffer. -//offset - the offset in the buffer of the first byte to read. -//length - the maximum number of bytes to read from the buffer. +// Creates ByteArrayInputStream that uses buf as its buffer array. The initial value of pos is offset and +// the initial value of count is the minimum of offset+length and buf.length. The buffer array is not copied. +// The buffer's mark is set to the specified offset. +// Parameters: +// buf - the input buffer. +// 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) { - this->buf = buf; + if (offset > buf.length) + { + count = buf.length; + } + else if (length > buf.length - offset) + { + count = buf.length; + } + else + { + count = offset + length; + } + this->buf = buf; } -//Creates a ByteArrayInputStream so that it uses buf as its buffer array. The buffer array is not copied. -//The initial value of pos is 0 and the initial value of count is the length of buf. -//Parameters: -//buf - the input buffer. +// Creates a ByteArrayInputStream so that it uses buf as its buffer array. The buffer array is not copied. +// The initial value of pos is 0 and the initial value of count is the length of buf. +// Parameters: +// buf - the input buffer. ByteArrayInputStream::ByteArrayInputStream(byteArray buf) - : pos( 0 ), count( buf.length ), mark( 0 ) + : pos(0), count(buf.length), mark(0) { - this->buf = buf; + this->buf = buf; } -//Reads the next byte of data from this input stream. The value byte is returned as an int in the range 0 to 255. -//If no byte is available because the end of the stream has been reached, the value -1 is returned. -//This read method cannot block. -//Returns: -//the next byte of data, or -1 if the end of the stream has been reached. +// Reads the next byte of data from this input stream. The value byte is returned as an int in the range 0 to 255. +// If no byte is available because the end of the stream has been reached, the value -1 is returned. +// This read method cannot block. +// Returns: +// the next byte of data, or -1 if the end of the stream has been reached. int ByteArrayInputStream::read() { - if( pos >= count ) - return -1; - else - return buf[pos++]; + if (pos >= count) + { + return -1; + } + else + { + return buf[pos++]; + } } -//Reads some number of bytes from the input stream and stores them into the buffer array b. -//The number of bytes actually read is returned as an integer. This method blocks until input data is available, -//end of file is detected, or an exception is thrown. -//If the length of b is zero, then no bytes are read and 0 is returned; otherwise, there is an attempt to read at least one byte. -//If no byte is available because the stream is at the end of the file, the value -1 is returned; otherwise, -//at least one byte is read and stored into b. +// Reads some number of bytes from the input stream and stores them into the buffer array b. +// The number of bytes actually read is returned as an integer. This method blocks until input data is available, +// end of file is detected, or an exception is thrown. +// If the length of b is zero, then no bytes are read and 0 is returned; otherwise, there is an attempt to read at least one byte. +// If no byte is available because the stream is at the end of the file, the value -1 is returned; otherwise, +// at least one byte is read and stored into b. // -//The first byte read is stored into element b[0], the next one into b[1], and so on. The number of bytes read is, -//at most, equal to the length of b. Let k be the number of bytes actually read; these bytes will be stored in elements b[0] through b[k-1], -//leaving elements b[k] through b[b.length-1] unaffected. +// The first byte read is stored into element b[0], the next one into b[1], and so on. The number of bytes read is, +// at most, equal to the length of b. Let k be the number of bytes actually read; these bytes will be stored in elements b[0] through b[k-1], +// leaving elements b[k] through b[b.length-1] unaffected. // -//The read(b) method for class InputStream has the same effect as: +// The read(b) method for class InputStream has the same effect as: // -// read(b, 0, b.length) -//Parameters: -//b - the buffer into which the data is read. -//Returns: -//the total number of bytes read into the buffer, or -1 is there is no more data because the end of the stream has been reached. +// read(b, 0, b.length) +// Parameters: +// b - the buffer into which the data is read. +// Returns: +// the total number of bytes read into the buffer, or -1 is there is no more data because the end of the stream has been reached. int ByteArrayInputStream::read(byteArray b) { - return read( b, 0, b.length ); + return read(b, 0, b.length); } -//Reads up to len bytes of data into an array of bytes from this input stream. If pos equals count, -//then -1 is returned to indicate end of file. Otherwise, the number k of bytes read is equal to the smaller of len and count-pos. -//If k is positive, then bytes buf[pos] through buf[pos+k-1] are copied into b[off] through b[off+k-1] in the manner -//performed by System.arraycopy. The value k is added into pos and k is returned. -//This read method cannot block. -//Parameters: -//b - the buffer into which the data is read. -//off - the start offset in the destination array b -//len - the maximum number of bytes read. -//Returns: -//the total number of bytes read into the buffer, or -1 if there is no more data because the end of the stream has been reached. +// Reads up to len bytes of data into an array of bytes from this input stream. If pos equals count, +// then -1 is returned to indicate end of file. Otherwise, the number k of bytes read is equal to the smaller of len and count-pos. +// If k is positive, then bytes buf[pos] through buf[pos+k-1] are copied into b[off] through b[off+k-1] in the manner +// performed by System.arraycopy. The value k is added into pos and k is returned. +// This read method cannot block. +// Parameters: +// b - the buffer into which the data is read. +// off - the start offset in the destination array b +// len - the maximum number of bytes read. +// Returns: +// the total number of bytes read into the buffer, or -1 if there is no more data because the end of the stream has been reached. int ByteArrayInputStream::read(byteArray b, unsigned int offset, unsigned int length) { - if( pos == count ) - return -1; + if (pos == count) + { + return -1; + } - int k = min( length, count-pos ); - XMemCpy( &b[offset], &buf[pos], k ); - //std::copy( buf->data+pos, buf->data+pos+k, b->data + offset ); // Or this instead? + int k = min(length, count - pos); + XMemCpy(&b[offset], &buf[pos], k); + // std::copy( buf->data+pos, buf->data+pos+k, b->data + offset ); // Or this instead? - pos += k; + pos += k; - return k; + return k; } -//Closing a ByteArrayInputStream has no effect. -//The methods in this class can be called after the stream has been closed without generating an IOException. +// Closing a ByteArrayInputStream has no effect. +// The methods in this class can be called after the stream has been closed without generating an IOException. void ByteArrayInputStream::close() { - return; + return; } -//Skips n bytes of input from this input stream. Fewer bytes might be skipped if the end of the input stream is reached. The actual number k of bytes to be skipped is equal to the smaller of n and count-pos. The value k is added into pos and k is returned. -//Overrides: -//skip in class InputStream -//Parameters: -//n - the number of bytes to be skipped. -//Returns: -//the actual number of bytes skipped. -int64_t ByteArrayInputStream::skip(int64_t n) +// Skips n bytes of input from this input stream. Fewer bytes might be skipped if the end of the input stream is reached. The actual number k of bytes to be skipped is equal to the smaller of n and count-pos. The value k is added into pos and k is returned. +// Overrides: +// skip in class InputStream +// Parameters: +// n - the number of bytes to be skipped. +// Returns: +// the actual number of bytes skipped. +__int64 ByteArrayInputStream::skip(__int64 n) { - int newPos = pos + n; + int newPos = pos + n; - if(newPos > count) newPos = count; + if (newPos > count) + { + newPos = count; + } - int k = newPos - pos; - pos = newPos; + int k = newPos - pos; + pos = newPos; - return k; + return k; } ByteArrayInputStream::~ByteArrayInputStream() { - if(buf.data != nullptr) delete [] buf.data; -} \ No newline at end of file + if (buf.data != NULL) + { + delete[] buf.data; + } +} diff --git a/Minecraft.World/ByteArrayOutputStream.cpp b/Minecraft.World/ByteArrayOutputStream.cpp index a9f36e04..9173941f 100644 --- a/Minecraft.World/ByteArrayOutputStream.cpp +++ b/Minecraft.World/ByteArrayOutputStream.cpp @@ -5,76 +5,95 @@ // Creates a new byte array output stream. The buffer capacity is initially 32 bytes, though its size increases if necessary. ByteArrayOutputStream::ByteArrayOutputStream() { - count = 0; - buf = byteArray( 32 ); + count = 0; + buf = byteArray(32); } -//Creates a new byte array output stream, with a buffer capacity of the specified size, in bytes. -//Parameters: -//size - the initial size. +// Creates a new byte array output stream, with a buffer capacity of the specified size, in bytes. +// Parameters: +// size - the initial size. ByteArrayOutputStream::ByteArrayOutputStream(unsigned int size) { - count = 0; - buf = byteArray( size ); + count = 0; + buf = byteArray(size); } ByteArrayOutputStream::~ByteArrayOutputStream() { - if (buf.data != nullptr) - delete[] buf.data; + if (buf.data != NULL) + { + delete[] buf.data; + } } -//Writes the specified byte to this byte array output stream. -//Parameters: -//b - the byte to be written. +// Writes the specified byte to this byte array output stream. +// Parameters: +// b - the byte to be written. void ByteArrayOutputStream::write(unsigned int b) { - // If we will fill the buffer we need to make it bigger - if( count + 1 >= buf.length ) - buf.resize( buf.length * 2 ); + // If we will fill the buffer we need to make it bigger + if (count + 1 >= buf.length) + { + buf.resize(buf.length * 2); + } - buf[count] = static_cast(b); - count++; + buf[count] = (byte)b; + count++; } // Writes b.length bytes from the specified byte array to this output stream. -//The general contract for write(b) is that it should have exactly the same effect as the call write(b, 0, b.length). +// The general contract for write(b) is that it should have exactly the same effect as the call write(b, 0, b.length). void ByteArrayOutputStream::write(byteArray b) { - write(b, 0, b.length); + write(b, 0, b.length); } -//Writes len bytes from the specified byte array starting at offset off to this byte array output stream. -//Parameters: -//b - the data. -//off - the start offset in the data. -//len - the number of bytes to write. +// Writes len bytes from the specified byte array starting at offset off to this byte array output stream. +// Parameters: +// b - the data. +// off - the start offset in the data. +// len - the number of bytes to write. void ByteArrayOutputStream::write(byteArray b, unsigned int offset, unsigned int length) { - assert( b.length >= offset + length ); - // 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 ) ); + if (offset > b.length || length > b.length - offset) + { + return; + } - XMemCpy( &buf[count], &b[offset], length ); - //std::copy( b->data+offset, b->data+offset+length, buf->data + count ); // Or this instead? + if (length > 0xFFFFFFFF - count) + { + return; + } - count += length; + // If we will fill the buffer we need to make it bigger + if (count + length >= buf.length) + { + 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); + + count += length; } -//Closing a ByteArrayOutputStream has no effect. -//The methods in this class can be called after the stream has been closed without generating an IOException. +// Closing a ByteArrayOutputStream has no effect. +// The methods in this class can be called after the stream has been closed without generating an IOException. void ByteArrayOutputStream::close() { } -//Creates a newly allocated byte array. Its size is the current size of this output stream and the valid contents of the buffer have been copied into it. -//Returns: -//the current contents of this output stream, as a byte array. +// Creates a newly allocated byte array. Its size is the current size of this output stream and the valid contents of the buffer have been copied into it. +// Returns: +// the current contents of this output stream, as a byte array. byteArray ByteArrayOutputStream::toByteArray() { - byteArray out(count); - memcpy(out.data,buf.data,count); - return out; -} \ No newline at end of file + byteArray out(count); + memcpy(out.data, buf.data, count); + return out; +} 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(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(((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(x); int yp = static_cast(y); int zp = static_cast(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(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::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::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 Packet::readItem(DataInputStream *dis) { shared_ptr 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 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..ddcfe197 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]; @@ -74,6 +75,7 @@ void PreLoginPacket::read(DataInputStream *dis) //throws IOException { m_szUniqueSaveName[i]=dis->readByte(); } + // m_szUniqueSaveName[m_iSaveNameLen - 1] = 0; // LCEMP does this but I have no idea why, TODO: why? m_serverSettings = dis->readInt(); m_hostIndex = dis->readByte(); 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 > *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 > *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(dis->readInt()); - dwTextureBytes = static_cast(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(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(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;ipbData= new BYTE [dwBytes]; - - for(DWORD i=0;ipbData[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(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(pSource); const unsigned char *pucEnd = pucIn + SrcSize; unsigned char *pucOut = static_cast(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; -- cgit v1.2.3