mirror of
https://github.com/nodejs/node.git
synced 2026-10-28 18:25:13 +08:00
zlib: validate pledgedSrcSize as a safe integer
pledgedSrcSize represents an exact byte count. Reject values that are not non-negative safe integers instead of silently ignoring or coercing them through IntegerValue(). Apply the same validation to zlib/iter and retain a native validation check for internal callers. Signed-off-by: Archkon <180910180+Archkon@users.noreply.github.com> PR-URL: https://github.com/nodejs/node/pull/64604 Fixes: https://github.com/nodejs/node/issues/64603 Reviewed-By: Ethan Arrowood <ethan@arrowood.dev> Reviewed-By: Jan Martin <jan.krems@gmail.com>
This commit is contained in:
1 parent
fe5037baa9
commit
de6eeece8f
6 files changed
+65
-26
No files matched your search
+5
-3
@@ -784,8 +784,9 @@ const stream = zlib.createZstdCompress({
|
||||
#### Pledged Source Size
|
||||
|
||||
It's possible to specify the expected total size of the uncompressed input via
|
||||
`opts.pledgedSrcSize`. If the size doesn't match at the end of the input,
|
||||
compression will fail with the code `ZSTD_error_srcSize_wrong`.
|
||||
`opts.pledgedSrcSize`, which must be a non-negative safe integer. If the size
|
||||
doesn't match at the end of the input, compression will fail with the code
|
||||
`ZSTD_error_srcSize_wrong`.
|
||||
|
||||
#### Decompressor options
|
||||
|
||||
@@ -1927,7 +1928,8 @@ added: v25.9.0
|
||||
`ZSTD_btultra2`.
|
||||
See the [Zstd compressor options][] in the zlib documentation for the
|
||||
full list.
|
||||
* `pledgedSrcSize` {number} Expected uncompressed size (optional hint).
|
||||
* `pledgedSrcSize` {number} Expected uncompressed size as a non-negative safe
|
||||
integer (optional hint).
|
||||
* `dictionary` {Buffer|TypedArray|DataView}
|
||||
* Returns: {Object} A stateful transform.
|
||||
|
||||
|
||||
@@ -257,16 +257,6 @@ function createZstdHandle(mode, options, processCallback, onError) {
|
||||
validateParams(options.params, maxParam, ERR_ZSTD_INVALID_PARAM);
|
||||
|
||||
const pledgedSrcSize = options.pledgedSrcSize;
|
||||
if (pledgedSrcSize !== undefined) {
|
||||
if (typeof pledgedSrcSize !== 'number' || NumberIsNaN(pledgedSrcSize)) {
|
||||
throw new ERR_INVALID_ARG_TYPE('options.pledgedSrcSize', 'number',
|
||||
pledgedSrcSize);
|
||||
}
|
||||
if (pledgedSrcSize < 0) {
|
||||
throw new ERR_OUT_OF_RANGE('options.pledgedSrcSize', '>= 0',
|
||||
pledgedSrcSize);
|
||||
}
|
||||
}
|
||||
|
||||
const handle = isCompress ?
|
||||
new binding.ZstdCompress() : new binding.ZstdDecompress();
|
||||
|
||||
+1
-1
@@ -939,7 +939,7 @@ class Zstd extends ZlibBase {
|
||||
const handle = mode === ZSTD_COMPRESS ?
|
||||
new binding.ZstdCompress() : new binding.ZstdDecompress();
|
||||
|
||||
const pledgedSrcSize = opts?.pledgedSrcSize ?? undefined;
|
||||
const pledgedSrcSize = opts?.pledgedSrcSize;
|
||||
|
||||
const writeState = new Uint32Array(2);
|
||||
|
||||
|
||||
+13
-11
@@ -941,9 +941,6 @@ class ZstdStream final : public CompressionStream<CompressionContext> {
|
||||
}
|
||||
|
||||
static void Init(const FunctionCallbackInfo<Value>& args) {
|
||||
Environment* env = Environment::GetCurrent(args);
|
||||
Local<Context> context = env->context();
|
||||
|
||||
CHECK((args.Length() == 4 || args.Length() == 5) &&
|
||||
"init(params, pledgedSrcSize, writeResult, writeCallback[, "
|
||||
"dictionary])");
|
||||
@@ -960,19 +957,24 @@ class ZstdStream final : public CompressionStream<CompressionContext> {
|
||||
wrap->InitStream(write_result, write_js_callback);
|
||||
|
||||
uint64_t pledged_src_size = ZSTD_CONTENTSIZE_UNKNOWN;
|
||||
if (args[1]->IsNumber()) {
|
||||
int64_t signed_pledged_src_size;
|
||||
if (!args[1]->IntegerValue(context).To(&signed_pledged_src_size)) {
|
||||
THROW_ERR_INVALID_ARG_VALUE(wrap->env(),
|
||||
"pledgedSrcSize should be an integer");
|
||||
if (!args[1]->IsUndefined()) {
|
||||
if (!args[1]->IsNumber()) {
|
||||
THROW_ERR_INVALID_ARG_TYPE(wrap->env(),
|
||||
"pledgedSrcSize must be a number");
|
||||
return;
|
||||
}
|
||||
if (!IsSafeJsInt(args[1])) {
|
||||
THROW_ERR_OUT_OF_RANGE(wrap->env(),
|
||||
"pledgedSrcSize must be a safe integer");
|
||||
return;
|
||||
}
|
||||
const int64_t signed_pledged_src_size = args[1].As<Integer>()->Value();
|
||||
if (signed_pledged_src_size < 0) {
|
||||
THROW_ERR_INVALID_ARG_VALUE(wrap->env(),
|
||||
"pledgedSrcSize may not be negative");
|
||||
THROW_ERR_OUT_OF_RANGE(wrap->env(),
|
||||
"pledgedSrcSize must be non-negative");
|
||||
return;
|
||||
}
|
||||
pledged_src_size = signed_pledged_src_size;
|
||||
pledged_src_size = static_cast<uint64_t>(signed_pledged_src_size);
|
||||
}
|
||||
|
||||
AllocScope alloc_scope(wrap);
|
||||
|
||||
@@ -353,7 +353,16 @@ async function testAsyncValidation() {
|
||||
|
||||
// Zstd pledgedSrcSize
|
||||
await assert.rejects(consume(compressZstd({ pledgedSrcSize: 'bad' })), TYPE);
|
||||
await assert.rejects(consume(compressZstd({ pledgedSrcSize: -1 })), RANGE);
|
||||
for (const pledgedSrcSize of [
|
||||
NaN,
|
||||
Infinity,
|
||||
-Infinity,
|
||||
1.9,
|
||||
-1,
|
||||
Number.MAX_SAFE_INTEGER + 1,
|
||||
]) {
|
||||
await assert.rejects(consume(compressZstd({ pledgedSrcSize })), RANGE);
|
||||
}
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
|
||||
@@ -35,3 +35,39 @@ compressWithPledgedSrcSize({ pledgedSrcSize: 42, actualSrcSize: 0 });
|
||||
compressWithPledgedSrcSize({ pledgedSrcSize: 42, actualSrcSize: 13 });
|
||||
|
||||
compressWithPledgedSrcSize({ pledgedSrcSize: 42, actualSrcSize: 42 });
|
||||
|
||||
function assertInvalidPledgedSrcSize(pledgedSrcSize, expected) {
|
||||
assert.throws(
|
||||
() => zlib.createZstdCompress({ pledgedSrcSize }),
|
||||
expected,
|
||||
);
|
||||
assert.throws(
|
||||
() => zlib.zstdCompressSync('', { pledgedSrcSize }),
|
||||
expected,
|
||||
);
|
||||
}
|
||||
|
||||
for (const pledgedSrcSize of ['1', null]) {
|
||||
assertInvalidPledgedSrcSize(pledgedSrcSize, {
|
||||
name: 'TypeError',
|
||||
code: 'ERR_INVALID_ARG_TYPE',
|
||||
});
|
||||
}
|
||||
|
||||
for (const pledgedSrcSize of [
|
||||
NaN,
|
||||
Infinity,
|
||||
-Infinity,
|
||||
1.9,
|
||||
-1,
|
||||
Number.MAX_SAFE_INTEGER + 1,
|
||||
]) {
|
||||
assertInvalidPledgedSrcSize(pledgedSrcSize, {
|
||||
name: 'RangeError',
|
||||
code: 'ERR_OUT_OF_RANGE',
|
||||
});
|
||||
}
|
||||
|
||||
zlib.createZstdCompress({
|
||||
pledgedSrcSize: Number.MAX_SAFE_INTEGER,
|
||||
}).destroy();
|
||||
Reference in new issue
Block a user