diff --git a/src/Common.cpp b/src/Common.cpp index 024e701..82ab336 100644 --- a/src/Common.cpp +++ b/src/Common.cpp @@ -384,10 +384,16 @@ void SplitString(const std::string& str, const char delim, std::vector DeComp(std::span input) { beammp_debugf("got {} bytes of input data", input.size()); - std::vector output_buffer(std::min(input.size() * 5, 15 * 1024 * 1024)); + // start with a decompression buffer of 5x the input size, clamped to a maximum of 15 MB. + // this buffer can and will grow, but we don't want to start it too large. A 5x compression ratio + // is pretty optimistic. + std::vector output_buffer(std::min(input.size() * 5, STARTING_MAX_DECOMPRESSION_BUFFER_SIZE)); uLongf output_size = output_buffer.size(); @@ -398,11 +404,17 @@ std::vector DeComp(std::span input) { reinterpret_cast(input.data()), static_cast(input.size())); if (res == Z_BUF_ERROR) { - if (output_buffer.size() > 30 * 1024 * 1024) { - throw std::runtime_error("decompressed packet size of 30 MB exceeded"); + // We assume that a reasonable maximum size for decompressed packets exists. We want to avoid + // a client effectively "zip bombing" us by sending a lot of small packets which decompress + // into huge data. + // If this limit were to be an issue, this could be made configurable, however clients have a similar + // limit. For that reason, we just reject packets which decompress into too much data. + if (output_buffer.size() >= MAX_DECOMPRESSION_BUFFER_SIZE) { + throw std::runtime_error(fmt::format("decompressed packet size of {} bytes exceeded", MAX_DECOMPRESSION_BUFFER_SIZE)); } - beammp_warn("zlib uncompress() failed, trying with 2x buffer size of " + std::to_string(output_buffer.size() * 2)); - output_buffer.resize(output_buffer.size() * 2); + // if decompression fails, we double the buffer size (up to the allowed limit) and try again + output_buffer.resize(std::max(output_buffer.size() * 2, MAX_DECOMPRESSION_BUFFER_SIZE)); + beammp_warnf("zlib uncompress() failed, trying with a larger buffer size of {}", output_buffer.size()); output_size = output_buffer.size(); } else if (res != Z_OK) { beammp_error("zlib uncompress() failed: " + std::to_string(res));