From: dxbjavid Date: Tue, 23 Jun 2026 13:42:18 +0000 (+0530) Subject: cap gzbuffer request at 1 GiB in the api X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=60c96e3e437bfbe841e28d9aa2d117a808ce060d;p=thirdparty%2Fzlib-ng.git cap gzbuffer request at 1 GiB in the api move the size limit into gzbuffer itself: zng_gzbuffer rejects requests over 1 GiB with -1 while the compat gzbuffer silently clamps to 1 GiB, keeping the checks next to the api like the rest of zlib-ng. with want bounded there the gz_buffer_alloc backstop is no longer needed, so drop it and note the limit in the zlib-ng.h docs. --- diff --git a/gzguts.h b/gzguts.h index 4064adda6..f953aac50 100644 --- a/gzguts.h +++ b/gzguts.h @@ -78,6 +78,13 @@ # define GZBUFSIZE 131072 #endif +/* upper limit on the requested buffer size; the allocation is three times this, + so the cap keeps that total well inside an unsigned and far above any size + that is useful in practice */ +#ifndef GZBUFSIZE_MAX +# define GZBUFSIZE_MAX (1u << 30) /* 1 GiB */ +#endif + /* gzip modes, also provide a little integrity check on the passed structure */ #define GZ_NONE 0 #define GZ_READ 7247 diff --git a/gzlib.c b/gzlib.c index ee9447189..275309954 100644 --- a/gzlib.c +++ b/gzlib.c @@ -80,15 +80,8 @@ int Z_INTERNAL gz_buffer_alloc(gz_state *state) { out_size = want * 2; // double output buffer for decompression } - /* the total reaches 3 * want but gzbuffer only guards 2 * want; cap against - INT_MAX (minus zng_alloc_aligned's overhead) and reject rather than wrap */ - const size_t aligned_overhead = sizeof(void *) + 64; - const size_t max_size = (size_t)INT_MAX - aligned_overhead; - if (out_size > max_size || in_size > max_size - out_size) { - PREFIX(gz_error)(state, Z_MEM_ERROR, "out of memory"); - return -1; - } - + /* gzbuffer caps want at GZBUFSIZE_MAX, so the total here stays inside the + unsigned that zng_alloc_aligned takes */ state->buffers = (unsigned char *)zng_alloc_aligned((unsigned)(in_size + out_size), 64); state->in = state->buffers; if (out_size) { @@ -341,8 +334,13 @@ z_int32_t Z_EXPORT PREFIX(gzbuffer)(gzFile file, z_uint32_t size) { return -1; /* check and set requested size */ - if ((size << 1) < size) - return -1; /* need to be able to double it */ + if (size > GZBUFSIZE_MAX) { +#ifdef ZLIB_COMPAT + size = GZBUFSIZE_MAX; /* silently clamp to stay compatible with zlib */ +#else + return -1; /* too large */ +#endif + } if (size < 8) size = 8; /* needed to behave well with flushing */ state->want = size; diff --git a/zlib-ng.h.in b/zlib-ng.h.in index 887a7c0ba..1b5111781 100644 --- a/zlib-ng.h.in +++ b/zlib-ng.h.in @@ -1363,6 +1363,10 @@ int32_t zng_gzbuffer(gzFile file, uint32_t size); If zlib-ng is compiled with 'WITH_REDUCED_MEM' set, the default buffer size is reduced to 8192 bytes. + The requested size is limited to 1 GiB, which is far larger than is useful + in practice. zng_gzbuffer() returns -1 when a larger size is requested, + while the zlib-compatible gzbuffer() silently clamps it to 1 GiB. + The new buffer size also affects the maximum length for gzprintf(). gzbuffer() returns 0 on success, or -1 on failure, such as being called