summaryrefslogtreecommitdiff
path: root/Source/Core
diff options
context:
space:
mode:
authorAdmiral H. Curtiss <pikachu025@gmail.com>2026-07-21 01:30:10 +0200
committerGitHub <noreply@github.com>2026-07-21 01:30:10 +0200
commitda1aad51880bbff94ee85f2f4ecb1cb138cd568b (patch)
tree592fc5e2a5d366694ddc0a4bde606f28a33089f4 /Source/Core
parentcb9df1264526c37ed3901afc622c456e8ee137da (diff)
parent5b9961b0c6572dd15040c00ef7e0e244b5526028 (diff)
Merge pull request #14740 from acts-1631/security/netplay-lzo-bounds
NetPlay: bound LZO decompression output
Diffstat (limited to 'Source/Core')
-rw-r--r--Source/Core/Core/NetPlayCommon.cpp49
1 files changed, 37 insertions, 12 deletions
diff --git a/Source/Core/Core/NetPlayCommon.cpp b/Source/Core/Core/NetPlayCommon.cpp
index 68500d04f4..0d1d73ecbf 100644
--- a/Source/Core/Core/NetPlayCommon.cpp
+++ b/Source/Core/Core/NetPlayCommon.cpp
@@ -174,7 +174,7 @@ bool CompressBufferIntoPacket(std::span<const u8> in_buffer, sf::Packet& packet)
bool DecompressPacketIntoFile(sf::Packet& packet, const std::string& file_path)
{
- u64 file_size = Common::PacketReadU64(packet);
+ const u64 file_size = Common::PacketReadU64(packet);
if (file_size == 0)
return true;
@@ -188,11 +188,12 @@ bool DecompressPacketIntoFile(sf::Packet& packet, const std::string& file_path)
std::vector<u8> in_buffer(LZO_OUT_LEN);
std::vector<u8> out_buffer(LZO_IN_LEN);
+ u64 bytes_written = 0;
while (true)
{
- u32 cur_len = 0; // number of bytes to read
- lzo_uint new_len = 0; // number of bytes to write
+ u32 cur_len = 0; // number of bytes to read
+ lzo_uint new_len = out_buffer.size(); // output buffer capacity
packet >> cur_len;
if (!cur_len)
@@ -209,21 +210,29 @@ bool DecompressPacketIntoFile(sf::Packet& packet, const std::string& file_path)
packet >> in_buffer[j];
}
- if (lzo1x_decompress(in_buffer.data(), cur_len, out_buffer.data(), &new_len, nullptr) !=
+ if (lzo1x_decompress_safe(in_buffer.data(), cur_len, out_buffer.data(), &new_len, nullptr) !=
LZO_E_OK)
{
PanicAlertFmtT("Internal LZO Error - decompression failed");
return false;
}
+ if (new_len > file_size - bytes_written)
+ {
+ PanicAlertFmtT("LZO error - output is too large");
+ return false;
+ }
+
if (!file.WriteBytes(out_buffer.data(), new_len))
{
PanicAlertFmtT("Error writing file: {0}", file_path);
return false;
}
+
+ bytes_written += new_len;
}
- return true;
+ return bytes_written == file_size;
}
static bool DecompressPacketIntoFolderInternal(sf::Packet& packet, const std::string& folder_path)
@@ -269,20 +278,21 @@ bool DecompressPacketIntoFolder(sf::Packet& packet, const std::string& folder_pa
std::optional<std::vector<u8>> DecompressPacketIntoBuffer(sf::Packet& packet)
{
- u64 size = Common::PacketReadU64(packet);
+ const u64 size = Common::PacketReadU64(packet);
- std::vector<u8> out_buffer(size);
+ std::vector<u8> out_buffer;
if (size == 0)
return out_buffer;
std::vector<u8> in_buffer(LZO_OUT_LEN);
+ std::vector<u8> decompressed_buffer(LZO_IN_LEN);
- lzo_uint i = 0;
+ u64 decompressed_size = 0;
while (true)
{
- u32 cur_len = 0; // number of bytes to read
- lzo_uint new_len = 0; // number of bytes to write
+ u32 cur_len = 0; // number of bytes to read
+ lzo_uint new_len = decompressed_buffer.size(); // output buffer capacity
packet >> cur_len;
if (!cur_len)
@@ -299,13 +309,28 @@ std::optional<std::vector<u8>> DecompressPacketIntoBuffer(sf::Packet& packet)
packet >> in_buffer[j];
}
- if (lzo1x_decompress(in_buffer.data(), cur_len, &out_buffer[i], &new_len, nullptr) != LZO_E_OK)
+ if (lzo1x_decompress_safe(in_buffer.data(), cur_len, decompressed_buffer.data(), &new_len,
+ nullptr) != LZO_E_OK)
{
PanicAlertFmtT("Internal LZO Error - decompression failed");
return {};
}
- i += new_len;
+ if (new_len > size - decompressed_size || new_len > out_buffer.max_size() - out_buffer.size())
+ {
+ PanicAlertFmtT("LZO error - output is too large");
+ return {};
+ }
+
+ out_buffer.insert(out_buffer.end(), decompressed_buffer.begin(),
+ decompressed_buffer.begin() + new_len);
+ decompressed_size += new_len;
+ }
+
+ if (decompressed_size != size)
+ {
+ PanicAlertFmtT("LZO error - output size mismatch");
+ return {};
}
return out_buffer;