]> git.kaiwu.me - njs.git/commitdiff
QuickJS: fix infinite loop on inflate of a stream needing a dictionary
authorDmitry Volyntsev <xeioex@nginx.com>
Fri, 12 Jun 2026 01:36:22 +0000 (18:36 -0700)
committerDmitry Volyntsev <xeioexception@gmail.com>
Tue, 16 Jun 2026 23:22:57 +0000 (16:22 -0700)
The qjs inflate loop treated only rc < 0 as an error.  Z_NEED_DICT is
positive, so a zlib stream with the FDICT flag and no dictionary made
inflate() return Z_NEED_DICT with no progress every iteration, spinning
forever and growing the output chain on attacker-controlled input.

Handle Z_NEED_DICT explicitly, matching the njs zlib module.

external/qjs_zlib_module.c
test/zlib.t.mjs

index 5abf108a1ba5942df1a3d7a5cc9ee808783174c3..caeb2761efb7d1613bc10e1a59174846643e476b 100644 (file)
@@ -415,6 +415,11 @@ qjs_zlib_ext_inflate(JSContext *ctx, JSValueConst this_val, int argc,
             goto fail;
         }
 
+        if (rc == Z_NEED_DICT) {
+            JS_ThrowTypeError(ctx, "failed to inflate, dictionary is required");
+            goto fail;
+        }
+
         njs_chb_written(&chain, chunk_size - stream.avail_out);
     }
 
index faef1fb018a61e728f17af5514c81b2df4bd6553..612a41984ed29893132e1e0a53e76000ad9bc16d 100644 (file)
@@ -93,6 +93,10 @@ let inflateSync_tsuite = {
 
         { value: zlib.deflateRawSync('WAKA', {dictionary: Buffer.from('WAKA')}),
           exception: 'InternalError: failed to inflate the compressed data: invalid distance too far back' },
+
+        { value: zlib.deflateSync('WAKA WAKA WAKA', {dictionary: Buffer.from('WAKA')}),
+          raw: false,
+          exception: 'TypeError: failed to inflate, dictionary is required' },
 ]};
 
 run([