CVE-2022-38266 (published 2022-09-09T22:15Z)

An issue in the Leptonica linked library (v1.79.0) allows attackers to cause an arithmetic exception leading to a Denial of Service (DoS) via a crafted JPEG file.

CVSS v3 base score: 6.5, MEDIUM (CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H)

Weakness information:
cwe_id: CWE-369
cwe_name: Divide By Zero
description: The product divides a value by zero.
extended_description: This weakness typically occurs when an unexpected value is provided to the product, or if an error occurs that is not properly detected. It frequently occurs in calculations involving physical dimensions such as size, length, width, and height.
         

Fix information:
repo_url: https://github.com/DanBloomberg/leptonica
commit_details: repo_url: https://github.com/DanBloomberg/leptonica
author: Dan Bloomberg
author_date: 2020-10-28 17:37:30-07:00
msg: Issue 26393: morphapp_fuzzer: Divide-by-zero in blockconvLow
* Removed the code that allowed divide by zero for tiny pix
* Ditto for 4 other block convolution functions.
repository: repo_url: https://github.com/DanBloomberg/leptonica
repo_name: DanBloomberg/leptonica
description: Leptonica is an open source library containing software that is broadly useful for image processing and image analysis applications. The official github repository for Leptonica is: danbloomberg/leptonica.  See leptonica.org for more documentation.
repo_language: C
owner: DanBloomberg
file_changes: filename: convolve.c
change_type: ModificationType.MODIFY
diff: @@ -114,7 +114,7 @@ static void blocksumLow(l_uint32 *datad, l_int32 w, l_int32 h, l_int32 wpl,
 /*!
  * \brief   pixBlockconv()
  *
- * \param[in]    pix 8    or 32 bpp; or 2, 4 or 8 bpp with colormap
+ * \param[in]    pix      8 or 32 bpp; or 2, 4 or 8 bpp with colormap
  * \param[in]    wc, hc   half width/height of convolution kernel
  * \return  pixd, or NULL on error
  *
@@ -122,9 +122,10 @@ static void blocksumLow(l_uint32 *datad, l_int32 w, l_int32 h, l_int32 wpl,
  * Notes:
  *      (1) The full width and height of the convolution kernel
  *          are (2 * wc + 1) and (2 * hc + 1)
- *      (2) Returns a copy if both wc and hc are 0
+ *      (2) Returns a copy if either wc or hc are 0
  *      (3) Require that w >= 2 * wc + 1 and h >= 2 * hc + 1,
- *          where (w,h) are the dimensions of pixs.
+ *          where (w,h) are the dimensions of pixs.  Otherwise,
+ *          return a copy.
  * </pre>
  */
 PIX  *
@@ -139,17 +140,14 @@ PIX     *pixs, *pixd, *pixr, *pixrc, *pixg, *pixgc, *pixb, *pixbc;
 
     if (!pix)
         return (PIX *)ERROR_PTR("pix not defined", procName, NULL);
-    if (wc < 0) wc = 0;
-    if (hc < 0) hc = 0;
+    if (wc <= 0 || hc <= 0)
+        return pixCopy(NULL, pix);
     pixGetDimensions(pix, &w, &h, &d);
     if (w < 2 * wc + 1 || h < 2 * hc + 1) {
-        wc = L_MIN(wc, (w - 1) / 2);
-        hc = L_MIN(hc, (h - 1) / 2);
-        L_WARNING("kernel too large; reducing!\n", procName);
-        L_INFO("wc = %d, hc = %d\n", procName, wc, hc);
+        L_ERROR("kernel is too large: w = %d, wc = %d, h = %d, hc = %d\n",
+                procName, w, wc, h, hc);
+        return pixCopy(NULL, pix);  /* no-op */
     }
-    if (wc == 0 && hc == 0)   /* no-op */
-        return pixCopy(NULL, pix);
 
         /* Remove colormap if necessary */
     if ((d == 2 || d == 4 || d == 8) && pixGetColormap(pix)) {
@@ -205,9 +203,10 @@ PIX     *pixs, *pixd, *pixr, *pixrc, *pixg, *pixgc, *pixb, *pixbc;
  *          returning; otherwise, just use the input accum pix.
  *      (2) The full width and height of the convolution kernel
  *          are (2 * wc + 1) and (2 * hc + 1).
- *      (3) Returns a copy if both wc and hc are 0.
+ *      (3) Returns a copy if either wc or hc are 0
  *      (4) Require that w >= 2 * wc + 1 and h >= 2 * hc + 1,
- *          where (w,h) are the dimensions of pixs.
+ *          where (w,h) are the dimensions of pixs.  Otherwise,
+ *          return a copy.
  * </pre>
  */
 PIX *
@@ -227,13 +226,11 @@ PIX       *pixd, *pixt;
     pixGetDimensions(pixs, &w, &h, &d);
     if (d != 8)
         return (PIX *)ERROR_PTR("pixs not 8 bpp", procName, NULL);
-    if (wc < 0) wc = 0;
-    if (hc < 0) hc = 0;
-    if (wc == 0 && hc == 0)   /* no-op */
+    if (wc <= 0 || hc <= 0)   /* no-op */
         return pixCopy(NULL, pixs);
     if (w < 2 * wc + 1 || h < 2 * hc + 1) {
-        L_WARNING("kernel too large; returning a copy\n", procName);
-        L_INFO("w = %d, wc = %d, h = %d, hc = %d\n", procName, w, wc, h, hc);
+        L_ERROR("kernel is too large: w = %d, wc = %d, h = %d, hc = %d\n",
+                procName, w, wc, h, hc);
         return pixCopy(NULL, pixs);
     }
 
@@ -612,7 +609,7 @@ l_uint32  *lines, *lined, *linedp;
  *          are (2 * wc + 1) and (2 * hc + 1).
  *      (2) Require that w >= 2 * wc + 1 and h >= 2 * hc + 1,
  *          where (w,h) are the dimensions of pixs.
- *      (3) Returns a copy if both wc and hc are 0.
+ *      (3) Returns a copy if either wc or hc are 0.
  *      (3) Adds mirrored border to avoid treating the boundary pixels
  *          specially.  Note that we add wc + 1 pixels to the left
  *          and wc to the right.  The added width is 2 * wc + 1 pixels,
@@ -650,16 +647,13 @@ PIX       *pixsb, *pixacc, *pixd;
     pixGetDimensions(pixs, &w, &h, &d);
     if (d != 8)
         return (PIX *)ERROR_PTR("pixs not 8 bpp", procName, NULL);
-    if (wc < 0) wc = 0;
-    if (hc < 0) hc = 0;
+    if (wc <= 0 || hc <= 0)  /* no-op */
+        return pixCopy(NULL, pixs);
     if (w < 2 * wc + 1 || h < 2 * hc + 1) {
-        wc = L_MIN(wc, (w - 1) / 2);
-        hc = L_MIN(hc, (h - 1) / 2);
-        L_WARNING("kernel too large; reducing!\n", procName);
-        L_INFO("wc = %d, hc = %d\n", procName, wc, hc);
-    }
-    if (wc == 0 && hc == 0)   /* no-op */
+        L_ERROR("kernel is too large: w = %d, wc = %d, h = %d, hc = %d\n",
+                procName, w, wc, h, hc);
         return pixCopy(NULL, pixs);
+    }
 
     if ((pixsb = pixAddMirroredBorder(pixs, wc + 1, wc, hc + 1, hc)) == NULL)
         return (PIX *)ERROR_PTR("pixsb not made", procName, NULL);
@@ -707,9 +701,10 @@ PIX       *pixsb, *pixacc, *pixd;
  * Notes:
  *      (1) The full width and height of the convolution kernel
  *          are (2 * wc + 1) and (2 * hc + 1)
- *      (2) Returns a copy if both wc and hc are 0
+ *      (2) Returns a copy if either wc or hc are 0.
  *      (3) Require that w >= 2 * wc + 1 and h >= 2 * hc + 1,
- *          where (w,h) are the dimensions of pixs.
+ *          where (w,h) are the dimensions of pixs.  Otherwise,
+ *          return a copy.
  *      (4) For nx == ny == 1, this defaults to pixBlockconv(), which
  *          is typically about twice as fast, and gives nearly
  *          identical results as pixBlockconvGrayTile().
@@ -741,19 +736,16 @@ PIXTILING  *pt;
 
     if (!pix)
         return (PIX *)ERROR_PTR("pix not defined", procName, NULL);
-    if (wc < 0) wc = 0;
-    if (hc < 0) hc = 0;
-    pixGetDimensions(pix, &w, &h, &d);
-    if (w < 2 * wc + 3 || h < 2 * hc + 3) {
-        wc = L_MAX(0, L_MIN(wc, (w - 3) / 2));
-        hc = L_MAX(0, L_MIN(hc, (h - 3) / 2));
-        L_WARNING("kernel too large; reducing!\n", procName);
-        L_INFO("wc = %d, hc = %d\n", procName, wc, hc);
-    }
-    if (wc == 0 && hc == 0)   /* no-op */
+    if (wc <= 0 || hc <= 0)   /* no-op */
         return pixCopy(NULL, pix);
     if (nx <= 1 && ny <= 1)
         return pixBlockconv(pix, wc, hc);
+    pixGetDimensions(pix, &w, &h, &d);
+    if (w < 2 * wc + 3 || h < 2 * hc + 3) {
+        L_ERROR("kernel is too large: w = %d, wc = %d, h = %d, hc = %d\n",
+                procName, w, wc, h, hc);
+        return pixCopy(NULL, pix);
+    }
 
         /* Test to see if the tiles are too small.  The required
          * condition is that the tile dimensions must be at least
@@ -846,9 +838,10 @@ PIXTILING  *pt;
  *          left and right, and with (hc + 1) pixels on top and bottom.
  *          The returned pix has these stripped off; they are only used
  *          for computation.
- *      (3) Returns a copy if both wc and hc are 0
- *      (4) Require that w > 2 * wc + 1 and h > 2 * hc + 1,
- *          where (w,h) are the dimensions of pixs.
+ *      (3) Returns a copy if either wc or hc are 0.
+ *      (4) Require that w > 2 * wc + 3 and h > 2 * hc + 3,
+ *          where (w,h) are the dimensions of pixs.  Otherwise,
+ *          return a copy.
  * </pre>
  */
 PIX *
@@ -870,16 +863,13 @@ PIX       *pixt, *pixd;
     pixGetDimensions(pixs, &w, &h, &d);
     if (d != 8)
         return (PIX *)ERROR_PTR("pixs not 8 bpp", procName, NULL);
-    if (wc < 0) wc = 0;
-    if (hc < 0) hc = 0;
+    if (wc <= 0 || hc <= 0)  /* no-op */
+        return pixCopy(NULL, pixs);
     if (w < 2 * wc + 3 || h < 2 * hc + 3) {
-        wc = L_MAX(0, L_MIN(wc, (w - 3) / 2));
-        hc = L_MAX(0, L_MIN(hc, (h - 3) / 2));
-        L_WARNING("kernel too large; reducing!\n", procName);
-        L_INFO("wc = %d, hc = %d\n", procName, wc, hc);
-    }
-    if (wc == 0 && hc == 0)
+        L_ERROR("kernel is too large: w = %d, wc = %d, h = %d, hc = %d\n",
+                procName, w, wc, h, hc);
         return pixCopy(NULL, pixs);
+    }
     wd = w - 2 * wc;
     hd = h - 2 * hc;
 

programming_language: C