diff options
| author | Admiral H. Curtiss <pikachu025@gmail.com> | 2026-07-21 01:30:10 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-07-21 01:30:10 +0200 |
| commit | da1aad51880bbff94ee85f2f4ecb1cb138cd568b (patch) | |
| tree | 592fc5e2a5d366694ddc0a4bde606f28a33089f4 | |
| parent | cb9df1264526c37ed3901afc622c456e8ee137da (diff) | |
| parent | 5b9961b0c6572dd15040c00ef7e0e244b5526028 (diff) | |
Merge pull request #14740 from acts-1631/security/netplay-lzo-bounds
NetPlay: bound LZO decompression output
| -rw-r--r-- | Source/Core/Core/NetPlayCommon.cpp | 49 |
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; |
