]> git.ipfire.org Git - thirdparty/zlib-ng.git/commitdiff
cap gzbuffer request at 1 GiB in the api
authordxbjavid <dxbjavid@gmail.com>
Tue, 23 Jun 2026 13:42:18 +0000 (19:12 +0530)
committerHans Kristian Rosbach <hk-github@circlestorm.org>
Sat, 4 Jul 2026 12:40:06 +0000 (14:40 +0200)
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.

gzguts.h
gzlib.c
zlib-ng.h.in

index 4064adda63b80cd245fced7ec5c6699751fe5b7b..f953aac500df9097a392143a21a61af0e3d32440 100644 (file)
--- a/gzguts.h
+++ b/gzguts.h
 #  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 ee9447189602591a8df3dd63ce94d9aa990cc77e..275309954f3a6d73e24549ecfcc22f3300de592e 100644 (file)
--- 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;
index 887a7c0ba8990538fc202b55378b82d14bf9dd41..1b51117810e5405332685de6dcb1388d18646da3 100644 (file)
@@ -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