From e5e63d50eac1b4357a5a7a0abd3c5f99a5c47881 Mon Sep 17 00:00:00 2001 From: Lasse Collin Date: Wed, 9 Sep 2026 14:14:40 +0300 Subject: [PATCH] liblzma: Clean up after a filter chain initialization error Filter coders are initialized using lzma_next_filter_init(). If filter chain initialization fails, the entire filter chain should be cleaned up with lzma_next_end(). lzma_raw_encoder_init() and lzma_raw_decoder_init() have always done this via lzma_raw_coder_init() in filter_common.c. (Separate cleanup is weird, but it must have made sense to the young me.) The following decoders initialize LZMA1 filter directly without using the raw filter chain API. This avoids needlessly pulling in all other filters when a program is linked against static liblzma. These functions didn't call lzma_next_end() after an initialization error, which left the state available for later reinitialization. - lzma_alone_decoder() - lzma_lzip_decoder() - lzma_auto_decoder() [*] - lzma_microlzma_decoder() [*] lzma_auto_decoder() is only indirectly affected due to the first two functions. lzma_auto_decoder() itself doesn't need a fix. There are also encoder functions that initialize the LZMA1 encoder directly. They don't have this issue because the whole lzma_stream is cleaned up when encoder initialization fails. Reported-by: GitHub user christos-cantina-security (christos-spearbit) --- src/liblzma/common/alone_decoder.c | 8 ++++++-- src/liblzma/common/lzip_decoder.c | 8 ++++++-- src/liblzma/common/microlzma_decoder.c | 8 ++++++-- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/src/liblzma/common/alone_decoder.c b/src/liblzma/common/alone_decoder.c index 8ebbbe8a..174b3b1d 100644 --- a/src/liblzma/common/alone_decoder.c +++ b/src/liblzma/common/alone_decoder.c @@ -152,8 +152,12 @@ alone_decode(void *coder_ptr, const lzma_allocator *allocator, } }; - return_if_error(lzma_next_filter_init(&coder->next, - allocator, filters)); + const lzma_ret ret = lzma_next_filter_init(&coder->next, + allocator, filters); + if (ret != LZMA_OK) { + lzma_next_end(&coder->next, allocator); + return ret; + } coder->sequence = SEQ_CODE; break; diff --git a/src/liblzma/common/lzip_decoder.c b/src/liblzma/common/lzip_decoder.c index 5630039f..d6f929d2 100644 --- a/src/liblzma/common/lzip_decoder.c +++ b/src/liblzma/common/lzip_decoder.c @@ -237,8 +237,12 @@ lzip_decode(void *coder_ptr, const lzma_allocator *allocator, } }; - return_if_error(lzma_next_filter_init(&coder->lzma_decoder, - allocator, filters)); + const lzma_ret ret = lzma_next_filter_init( + &coder->lzma_decoder, allocator, filters); + if (ret != LZMA_OK) { + lzma_next_end(&coder->lzma_decoder, allocator); + return ret; + } coder->crc32 = 0; coder->sequence = SEQ_LZMA_STREAM; diff --git a/src/liblzma/common/microlzma_decoder.c b/src/liblzma/common/microlzma_decoder.c index 882cb2c8..a7720cc2 100644 --- a/src/liblzma/common/microlzma_decoder.c +++ b/src/liblzma/common/microlzma_decoder.c @@ -108,8 +108,12 @@ microlzma_decode(void *coder_ptr, const lzma_allocator *allocator, } }; - return_if_error(lzma_next_filter_init(&coder->lzma, - allocator, filters)); + const lzma_ret ret = lzma_next_filter_init(&coder->lzma, + allocator, filters); + if (ret != LZMA_OK) { + lzma_next_end(&coder->lzma, allocator); + return ret; + } // Pass one dummy 0x00 byte to the LZMA decoder since that // is what it expects the first byte to be.