Commit 102ea0ed for xz
commit 102ea0ed1290869f3af53009f98def030c6b6cd0
Author: xordanblu <jordygarciamorales@gmail.com>
Date: Sat Aug 15 19:50:05 2026 +0300
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 <lasse.collin@tukaani.org>
Fixes: https://github.com/tukaani-project/xz/pull/240
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);