From 102ea0ed1290869f3af53009f98def030c6b6cd0 Mon Sep 17 00:00:00 2001 From: xordanblu Date: Sat, 15 Aug 2026 19:50:05 +0300 Subject: [PATCH] xz: Make it an error if the totals in xz --list exceed UINT64_MAX If at least three files are passed to xz --list, the totals might exceed the range of uint64_t. Previously wrong totals were displayed in this case. Now an error is shown as soon as an overflow would occur, and the remaining files aren't processed. In most other cases an error doesn't prevent xz from processing the remaining files, but in this case it feels OK because (1) the error should be very rare, (2) it keeps the code slightly simpler, and (3) with xz --robot --list the caller will likely ignore the output anyway when xz exits with a non-zero status. Co-authored-by: Lasse Collin Fixes: https://github.com/tukaani-project/xz/pull/240 --- src/xz/list.c | 34 +++++++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/src/xz/list.c b/src/xz/list.c index 210f23ad..56744829 100644 --- a/src/xz/list.c +++ b/src/xz/list.c @@ -1142,12 +1142,36 @@ print_info_robot(xz_file_info *xfi, file_pair *pair) static void update_totals(const xz_file_info *xfi) { - // TODO: Integer overflow checks + const uint64_t streams = lzma_index_stream_count(xfi->idx); + const uint64_t blocks = lzma_index_block_count(xfi->idx); + const uint64_t compressed_size = lzma_index_file_size(xfi->idx); + const uint64_t uncompressed_size + = lzma_index_uncompressed_size(xfi->idx); + + // Of these, totals.uncompressed_size is the most likely to overflow + // because it doesn't require a huge file. Even that is likely to + // happen only with invalid/crafted files. + // + // For simplicity, the error message refers to file sizes even though + // we are checking other things too. + if (totals.files == UINT64_MAX + || UINT64_MAX - totals.streams < streams + || UINT64_MAX - totals.blocks < blocks + || UINT64_MAX - totals.compressed_size + < compressed_size + || UINT64_MAX - totals.uncompressed_size + < uncompressed_size + || UINT64_MAX - totals.stream_padding + < xfi->stream_padding) { + message_fatal(_("Error: The total compressed or uncompressed " + "size of the files is too large")); + } + ++totals.files; - totals.streams += lzma_index_stream_count(xfi->idx); - totals.blocks += lzma_index_block_count(xfi->idx); - totals.compressed_size += lzma_index_file_size(xfi->idx); - totals.uncompressed_size += lzma_index_uncompressed_size(xfi->idx); + totals.streams += streams; + totals.blocks += blocks; + totals.compressed_size += compressed_size; + totals.uncompressed_size += uncompressed_size; totals.stream_padding += xfi->stream_padding; totals.checks |= lzma_index_checks(xfi->idx);