Commit 8c5debbea41 for nodejs
commit 8c5debbea41dd50ed5b5bb9faf8ef442c5a794e4
Author: Evgenii Kliuchnikov <eustas@google.com>
Date: Fri Feb 27 05:10:32 2026 -0800
deps: brotli: cherry-pick 0ed4268a4401abcb44720963
Original commit message:
Detect and report invalid stream earlier.
PiperOrigin-RevId: 876198329
PR-URL: https://github.com/nodejs-private/node-private/pull/1002
Fixes: https://hackerone.com/reports/4107681
Refs: https://github.com/google/brotli/commit/0ed4268a4401abcb4472096340477cf4af7d1a2b
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
CVE-ID: CVE-2026-111497
diff --git a/deps/brotli/c/dec/decode.c b/deps/brotli/c/dec/decode.c
index e87e7f5ea0f..19c7e0283fa 100644
--- a/deps/brotli/c/dec/decode.c
+++ b/deps/brotli/c/dec/decode.c
@@ -1176,7 +1176,7 @@ static BrotliDecoderErrorCode DecodeContextMap(brotli_reg_t context_map_size,
/* Decodes a command or literal and updates block type ring-buffer.
Reads 3..54 bits. */
-static BROTLI_INLINE BROTLI_BOOL DecodeBlockTypeAndLength(
+static BROTLI_INLINE BrotliDecoderErrorCode DecodeBlockTypeAndLength(
int safe, BrotliDecoderState* s, int tree_type) {
brotli_reg_t max_block_type = s->num_block_types[tree_type];
const HuffmanCode* type_tree = &s->block_type_trees[
@@ -1187,7 +1187,7 @@ static BROTLI_INLINE BROTLI_BOOL DecodeBlockTypeAndLength(
brotli_reg_t* ringbuffer = &s->block_type_rb[tree_type * 2];
brotli_reg_t block_type;
if (max_block_type <= 1) {
- return BROTLI_FALSE;
+ return BROTLI_DECODER_ERROR_FORMAT_BLOCK_SWITCH;
}
/* Read 0..15 + 3..39 bits. */
@@ -1197,11 +1197,13 @@ static BROTLI_INLINE BROTLI_BOOL DecodeBlockTypeAndLength(
} else {
BrotliBitReaderState memento;
BrotliBitReaderSaveState(br, &memento);
- if (!SafeReadSymbol(type_tree, br, &block_type)) return BROTLI_FALSE;
+ if (!SafeReadSymbol(type_tree, br, &block_type)) {
+ return BROTLI_DECODER_NEEDS_MORE_INPUT;
+ }
if (!SafeReadBlockLength(s, &s->block_length[tree_type], len_tree, br)) {
s->substate_read_block_length = BROTLI_STATE_READ_BLOCK_LENGTH_NONE;
BrotliBitReaderRestoreState(br, &memento);
- return BROTLI_FALSE;
+ return BROTLI_DECODER_NEEDS_MORE_INPUT;
}
}
@@ -1217,7 +1219,7 @@ static BROTLI_INLINE BROTLI_BOOL DecodeBlockTypeAndLength(
}
ringbuffer[0] = ringbuffer[1];
ringbuffer[1] = block_type;
- return BROTLI_TRUE;
+ return BROTLI_DECODER_SUCCESS;
}
static BROTLI_INLINE void DetectTrivialLiteralBlockTypes(
@@ -1254,59 +1256,65 @@ static BROTLI_INLINE void PrepareLiteralDecoding(BrotliDecoderState* s) {
/* Decodes the block type and updates the state for literal context.
Reads 3..54 bits. */
-static BROTLI_INLINE BROTLI_BOOL DecodeLiteralBlockSwitchInternal(
+static BROTLI_INLINE BrotliDecoderErrorCode DecodeLiteralBlockSwitchInternal(
int safe, BrotliDecoderState* s) {
- if (!DecodeBlockTypeAndLength(safe, s, 0)) {
- return BROTLI_FALSE;
+ BrotliDecoderErrorCode result = DecodeBlockTypeAndLength(safe, s, 0);
+ if (result != BROTLI_DECODER_SUCCESS) {
+ return result;
}
PrepareLiteralDecoding(s);
- return BROTLI_TRUE;
+ return BROTLI_DECODER_SUCCESS;
}
-static void BROTLI_NOINLINE DecodeLiteralBlockSwitch(BrotliDecoderState* s) {
- DecodeLiteralBlockSwitchInternal(0, s);
+static BROTLI_NOINLINE BrotliDecoderErrorCode
+DecodeLiteralBlockSwitch(BrotliDecoderState* s) {
+ return DecodeLiteralBlockSwitchInternal(0, s);
}
-static BROTLI_BOOL BROTLI_NOINLINE SafeDecodeLiteralBlockSwitch(
+static BROTLI_NOINLINE BrotliDecoderErrorCode SafeDecodeLiteralBlockSwitch(
BrotliDecoderState* s) {
return DecodeLiteralBlockSwitchInternal(1, s);
}
/* Block switch for insert/copy length.
Reads 3..54 bits. */
-static BROTLI_INLINE BROTLI_BOOL DecodeCommandBlockSwitchInternal(
+static BROTLI_INLINE BrotliDecoderErrorCode DecodeCommandBlockSwitchInternal(
int safe, BrotliDecoderState* s) {
- if (!DecodeBlockTypeAndLength(safe, s, 1)) {
- return BROTLI_FALSE;
+ BrotliDecoderErrorCode result = DecodeBlockTypeAndLength(safe, s, 1);
+ if (result != BROTLI_DECODER_SUCCESS) {
+ return result;
}
s->htree_command = s->insert_copy_hgroup.htrees[s->block_type_rb[3]];
- return BROTLI_TRUE;
+ return BROTLI_DECODER_SUCCESS;
}
-static void BROTLI_NOINLINE DecodeCommandBlockSwitch(BrotliDecoderState* s) {
- DecodeCommandBlockSwitchInternal(0, s);
+static BROTLI_NOINLINE BrotliDecoderErrorCode
+DecodeCommandBlockSwitch(BrotliDecoderState* s) {
+ return DecodeCommandBlockSwitchInternal(0, s);
}
-static BROTLI_BOOL BROTLI_NOINLINE SafeDecodeCommandBlockSwitch(
- BrotliDecoderState* s) {
+static BROTLI_NOINLINE BrotliDecoderErrorCode
+SafeDecodeCommandBlockSwitch(BrotliDecoderState* s) {
return DecodeCommandBlockSwitchInternal(1, s);
}
/* Block switch for distance codes.
Reads 3..54 bits. */
-static BROTLI_INLINE BROTLI_BOOL DecodeDistanceBlockSwitchInternal(
+static BROTLI_INLINE BrotliDecoderErrorCode DecodeDistanceBlockSwitchInternal(
int safe, BrotliDecoderState* s) {
- if (!DecodeBlockTypeAndLength(safe, s, 2)) {
- return BROTLI_FALSE;
+ BrotliDecoderErrorCode result = DecodeBlockTypeAndLength(safe, s, 2);
+ if (result != BROTLI_DECODER_SUCCESS) {
+ return result;
}
s->dist_context_map_slice = s->dist_context_map +
(s->block_type_rb[5] << BROTLI_DISTANCE_CONTEXT_BITS);
s->dist_htree_index = s->dist_context_map_slice[s->distance_context];
- return BROTLI_TRUE;
+ return BROTLI_DECODER_SUCCESS;
}
-static void BROTLI_NOINLINE DecodeDistanceBlockSwitch(BrotliDecoderState* s) {
- DecodeDistanceBlockSwitchInternal(0, s);
+static BROTLI_NOINLINE BrotliDecoderErrorCode
+DecodeDistanceBlockSwitch(BrotliDecoderState* s) {
+ return DecodeDistanceBlockSwitchInternal(0, s);
}
static BROTLI_BOOL BROTLI_NOINLINE SafeDecodeDistanceBlockSwitch(
@@ -1940,6 +1948,9 @@ static BROTLI_INLINE BROTLI_BOOL CheckInputAmount(
return BrotliCheckInputAmount(br);
}
+/* NB: METHOD should return BROTLI_FALSE only in case there is not enough input;
+ in case of "unsafe" execution, when input is guaranteed to be sufficient,
+ result is ignored. */
#define BROTLI_SAFE(METHOD) \
{ \
if (safe) { \
@@ -1952,6 +1963,22 @@ static BROTLI_INLINE BROTLI_BOOL CheckInputAmount(
} \
}
+/* NB: METHOD should return BROTLI_DECODER_SUCCESS, BROTLI_DECODER_ERROR_*, or
+ BROTLI_DECODER_NEEDS_MORE_INPUT; the later two break the processing. */
+#define BROTLI_SAFE_WITH_STATUS(METHOD) \
+ { \
+ BrotliDecoderErrorCode status; \
+ if (safe) { \
+ status = Safe##METHOD; \
+ } else { \
+ status = METHOD; \
+ } \
+ if (status != BROTLI_DECODER_SUCCESS) { \
+ result = status; \
+ goto saveStateAndReturn; \
+ } \
+ }
+
static BROTLI_INLINE BrotliDecoderErrorCode ProcessCommandsInternal(
int safe, BrotliDecoderState* s) {
int pos = s->pos;
@@ -1991,7 +2018,7 @@ CommandBegin:
goto saveStateAndReturn;
}
if (BROTLI_PREDICT_FALSE(s->block_length[1] == 0)) {
- BROTLI_SAFE(DecodeCommandBlockSwitch(s));
+ BROTLI_SAFE_WITH_STATUS(DecodeCommandBlockSwitch(s));
goto CommandBegin;
}
/* Read the insert/copy length in the command. */
@@ -2136,7 +2163,7 @@ CommandPostDecodeLiterals:
} else {
/* Read distance code in the command, unless it was implicitly zero. */
if (BROTLI_PREDICT_FALSE(s->block_length[2] == 0)) {
- BROTLI_SAFE(DecodeDistanceBlockSwitch(s));
+ BROTLI_SAFE_WITH_STATUS(DecodeDistanceBlockSwitch(s));
}
BROTLI_SAFE(ReadDistance(s, br));
}
@@ -2330,7 +2357,7 @@ CommandPostWrapCopy:
}
NextLiteralBlock:
- BROTLI_SAFE(DecodeLiteralBlockSwitch(s));
+ BROTLI_SAFE_WITH_STATUS(DecodeLiteralBlockSwitch(s));
goto CommandInner;
saveStateAndReturn:
@@ -2552,6 +2579,8 @@ BrotliDecoderResult BrotliDecoderDecompressStream(
if (result != BROTLI_DECODER_SUCCESS) {
break;
}
+ BROTLI_DCHECK(s->meta_block_remaining_len <=
+ (int)BROTLI_BLOCK_SIZE_CAP);
BROTLI_LOG_UINT(s->is_last_metablock);
BROTLI_LOG_UINT(s->meta_block_remaining_len);
BROTLI_LOG_UINT(s->is_metadata);
diff --git a/deps/brotli/c/include/brotli/decode.h b/deps/brotli/c/include/brotli/decode.h
index 8d436db733c..10d01e3658b 100644
--- a/deps/brotli/c/include/brotli/decode.h
+++ b/deps/brotli/c/include/brotli/decode.h
@@ -85,9 +85,7 @@ typedef enum {
BROTLI_ERROR_CODE(_ERROR_FORMAT_, PADDING_1, -14) SEPARATOR \
BROTLI_ERROR_CODE(_ERROR_FORMAT_, PADDING_2, -15) SEPARATOR \
BROTLI_ERROR_CODE(_ERROR_FORMAT_, DISTANCE, -16) SEPARATOR \
- \
- /* -17 code is reserved */ \
- \
+ BROTLI_ERROR_CODE(_ERROR_FORMAT_, BLOCK_SWITCH, -17) SEPARATOR \
BROTLI_ERROR_CODE(_ERROR_, COMPOUND_DICTIONARY, -18) SEPARATOR \
BROTLI_ERROR_CODE(_ERROR_, DICTIONARY_NOT_SET, -19) SEPARATOR \
BROTLI_ERROR_CODE(_ERROR_, INVALID_ARGUMENTS, -20) SEPARATOR \
diff --git a/tools/nix/sharedLibDeps.nix b/tools/nix/sharedLibDeps.nix
index f45c55d76db..1d355d4a194 100644
--- a/tools/nix/sharedLibDeps.nix
+++ b/tools/nix/sharedLibDeps.nix
@@ -11,7 +11,6 @@
{
inherit (pkgs)
ada
- brotli
gtest
libuv
merve
@@ -23,6 +22,14 @@
zstd
;
abseil = pkgs.abseil-cpp;
+ brotli = pkgs.brotli.overrideAttrs (old: {
+ patches = (old.patches or [ ]) ++ [
+ (pkgs.fetchpatch2 {
+ url = "https://github.com/google/brotli/commit/0ed4268a4401abcb4472096340477cf4af7d1a2b.patch?full_index=1";
+ hash = "sha256-dVpnYI2JLDEt2VQkbI6RnbpdcQSMB5bTQ6TJp5CLnyw=";
+ })
+ ];
+ });
cares = pkgs.c-ares;
hdr-histogram = pkgs.hdrhistogram_c;
highway = pkgs.libhwy;