libtiff: Avoiding FPE (division by zero) for TIFFhowmany_32() and TIFFhowmany_64() macros by checking for denominator not zero before...

From 021a737bfa9884c0f7b98883cd5ce45279974fc8 Mon Sep 17 00:00:00 2001
From: Su_Laus <[EMAIL REDACTED]>
Date: Thu, 14 Mar 2024 21:37:46 +0100
Subject: [PATCH] Avoiding FPE (division by zero) for TIFFhowmany_32() and
 TIFFhowmany_64() macros by checking for denominator not zero before macros
 are executed. Fixes #628.

---
 libtiff/tif_dirread.c |  4 +++-
 libtiff/tif_jpeg.c    | 12 ++++++++++++
 libtiff/tif_read.c    | 28 +++++++++++++++++++++++-----
 libtiff/tif_strip.c   | 11 +++++++++--
 4 files changed, 47 insertions(+), 8 deletions(-)

diff --git a/libtiff/tif_dirread.c b/libtiff/tif_dirread.c
index f996e564..d4028e9f 100644
--- a/libtiff/tif_dirread.c
+++ b/libtiff/tif_dirread.c
@@ -7445,7 +7445,7 @@ static void ChopUpSingleUncompressedStrip(TIFF *tif)
     /*
      * never increase the number of rows per strip
      */
-    if (rowsperstrip >= td->td_rowsperstrip)
+    if (rowsperstrip >= td->td_rowsperstrip || rowsperstrip == 0)
         return;
     nstrips = TIFFhowmany_32(td->td_imagelength, rowsperstrip);
     if (nstrips == 0)
@@ -7541,6 +7541,8 @@ static void TryChopUpUncompressedBigTiff(TIFF *tif)
     stripbytes = rowblocksperstrip * rowblockbytes;
     assert(stripbytes <= 0x7FFFFFFFUL);
 
+    if (rowsperstrip == 0)
+        return;
     nstrips = TIFFhowmany_32(td->td_imagelength, rowsperstrip);
     if (nstrips == 0)
         return;
diff --git a/libtiff/tif_jpeg.c b/libtiff/tif_jpeg.c
index 39bd8130..d80bbc6f 100644
--- a/libtiff/tif_jpeg.c
+++ b/libtiff/tif_jpeg.c
@@ -1215,6 +1215,12 @@ int TIFFJPEGIsFullStripRequired(TIFF *tif)
          * For PC 2, scale down the expected strip/tile size
          * to match a downsampled component
          */
+        if (sp->h_sampling == 0 || sp->v_sampling == 0)
+        {
+            TIFFErrorExtR(tif, module,
+                          "JPEG horizontal or vertical sampling is zero");
+            return (0);
+        }
         segment_width = TIFFhowmany_32(segment_width, sp->h_sampling);
         segment_height = TIFFhowmany_32(segment_height, sp->v_sampling);
     }
@@ -2164,6 +2170,12 @@ static int JPEGPreEncode(TIFF *tif, uint16_t s)
         /* for PC 2, scale down the strip/tile size
          * to match a downsampled component
          */
+        if (sp->h_sampling == 0 || sp->v_sampling == 0)
+        {
+            TIFFErrorExtR(tif, module,
+                          "JPEG horizontal or vertical sampling is zero");
+            return (0);
+        }
         segment_width = TIFFhowmany_32(segment_width, sp->h_sampling);
         segment_height = TIFFhowmany_32(segment_height, sp->v_sampling);
     }
diff --git a/libtiff/tif_read.c b/libtiff/tif_read.c
index 437c1a05..df4bac69 100644
--- a/libtiff/tif_read.c
+++ b/libtiff/tif_read.c
@@ -495,6 +495,11 @@ static tmsize_t TIFFReadEncodedStripGetStripSize(TIFF *tif, uint32_t strip,
     rowsperstrip = td->td_rowsperstrip;
     if (rowsperstrip > td->td_imagelength)
         rowsperstrip = td->td_imagelength;
+    if (rowsperstrip == 0)
+    {
+        TIFFErrorExtR(tif, module, "rowsperstrip is zero");
+        return ((tmsize_t)(-1));
+    }
     stripsperplane =
         TIFFhowmany_32_maxuint_compat(td->td_imagelength, rowsperstrip);
     stripinplane = (strip % stripsperplane);
@@ -1449,6 +1454,11 @@ static int TIFFStartTile(TIFF *tif, uint32_t tile)
         tif->tif_flags |= TIFF_CODERSETUP;
     }
     tif->tif_curtile = tile;
+    if (td->td_tilewidth == 0)
+    {
+        TIFFErrorExtR(tif, module, "Zero tilewidth");
+        return 0;
+    }
     howmany32 = TIFFhowmany_32(td->td_imagewidth, td->td_tilewidth);
     if (howmany32 == 0)
     {
@@ -1558,14 +1568,22 @@ int TIFFReadFromUserBuffer(TIFF *tif, uint32_t strile, void *inbuf,
         uint32_t stripsperplane;
         if (rowsperstrip > td->td_imagelength)
             rowsperstrip = td->td_imagelength;
-        stripsperplane =
-            TIFFhowmany_32_maxuint_compat(td->td_imagelength, rowsperstrip);
-        if (!TIFFStartStrip(tif, strile) ||
-            !(*tif->tif_decodestrip)(tif, (uint8_t *)outbuf, outsize,
-                                     (uint16_t)(strile / stripsperplane)))
+        if (rowsperstrip == 0)
         {
+            TIFFErrorExtR(tif, module, "rowsperstrip is zero");
             ret = 0;
         }
+        else
+        {
+            stripsperplane =
+                TIFFhowmany_32_maxuint_compat(td->td_imagelength, rowsperstrip);
+            if (!TIFFStartStrip(tif, strile) ||
+                !(*tif->tif_decodestrip)(tif, (uint8_t *)outbuf, outsize,
+                                         (uint16_t)(strile / stripsperplane)))
+            {
+                ret = 0;
+            }
+        }
     }
     if (ret)
     {
diff --git a/libtiff/tif_strip.c b/libtiff/tif_strip.c
index 820a2544..ee31892a 100644
--- a/libtiff/tif_strip.c
+++ b/libtiff/tif_strip.c
@@ -61,6 +61,11 @@ uint32_t TIFFNumberOfStrips(TIFF *tif)
     TIFFDirectory *td = &tif->tif_dir;
     uint32_t nstrips;
 
+    if (td->td_rowsperstrip == 0)
+    {
+        TIFFWarningExtR(tif, "TIFFNumberOfStrips", "RowsPerStrip is zero");
+        return 0;
+    }
     nstrips = (td->td_rowsperstrip == (uint32_t)-1
                    ? 1
                    : TIFFhowmany_32(td->td_imagelength, td->td_rowsperstrip));
@@ -107,7 +112,8 @@ uint64_t TIFFVStripSize64(TIFF *tif, uint32_t nrows)
         if ((ycbcrsubsampling[0] != 1 && ycbcrsubsampling[0] != 2 &&
              ycbcrsubsampling[0] != 4) ||
             (ycbcrsubsampling[1] != 1 && ycbcrsubsampling[1] != 2 &&
-             ycbcrsubsampling[1] != 4))
+             ycbcrsubsampling[1] != 4) ||
+            (ycbcrsubsampling[0] == 0 || ycbcrsubsampling[1] == 0))
         {
             TIFFErrorExtR(tif, module, "Invalid YCbCr subsampling (%dx%d)",
                           ycbcrsubsampling[0], ycbcrsubsampling[1]);
@@ -267,7 +273,8 @@ uint64_t TIFFScanlineSize64(TIFF *tif)
             if (((ycbcrsubsampling[0] != 1) && (ycbcrsubsampling[0] != 2) &&
                  (ycbcrsubsampling[0] != 4)) ||
                 ((ycbcrsubsampling[1] != 1) && (ycbcrsubsampling[1] != 2) &&
-                 (ycbcrsubsampling[1] != 4)))
+                 (ycbcrsubsampling[1] != 4)) ||
+                ((ycbcrsubsampling[0] == 0) || (ycbcrsubsampling[1] == 0)))
             {
                 TIFFErrorExtR(tif, module, "Invalid YCbCr subsampling");
                 return 0;