From 0fe3e2e604c68cc787e5ad8cfa65cfb2664561e4 Mon Sep 17 00:00:00 2001 From: Titouan Christophe Date: Mon, 14 Sep 2026 16:14:16 +0200 Subject: [PATCH] package/xz: add patch for GHSA-5qpq-xqfv-j9pg This fixes the following vulnerability: XZ Utils: Invalid write if a decoder is reinitialized after allocation failure See https://github.com/tukaani-project/xz/security/advisories/GHSA-5qpq-xqfv-j9pg There is still no CVE number assigned to the issue. (alternative to commit 6f125a653038c9460b515b1f0d4c8c4be37d88c3) Signed-off-by: Titouan Christophe Signed-off-by: Thomas Perale --- ...t-safe-to-reinit-after-alloc-failure.patch | 31 ++++++ ...-a-filter-chain-initialization-error.patch | 97 +++++++++++++++++++ 2 files changed, 128 insertions(+) create mode 100644 package/xz/0006-liblzma-make-lzma-lz-decoder-init-safe-to-reinit-after-alloc-failure.patch create mode 100644 package/xz/0007-liblzma-clean-up-after-a-filter-chain-initialization-error.patch diff --git a/package/xz/0006-liblzma-make-lzma-lz-decoder-init-safe-to-reinit-after-alloc-failure.patch b/package/xz/0006-liblzma-make-lzma-lz-decoder-init-safe-to-reinit-after-alloc-failure.patch new file mode 100644 index 0000000000..0fe4c55c2b --- /dev/null +++ b/package/xz/0006-liblzma-make-lzma-lz-decoder-init-safe-to-reinit-after-alloc-failure.patch @@ -0,0 +1,31 @@ +From: Lasse Collin +Date: Wed, 9 Sep 2026 14:14:40 +0300 +Subject: liblzma: Make lzma_lz_decoder_init() safe to reinit after alloc failure + +If memory allocation fails and the resulting coder state is reused, +ensure that memory allocation is attempted again. However, coders that +are initialized via lzma_next_filter_init() shouldn't be reinitialized +after failure; they should be cleaned up with lzma_next_end(). + +Reported-by: GitHub user christos-cantina-security (christos-spearbit) +(cherry picked from commit fe4d763d566a38ad61d4c5022520c25578a3a464) + +--- +Upstream: https://github.com/tukaani-project/xz/commit/0917f6d0f03d9add15dda27e0bf2ebfc22aaf67a +Signed-off-by: Titouan Christophe +--- + src/liblzma/lz/lz_decoder.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/liblzma/lz/lz_decoder.c b/src/liblzma/lz/lz_decoder.c +index 92913f225..18669300e 100644 +--- a/src/liblzma/lz/lz_decoder.c ++++ b/src/liblzma/lz/lz_decoder.c +@@ -276,6 +276,7 @@ lzma_lz_decoder_init(lzma_next_coder *next, const lzma_allocator *allocator, + + // Allocate and initialize the dictionary. + if (coder->dict.size != alloc_size) { ++ coder->dict.size = 0; + lzma_free(coder->dict.buf, allocator); + coder->dict.buf = lzma_alloc(alloc_size, allocator); + if (coder->dict.buf == NULL) diff --git a/package/xz/0007-liblzma-clean-up-after-a-filter-chain-initialization-error.patch b/package/xz/0007-liblzma-clean-up-after-a-filter-chain-initialization-error.patch new file mode 100644 index 0000000000..442d219780 --- /dev/null +++ b/package/xz/0007-liblzma-clean-up-after-a-filter-chain-initialization-error.patch @@ -0,0 +1,97 @@ +From: Lasse Collin +Date: Wed, 9 Sep 2026 14:14:40 +0300 +Subject: 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) +(cherry picked from commit e5e63d50eac1b4357a5a7a0abd3c5f99a5c47881) + +--- +Upstream: https://github.com/tukaani-project/xz/commit/0130b7524227d0bb9f405ecaf0af632a767fa735 +Signed-off-by: Titouan Christophe +--- + 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 78af65157..b2b049b5c 100644 +--- a/src/liblzma/common/alone_decoder.c ++++ b/src/liblzma/common/alone_decoder.c +@@ -151,8 +151,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 651a0ae71..30c50286d 100644 +--- a/src/liblzma/common/lzip_decoder.c ++++ b/src/liblzma/common/lzip_decoder.c +@@ -238,8 +238,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 882cb2c80..a7720cc2a 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.