Skip to content
Closed

Nodejs #63133

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,233 @@
Source: upstream, https://github.com/google/brotli/commit/0ed4268a4401abcb4472096340477cf4af7d1a2b
Upstream: yes, not in a release yet
Reason: CVE-2026-111497, node uses the new BROTLI_DECODER_ERROR_FORMAT_BLOCK_SWITCH since 22.23.4 and 24.22.1

From 0ed4268a4401abcb4472096340477cf4af7d1a2b Mon Sep 17 00:00:00 2001
From: Evgenii Kliuchnikov <eustas@google.com>
Date: Fri, 27 Feb 2026 05:10:32 -0800
Subject: [PATCH] Detect and report invalid stream earlier.

PiperOrigin-RevId: 876198329
---
c/dec/decode.c | 87 ++++++++++++++++++++++++++-------------
c/include/brotli/decode.h | 4 +-
2 files changed, 59 insertions(+), 32 deletions(-)

diff --git a/c/dec/decode.c b/c/dec/decode.c
index e87e7f5ea..19c7e0283 100644
--- a/c/dec/decode.c
+++ b/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 @@ static BROTLI_INLINE BrotliDecoderErrorCode ProcessCommandsInternal(
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 @@ static BROTLI_INLINE BrotliDecoderErrorCode ProcessCommandsInternal(
} 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 @@ static BROTLI_INLINE BrotliDecoderErrorCode ProcessCommandsInternal(
}

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/c/include/brotli/decode.h b/c/include/brotli/decode.h
index 8d436db73..10d01e365 100644
--- a/c/include/brotli/decode.h
+++ b/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 \
3 changes: 2 additions & 1 deletion srcpkgs/brotli/template
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Template file for 'brotli'
pkgname=brotli
version=1.2.0
revision=2
revision=3
build_style=cmake
configure_args="-DBROTLI_BUILD_FOR_PACKAGE=ON"
short_desc="Generic-purpose lossless compression algorithm"
Expand All @@ -25,6 +25,7 @@ brotli-devel_package() {
depends="${sourcepkg}>=${version}_${revision}"
pkg_install() {
vmove usr/include
vmove usr/share/man/man3
vmove usr/lib/*.so
vmove usr/lib/*.a
vmove usr/lib/pkgconfig
Expand Down
4 changes: 2 additions & 2 deletions srcpkgs/c-ares/template
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Template file for 'c-ares'
pkgname=c-ares
version=1.34.8
version=1.34.9
revision=1
build_style=gnu-configure
checkdepends="iana-etc"
Expand All @@ -10,7 +10,7 @@ license="MIT"
homepage="https://c-ares.org/"
changelog="https://c-ares.org/changelog.html"
distfiles="https://github.com/c-ares/c-ares/releases/download/v${version}/c-ares-${version}.tar.gz"
checksum=c222b6d681096f9444d2c4863d2c1174019e27cacca0a4a5c114d36dd7d7bf78
checksum=9364b70a12eb59a06830fb488d9357f90100dff0d98b23ea3593a183d43e6f2f
make_check=ci-skip # segfaults only on CI

post_install() {
Expand Down
14 changes: 0 additions & 14 deletions srcpkgs/nodejs/patches/cross-aarch64.patch

This file was deleted.

4 changes: 2 additions & 2 deletions srcpkgs/nodejs/template
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Template file for 'nodejs'
pkgname=nodejs
version=24.18.0
version=24.22.1
revision=1
build_style=configure
configure_args="
Expand Down Expand Up @@ -43,7 +43,7 @@ license="MIT"
homepage="https://nodejs.org/"
changelog="https://raw.githubusercontent.com/nodejs/node/main/doc/changelogs/CHANGELOG_V${version%%.*}.md"
distfiles="https://nodejs.org/dist/v${version}/node-v${version}.tar.xz"
checksum=e94afde24db08e0c564ee7110a2d5aab51ee0059382c9fd8233c54eec47b28f9
checksum=4f5379796280cdaeb0c2f358fd04b6a16cc4fb7dfa83b5a8c91a9d963b435231
python_version=3

build_options="ssl libuv icu nghttp2 cares brotli"
Expand Down
Loading