From 0b3936b49f06743ea7aa48f4c03c99edf48afe80 Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Wed, 23 Mar 2016 11:45:38 +0100 Subject: [PATCH] zlib: Fix handling of gzip magic bytes mid-file Only treat the gzip magic bytes, when encountered within the file after reading a single block, as the start of a new member when the previous member has ended. Add test files that reliably reproduce #5852. The gzipped file in test/fixtures/pseudo-multimember-gzip.gz contains the gzip magic bytes exactly at the position that node encounters after having read a single block, leading it to believe that a new data member is starting. Fixes: https://github.com/nodejs/node/issues/5852 PR-URL: https://github.com/nodejs/node/pull/5863 Reviewed-By: Ben Noordhuis Reviewed-By: Colin Ihrig Reviewed-By: James M Snell Reviewed-By: Jeremiah Senkpiel --- src/node_zlib.cc | 3 ++- test/fixtures/pseudo-multimember-gzip.gz | Bin 0 -> 161 bytes test/fixtures/pseudo-multimember-gzip.z | Bin 0 -> 148 bytes .../test-zlib-from-concatenated-gzip.js | 22 ++++++++++++++++++ 4 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 test/fixtures/pseudo-multimember-gzip.gz create mode 100644 test/fixtures/pseudo-multimember-gzip.z diff --git a/src/node_zlib.cc b/src/node_zlib.cc index 4984989bb44066..0712f8feec6f08 100644 --- a/src/node_zlib.cc +++ b/src/node_zlib.cc @@ -258,7 +258,8 @@ class ZCtx : public AsyncWrap { } } while (ctx->strm_.avail_in >= GZIP_MIN_HEADER_SIZE && - ctx->mode_ == GUNZIP) { + ctx->mode_ == GUNZIP && + ctx->err_ == Z_STREAM_END) { // Bytes remain in input buffer. Perhaps this is another compressed // member in the same archive, or just trailing garbage. // Check the header to find out. diff --git a/test/fixtures/pseudo-multimember-gzip.gz b/test/fixtures/pseudo-multimember-gzip.gz new file mode 100644 index 0000000000000000000000000000000000000000..a019c484d854820da00e478ed3d8509b626523e9 GIT binary patch literal 161 zcmb2|=3qF}^(l;r`RzeNMg|6kLkqt8zfI&_0A!*9`EFD`ZFzZ8bsY2l|6*hS01{gc ACjbBd literal 0 HcmV?d00001 diff --git a/test/fixtures/pseudo-multimember-gzip.z b/test/fixtures/pseudo-multimember-gzip.z new file mode 100644 index 0000000000000000000000000000000000000000..e87b13ab534fbca0aed4ef958fef8bd67644969e GIT binary patch literal 148 jcmb=J^Y)-2BLf4&p#@+4-{!L|05S&-G#LNpV_*aTG13WI literal 0 HcmV?d00001 diff --git a/test/parallel/test-zlib-from-concatenated-gzip.js b/test/parallel/test-zlib-from-concatenated-gzip.js index 9bee905b33836b..36650e7b3b737f 100644 --- a/test/parallel/test-zlib-from-concatenated-gzip.js +++ b/test/parallel/test-zlib-from-concatenated-gzip.js @@ -4,6 +4,8 @@ const common = require('../common'); const assert = require('assert'); const zlib = require('zlib'); +const path = require('path'); +const fs = require('fs'); const data = Buffer.concat([ zlib.gzipSync('abc'), @@ -16,3 +18,23 @@ zlib.gunzip(data, common.mustCall((err, result) => { assert.ifError(err); assert.equal(result, 'abcdef', 'result should match original string'); })); + +// files that have the "right" magic bytes for starting a new gzip member +// in the middle of themselves, even if they are part of a single +// regularly compressed member +const pmmFileZlib = path.join(common.fixturesDir, 'pseudo-multimember-gzip.z'); +const pmmFileGz = path.join(common.fixturesDir, 'pseudo-multimember-gzip.gz'); + +const pmmExpected = zlib.inflateSync(fs.readFileSync(pmmFileZlib)); +const pmmResultBuffers = []; + +fs.createReadStream(pmmFileGz) + .pipe(zlib.createGunzip()) + .on('error', (err) => { + assert.ifError(err); + }) + .on('data', (data) => pmmResultBuffers.push(data)) + .on('finish', common.mustCall(() => { + assert.deepStrictEqual(Buffer.concat(pmmResultBuffers), pmmExpected, + 'result should match original random garbage'); + }));