From 1c0e42706c988e0c85b23db5ac1632b48560cc60 Mon Sep 17 00:00:00 2001 From: Anand Suresh Date: Thu, 29 Mar 2018 15:07:44 -0700 Subject: [PATCH 1/2] zlib: fix windowBits validation to allow 0 for decompression mode From the zlib v1.2.11 manual: > ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, > int windowBits)); > > ... > windowBits can also be zero to request that inflate use the window > size in the zlib header of the compressed stream. The current validation of windowBits in zlib.js doesn't check for this case. --- lib/zlib.js | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/lib/zlib.js b/lib/zlib.js index 01a2ebe9335bad..fabe30b3a7157b 100644 --- a/lib/zlib.js +++ b/lib/zlib.js @@ -251,9 +251,20 @@ function Zlib(opts, mode) { opts.finishFlush, 'options.finishFlush', Z_NO_FLUSH, Z_BLOCK, Z_FINISH); - windowBits = checkRangesOrGetDefault( - opts.windowBits, 'options.windowBits', - Z_MIN_WINDOWBITS, Z_MAX_WINDOWBITS, Z_DEFAULT_WINDOWBITS); + // windowBits is special. On the compression side, 0 is an invalid value. + // But on the decompression side, a value of 0 for windowBits tells zlib + // to extract the value from the headers of the compressed stream. + if (opts.windowBits === 0 && + (mode === INFLATE || + mode === GUNZIP || + mode === INFLATERAW || + mode === UNZIP)) { + windowBits = 0 + } else { + windowBits = checkRangesOrGetDefault( + opts.windowBits, 'options.windowBits', + Z_MIN_WINDOWBITS, Z_MAX_WINDOWBITS, Z_DEFAULT_WINDOWBITS); + } level = checkRangesOrGetDefault( opts.level, 'options.level', From fda4044819fa2e092ac6283049465c9b2073bddd Mon Sep 17 00:00:00 2001 From: Anand Suresh Date: Thu, 29 Mar 2018 16:17:26 -0700 Subject: [PATCH 2/2] zlib: code-review fixes --- lib/zlib.js | 11 ++++---- src/node_zlib.cc | 12 ++++++-- test/parallel/test-zlib-zero-windowBits.js | 33 ++++++++++++++++++++++ 3 files changed, 48 insertions(+), 8 deletions(-) create mode 100644 test/parallel/test-zlib-zero-windowBits.js diff --git a/lib/zlib.js b/lib/zlib.js index fabe30b3a7157b..654b248c3f96a8 100644 --- a/lib/zlib.js +++ b/lib/zlib.js @@ -251,15 +251,14 @@ function Zlib(opts, mode) { opts.finishFlush, 'options.finishFlush', Z_NO_FLUSH, Z_BLOCK, Z_FINISH); - // windowBits is special. On the compression side, 0 is an invalid value. - // But on the decompression side, a value of 0 for windowBits tells zlib - // to extract the value from the headers of the compressed stream. - if (opts.windowBits === 0 && + // windowBits is special. On the compression side, 0 is an invalid value. + // But on the decompression side, a value of 0 for windowBits tells zlib + // to use the window size in the zlib header of the compressed stream. + if ((opts.windowBits == null || opts.windowBits === 0) && (mode === INFLATE || mode === GUNZIP || - mode === INFLATERAW || mode === UNZIP)) { - windowBits = 0 + windowBits = 0; } else { windowBits = checkRangesOrGetDefault( opts.windowBits, 'options.windowBits', diff --git a/src/node_zlib.cc b/src/node_zlib.cc index 500a62a52bf6c4..4367d043d25a30 100644 --- a/src/node_zlib.cc +++ b/src/node_zlib.cc @@ -438,9 +438,17 @@ class ZCtx : public AsyncWrap { ZCtx* ctx; ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder()); + // windowBits is special. On the compression side, 0 is an invalid value. + // But on the decompression side, a value of 0 for windowBits tells zlib + // to use the window size in the zlib header of the compressed stream. int windowBits = args[0]->Uint32Value(); - CHECK((windowBits >= Z_MIN_WINDOWBITS && windowBits <= Z_MAX_WINDOWBITS) && - "invalid windowBits"); + if (!((windowBits == 0) && + (ctx->mode_ == INFLATE || + ctx->mode_ == GUNZIP || + ctx->mode_ == UNZIP))) { + CHECK((windowBits >= Z_MIN_WINDOWBITS && + windowBits <= Z_MAX_WINDOWBITS) && "invalid windowBits"); + } int level = args[1]->Int32Value(); CHECK((level >= Z_MIN_LEVEL && level <= Z_MAX_LEVEL) && diff --git a/test/parallel/test-zlib-zero-windowBits.js b/test/parallel/test-zlib-zero-windowBits.js new file mode 100644 index 00000000000000..a62e6148e33df7 --- /dev/null +++ b/test/parallel/test-zlib-zero-windowBits.js @@ -0,0 +1,33 @@ +'use strict'; + +const common = require('../common'); +const assert = require('assert'); +const zlib = require('zlib'); + + +// windowBits is a special case in zlib. On the compression side, 0 is invalid. +// On the decompression side, it indicates that zlib should use the value from +// the header of the compressed stream. +{ + const inflate = zlib.createInflate({ windowBits: 0 }); + assert(inflate instanceof zlib.Inflate); +} + +{ + const gunzip = zlib.createGunzip({ windowBits: 0 }); + assert(gunzip instanceof zlib.Gunzip); +} + +{ + const unzip = zlib.createUnzip({ windowBits: 0 }); + assert(unzip instanceof zlib.Unzip); +} + +{ + common.expectsError(() => zlib.createGzip({ windowBits: 0 }), { + code: 'ERR_OUT_OF_RANGE', + type: RangeError, + message: 'The value of "options.windowBits" is out of range. ' + + 'It must be >= 8 and <= 15. Received 0' + }); +}