libtiff: LZMADecode: zero-initialize (not-yet-written parts of) output buffer if failure, and handle repeated calls to decoding same...

From 0171fffd8b56b06be686f632138f23bc44d8c825 Mon Sep 17 00:00:00 2001
From: Even Rouault <[EMAIL REDACTED]>
Date: Sun, 26 May 2024 19:52:53 +0200
Subject: [PATCH] LZMADecode: zero-initialize (not-yet-written parts of) output
 buffer if failure, and handle repeated calls to decoding same tile/strip if
 previous failure occured

---
 libtiff/tif_lzma.c | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/libtiff/tif_lzma.c b/libtiff/tif_lzma.c
index 6fdc9280..1cc0f690 100644
--- a/libtiff/tif_lzma.c
+++ b/libtiff/tif_lzma.c
@@ -44,6 +44,8 @@
 typedef struct
 {
     TIFFPredictorState predict;
+    int read_error; /* whether a read error has occurred, and which should cause
+                       further reads in the same strip/tile to be aborted */
     lzma_stream stream;
     lzma_filter filters[LZMA_FILTERS_MAX + 1];
     lzma_options_delta opt_delta; /* delta filter options */
@@ -156,6 +158,9 @@ static int LZMAPreDecode(TIFF *tif, uint16_t s)
                       LZMAStrerror(ret));
         return 0;
     }
+
+    sp->read_error = 0;
+
     return 1;
 }
 
@@ -168,6 +173,16 @@ static int LZMADecode(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s)
     assert(sp != NULL);
     assert(sp->state == LSTATE_INIT_DECODE);
 
+    if (sp->read_error)
+    {
+        memset(op, 0, (size_t)occ);
+        TIFFErrorExtR(tif, module,
+                      "LZMADecode: Scanline %" PRIu32 " cannot be read due to "
+                      "previous error",
+                      tif->tif_row);
+        return 0;
+    }
+
     sp->stream.next_in = tif->tif_rawcp;
     sp->stream.avail_in = (size_t)tif->tif_rawcc;
 
@@ -175,6 +190,7 @@ static int LZMADecode(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s)
     sp->stream.avail_out = (size_t)occ;
     if ((tmsize_t)sp->stream.avail_out != occ)
     {
+        memset(op, 0, (size_t)occ);
         TIFFErrorExtR(tif, module,
                       "Liblzma cannot deal with buffers this size");
         return 0;
@@ -198,6 +214,8 @@ static int LZMADecode(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s)
                 lzma_stream_decoder(&sp->stream, lzma_memusage(&sp->stream), 0);
             if (r != LZMA_OK)
             {
+                sp->read_error = 1;
+                memset(op, 0, (size_t)occ);
                 TIFFErrorExtR(tif, module,
                               "Error initializing the stream decoder, %s",
                               LZMAStrerror(r));
@@ -217,6 +235,8 @@ static int LZMADecode(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s)
     } while (sp->stream.avail_out > 0);
     if (sp->stream.avail_out != 0)
     {
+        sp->read_error = 1;
+        memset(sp->stream.next_out, 0, sp->stream.avail_out);
         TIFFErrorExtR(tif, module,
                       "Not enough data at scanline %" PRIu32
                       " (short %" TIFF_SIZE_FORMAT " bytes)",