Skip to content

Commit efae43f

Browse files
aqrlnjasnell
authored andcommitted
zlib: fix node crashing on invalid options
This commit fixes the Node process crashing when constructors of classes of the zlib module are given invalid options. * Throw an Error when the zlib library rejects the value of windowBits, instead of crashing with an assertion. * Treat windowBits and memLevel options consistently with other ones and don't crash when non-numeric values are given. * Fix bugs in the validation logic: - Don't conflate 0 and undefined when checking if a field of an options object exists. - Treat NaN and Infinity values the same way as values of invalid types instead of allowing to actually set zlib options to NaN or Infinity. PR-URL: #13098 Fixes: #13082 Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Colin Ihrig <[email protected]> Reviewed-By: Luigi Pinca <[email protected]> Reviewed-By: Sakthipriyan Vairamani <[email protected]>
1 parent b4f6ea0 commit efae43f

File tree

4 files changed

+73
-15
lines changed

4 files changed

+73
-15
lines changed

doc/api/zlib.md

+4
Original file line numberDiff line numberDiff line change
@@ -437,6 +437,10 @@ added: v0.5.8
437437

438438
Returns a new [DeflateRaw][] object with an [options][].
439439

440+
**Note:** The zlib library rejects requests for 256-byte windows (i.e.,
441+
`{ windowBits: 8 }` in `options`). An `Error` will be thrown when creating
442+
a [DeflateRaw][] object with this specific value of the `windowBits` option.
443+
440444
## zlib.createGunzip([options])
441445
<!-- YAML
442446
added: v0.5.8

lib/zlib.js

+24-10
Original file line numberDiff line numberDiff line change
@@ -182,37 +182,37 @@ class Zlib extends Transform {
182182
this._finishFlushFlag = opts.finishFlush !== undefined ?
183183
opts.finishFlush : constants.Z_FINISH;
184184

185-
if (opts.chunkSize) {
185+
if (opts.chunkSize !== undefined) {
186186
if (opts.chunkSize < constants.Z_MIN_CHUNK) {
187187
throw new RangeError('Invalid chunk size: ' + opts.chunkSize);
188188
}
189189
}
190190

191-
if (opts.windowBits) {
191+
if (opts.windowBits !== undefined) {
192192
if (opts.windowBits < constants.Z_MIN_WINDOWBITS ||
193193
opts.windowBits > constants.Z_MAX_WINDOWBITS) {
194194
throw new RangeError('Invalid windowBits: ' + opts.windowBits);
195195
}
196196
}
197197

198-
if (opts.level) {
198+
if (opts.level !== undefined) {
199199
if (opts.level < constants.Z_MIN_LEVEL ||
200200
opts.level > constants.Z_MAX_LEVEL) {
201201
throw new RangeError('Invalid compression level: ' + opts.level);
202202
}
203203
}
204204

205-
if (opts.memLevel) {
205+
if (opts.memLevel !== undefined) {
206206
if (opts.memLevel < constants.Z_MIN_MEMLEVEL ||
207207
opts.memLevel > constants.Z_MAX_MEMLEVEL) {
208208
throw new RangeError('Invalid memLevel: ' + opts.memLevel);
209209
}
210210
}
211211

212-
if (opts.strategy && isInvalidStrategy(opts.strategy))
212+
if (opts.strategy !== undefined && isInvalidStrategy(opts.strategy))
213213
throw new TypeError('Invalid strategy: ' + opts.strategy);
214214

215-
if (opts.dictionary) {
215+
if (opts.dictionary !== undefined) {
216216
if (!ArrayBuffer.isView(opts.dictionary)) {
217217
throw new TypeError(
218218
'Invalid dictionary: it should be a Buffer, TypedArray, or DataView');
@@ -224,14 +224,28 @@ class Zlib extends Transform {
224224
this._hadError = false;
225225

226226
var level = constants.Z_DEFAULT_COMPRESSION;
227-
if (typeof opts.level === 'number') level = opts.level;
227+
if (Number.isFinite(opts.level)) {
228+
level = opts.level;
229+
}
228230

229231
var strategy = constants.Z_DEFAULT_STRATEGY;
230-
if (typeof opts.strategy === 'number') strategy = opts.strategy;
232+
if (Number.isFinite(opts.strategy)) {
233+
strategy = opts.strategy;
234+
}
235+
236+
var windowBits = constants.Z_DEFAULT_WINDOWBITS;
237+
if (Number.isFinite(opts.windowBits)) {
238+
windowBits = opts.windowBits;
239+
}
240+
241+
var memLevel = constants.Z_DEFAULT_MEMLEVEL;
242+
if (Number.isFinite(opts.memLevel)) {
243+
memLevel = opts.memLevel;
244+
}
231245

232-
this._handle.init(opts.windowBits || constants.Z_DEFAULT_WINDOWBITS,
246+
this._handle.init(windowBits,
233247
level,
234-
opts.memLevel || constants.Z_DEFAULT_MEMLEVEL,
248+
memLevel,
235249
strategy,
236250
opts.dictionary);
237251

src/node_zlib.cc

+8-5
Original file line numberDiff line numberDiff line change
@@ -551,16 +551,19 @@ class ZCtx : public AsyncWrap {
551551
CHECK(0 && "wtf?");
552552
}
553553

554-
if (ctx->err_ != Z_OK) {
555-
ZCtx::Error(ctx, "Init error");
556-
}
557-
558-
559554
ctx->dictionary_ = reinterpret_cast<Bytef *>(dictionary);
560555
ctx->dictionary_len_ = dictionary_len;
561556

562557
ctx->write_in_progress_ = false;
563558
ctx->init_done_ = true;
559+
560+
if (ctx->err_ != Z_OK) {
561+
if (dictionary != nullptr) {
562+
delete[] dictionary;
563+
ctx->dictionary_ = nullptr;
564+
}
565+
ctx->env()->ThrowError("Init error");
566+
}
564567
}
565568

566569
static void SetDictionary(ZCtx* ctx) {
+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
'use strict';
2+
3+
require('../common');
4+
5+
const assert = require('assert');
6+
const zlib = require('zlib');
7+
8+
// For raw deflate encoding, requests for 256-byte windows are rejected as
9+
// invalid by zlib.
10+
// (http://zlib.net/manual.html#Advanced)
11+
assert.throws(() => {
12+
zlib.createDeflateRaw({ windowBits: 8 });
13+
}, /^Error: Init error$/);
14+
15+
// Regression tests for bugs in the validation logic.
16+
17+
assert.throws(() => {
18+
zlib.createGzip({ chunkSize: 0 });
19+
}, /^RangeError: Invalid chunk size: 0$/);
20+
21+
assert.throws(() => {
22+
zlib.createGzip({ windowBits: 0 });
23+
}, /^RangeError: Invalid windowBits: 0$/);
24+
25+
assert.throws(() => {
26+
zlib.createGzip({ memLevel: 0 });
27+
}, /^RangeError: Invalid memLevel: 0$/);
28+
29+
{
30+
const stream = zlib.createGzip({ level: NaN });
31+
assert.strictEqual(stream._level, zlib.constants.Z_DEFAULT_COMPRESSION);
32+
}
33+
34+
{
35+
const stream = zlib.createGzip({ strategy: NaN });
36+
assert.strictEqual(stream._strategy, zlib.constants.Z_DEFAULT_STRATEGY);
37+
}

0 commit comments

Comments
 (0)