Commit e5e63d50 for xz
commit e5e63d50eac1b4357a5a7a0abd3c5f99a5c47881
Author: Lasse Collin <lasse.collin@tukaani.org>
Date: Wed Sep 9 14:14:40 2026 +0300
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)
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.