diff --git a/.github/workflows/build-node-openssl-fips.yml b/.github/workflows/build-node-openssl-fips.yml index 1837722ce720..d5950da06e0b 100644 --- a/.github/workflows/build-node-openssl-fips.yml +++ b/.github/workflows/build-node-openssl-fips.yml @@ -89,6 +89,9 @@ jobs: path: artifacts/${{ env.NODE_ARCHIVE_LATEST }} - name: Upload Node archive to release + # Keep branch builds in run-scoped artifacts so they cannot replace the + # shared release used by the regular Node 22 build process. + if: github.ref == 'refs/heads/v22.21.1' uses: softprops/action-gh-release@v1 with: name: node-${{ env.NODE_VERSION }}-fips-LATEST diff --git a/.github/workflows/build-node.yml b/.github/workflows/build-node.yml index 5d3e80fc1931..ff06bd1db1d8 100644 --- a/.github/workflows/build-node.yml +++ b/.github/workflows/build-node.yml @@ -82,6 +82,9 @@ jobs: path: artifacts/${{ env.NODE_ARCHIVE_LATEST }} - name: Upload Node archive to release + # Keep branch builds in run-scoped artifacts so they cannot replace the + # shared release used by fibers and native-package builds. + if: github.ref == 'refs/heads/v22.21.1' uses: softprops/action-gh-release@v1 with: name: node-${{ env.NODE_VERSION }}-LATEST diff --git a/deps/brotli/c/dec/decode.c b/deps/brotli/c/dec/decode.c index 220c7e85c633..0017e2c059ce 100644 --- a/deps/brotli/c/dec/decode.c +++ b/deps/brotli/c/dec/decode.c @@ -1124,7 +1124,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[ @@ -1135,7 +1135,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. */ @@ -1145,11 +1145,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; } } @@ -1165,7 +1167,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( @@ -1202,59 +1204,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( @@ -1887,6 +1895,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) { \ @@ -1899,6 +1910,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; @@ -1938,7 +1965,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. */ @@ -2046,7 +2073,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)); } @@ -2240,7 +2267,7 @@ static BROTLI_INLINE BrotliDecoderErrorCode ProcessCommandsInternal( } NextLiteralBlock: - BROTLI_SAFE(DecodeLiteralBlockSwitch(s)); + BROTLI_SAFE_WITH_STATUS(DecodeLiteralBlockSwitch(s)); goto CommandInner; saveStateAndReturn: @@ -2462,6 +2489,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 af1aa23f60d7..18ca1482d759 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/src/node_zlib.cc b/src/node_zlib.cc index 05818affb1bd..4d591555e8bd 100644 --- a/src/node_zlib.cc +++ b/src/node_zlib.cc @@ -1813,6 +1813,7 @@ void DefineZlibConstants(Local target) { NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_FORMAT_PADDING_1); NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_FORMAT_PADDING_2); NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_FORMAT_DISTANCE); + NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_FORMAT_BLOCK_SWITCH); NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_DICTIONARY_NOT_SET); NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_INVALID_ARGUMENTS); NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_ALLOC_CONTEXT_MODES); diff --git a/test/parallel/test-zlib-invalid-input.js b/test/parallel/test-zlib-invalid-input.js index 3ec7a15e0bb9..14197d978601 100644 --- a/test/parallel/test-zlib-invalid-input.js +++ b/test/parallel/test-zlib-invalid-input.js @@ -52,6 +52,33 @@ nonStringInputs.forEach(common.mustCall((input) => { }); }, nonStringInputs.length)); +{ + // A block switch is invalid when the stream declares only one block type. + const invalidBlockSwitch = Buffer.from( + '200010414141fcffff07002228f00b60f7f41f000000', + 'hex', + ); + const expectedError = { + code: 'ERR__ERROR_FORMAT_BLOCK_SWITCH', + errno: zlib.constants.BROTLI_DECODER_ERROR_FORMAT_BLOCK_SWITCH, + }; + + assert.strictEqual(expectedError.errno, -17); + assert.throws( + () => zlib.brotliDecompressSync(invalidBlockSwitch), + expectedError, + ); + + const brotli = zlib.createBrotliDecompress(); + brotli.resume(); + brotli.on('error', common.expectsError(expectedError)); + brotli.on('end', common.mustNotCall()); + for (let i = 0; i < invalidBlockSwitch.length; i++) { + brotli.write(invalidBlockSwitch.subarray(i, i + 1)); + } + brotli.end(); +} + unzips.forEach(common.mustCall((uz, i) => { uz.on('error', common.mustCall()); uz.on('end', common.mustNotCall());