diff --git a/buffer.c b/buffer.c index 46ea7c4..d7fbe6d 100644 --- a/buffer.c +++ b/buffer.c @@ -39,6 +39,10 @@ private unsigned int MAGIC_COUNT = 0; private unsigned int AVAIL_COUNT = 0; private byte *NEXT_IN = NULL; +/* CWE-409: Decompression bomb protection - max 64 MiB decompressed output */ +#define MAX_DECOMPRESS_SIZE (64 * 1024 * 1024) +private unsigned long long total_decompressed = 0; + private int (*d_func1)(byte *, unsigned int); private int (*d_func2)(byte *, unsigned int); private int (*d_func3)(byte *, unsigned int); @@ -243,7 +247,13 @@ inflate_gzip(byte *p, unsigned int max) if (err != Z_OK && err != Z_STREAM_END) warn_exit("zlib inflate error (%d).", err); - inflated = max - z.avail_out; + inflated = max - z.avail_out; + + /* CWE-409: Check decompressed size limit */ + total_decompressed += (inflated - (max - old)); + if (total_decompressed > MAX_DECOMPRESS_SIZE) + warn_exit("decompression bomb detected: output exceeds %d MiB limit.", + MAX_DECOMPRESS_SIZE / (1024 * 1024)); if (old == z.avail_out && z.avail_in != 0) break; @@ -288,7 +298,13 @@ inflate_bzip2(byte *p, unsigned int max) if (err != BZ_OK && err != BZ_STREAM_END) warn_exit("bzip2 BZ2_bzDecompress error (%d).", err); - inflated = max - bz.avail_out; + inflated = max - bz.avail_out; + + /* CWE-409: Check decompressed size limit */ + total_decompressed += (inflated - (max - old)); + if (total_decompressed > MAX_DECOMPRESS_SIZE) + warn_exit("decompression bomb detected: output exceeds %d MiB limit.", + MAX_DECOMPRESS_SIZE / (1024 * 1024)); if (old == bz.avail_out && bz.avail_in != 0) break; @@ -377,7 +393,10 @@ Compressed_Data_Packet(int len) unsigned int alg = Getc(); int err; private int (*func)(byte *, unsigned int); - + + /* CWE-409: Reset decompressed size counter */ + total_decompressed = 0; + comp_algs(alg); #ifdef HAVE_LIBZ