CVE-2022-27114: Integer Overflow or Wraparound (CWE-190)
value: There is a vulnerability in htmldoc 1.9.16. In image_load_jpeg function image.cxx when it calls malloc,'img->width' and 'img->height' they are large enough to cause an integer overflow. So, the malloc function may return a heap blosmaller than the expected size, and it will cause a buffer overflow/Address boundary error in the jpeg_read_scanlines function.
CWE description: The product performs a calculation that can
         produce an integer overflow or wraparound when the logic
         assumes that the resulting value will always be larger than
         the original value. This occurs when an integer value is
         incremented to a value that is too large to store in the
         associated representation. When this occurs, the value may
         become a very small or negative number.
CVSS v3 base score: 5.5
Published: 2022-05-09T17:15Z
Repository: https://github.com/michaelrsweet/htmldoc
Language: Markdown
Files changed: CHANGES.md, htmldoc/image.cxx
Commit date: 2022-03-10 15:29:36 -0500
Commit message: Fix a potential integer overflow bug in the JPEG and PNG loaders (Issue #471)

All images are now limited to 4GiB of memory usage (37837x37837 pixels).

Diff: diff --git a/CHANGES.md b/CHANGES.md
index 445a702d1..29e4dda29 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -1,9 +1,10 @@
 # Changes in HTMLDOC v1.9.16
 
-- Updated the GUI interface for current display fonts.
+- Fixed a potential image overflow bug with JPEG and PNG images (Issue #471)
 - Fixed some minor Coverity warnings.
+- Updated the GUI interface for current display fonts.
 
 
 # Changes in HTMLDOC v1.9.15
 
 - Fixed a potential heap overflow bug with GIF images (Issue #461)
diff --git a/htmldoc/image.cxx b/htmldoc/image.cxx
index 8aeccced7..9b4d11de4 100644
--- a/htmldoc/image.cxx
+++ b/htmldoc/image.cxx
@@ -24,10 +24,17 @@ extern "C" {		/* Workaround for JPEG header problems... */
 #ifdef HAVE_LIBPNG
 #  include <png.h>	/* Portable Network Graphics (PNG) definitions */
 #endif // HAVE_LIBPNG
 
 
+/*
+ * Limits...
+ */
+
+#define IMAGE_MAX_DIM	37837		// Maximum dimension - sqrt(4GiB / 3)
+
+
 /*
  * GIF definitions...
  */
 
 #define GIF_INTERLACE	0x40
@@ -924,11 +931,11 @@ image_load_bmp(image_t *img,	/* I - Image to load into */
   read_long(fp);
   read_long(fp);
   colors_used      = (int)read_dword(fp);
   read_dword(fp);
 
-  if (img->width <= 0 || img->width > 8192 || img->height <= 0 || img->height > 8192 || info_size < 0)
+  if (img->width <= 0 || img->width > IMAGE_MAX_DIM || img->height <= 0 || img->height > IMAGE_MAX_DIM || info_size < 0)
     return (-1);
 
   if (info_size > 40)
   {
     for (info_size -= 40; info_size > 0; info_size --)
@@ -1276,11 +1283,11 @@ image_load_gif(image_t *img,	/* I - Image pointer */
 
   img->width  = (buf[7] << 8) | buf[6];
   img->height = (buf[9] << 8) | buf[8];
   ncolors     = 2 << (buf[10] & 0x07);
 
-  if (img->width <= 0 || img->width > 32767 || img->height <= 0 || img->height > 32767)
+  if (img->width <= 0 || img->width > IMAGE_MAX_DIM || img->height <= 0 || img->height > IMAGE_MAX_DIM)
     return (-1);
 
   // If we are writing an encrypted PDF file, bump the use count so we create
   // an image object (Acrobat 6 bug workaround)
   if (Encryption)
@@ -1324,11 +1331,11 @@ image_load_gif(image_t *img,	/* I - Image pointer */
 
           img->width  = (buf[5] << 8) | buf[4];
           img->height = (buf[7] << 8) | buf[6];
           img->depth  = gray ? 1 : 3;
 
-	  if (img->width <= 0 || img->width > 32767 || img->height <= 0 || img->height > 32767)
+	  if (img->width <= 0 || img->width > IMAGE_MAX_DIM || img->height <= 0 || img->height > IMAGE_MAX_DIM)
 	    return (-1);
 
           if (transparent >= 0)
           {
            /*
@@ -1441,10 +1448,16 @@ JSAMPROW			row;		/* Sample row pointer */
 
   img->width  = (int)cinfo.output_width;
   img->height = (int)cinfo.output_height;
   img->depth  = (int)cinfo.output_components;
 
+  if (img->width <= 0 || img->width > IMAGE_MAX_DIM || img->height <= 0 || img->height > IMAGE_MAX_DIM)
+  {
+    jpeg_destroy_decompress(&cinfo);
+    return (-1);
+  }
+
   if (!load_data)
   {
     jpeg_destroy_decompress(&cinfo);
     return (0);
   }
@@ -1596,10 +1609,16 @@ image_load_png(image_t *img,	/* I - Image pointer */
   }
 
   img->width  = (int)png_get_image_width(pp, info);
   img->height = (int)png_get_image_height(pp, info);
 
+  if (img->width <= 0 || img->width > IMAGE_MAX_DIM || img->height <= 0 || img->height > IMAGE_MAX_DIM)
+  {
+    png_destroy_read_struct(&pp, &info, NULL);
+    return (-1);
+  }
+
   if (color_type & PNG_COLOR_MASK_ALPHA)
   {
     if ((PSLevel == 0 && PDFVersion >= 14) || PSLevel == 3)
       image_need_mask(img, 8);
     else if (PSLevel == 0 && PDFVersion == 13)

Vulnerable code: - Updated the GUI interface for current display fonts.
  if (img->width <= 0 || img->width > 8192 || img->height <= 0 || img->height > 8192 || info_size < 0)
  if (img->width <= 0 || img->width > 32767 || img->height <= 0 || img->height > 32767)
	  if (img->width <= 0 || img->width > 32767 || img->height <= 0 || img->height > 32767)
Fixed code: - Fixed a potential image overflow bug with JPEG and PNG images (Issue #471)
- Updated the GUI interface for current display fonts.
/*
 * Limits...
 */

#define IMAGE_MAX_DIM	37837		// Maximum dimension - sqrt(4GiB / 3)


  if (img->width <= 0 || img->width > IMAGE_MAX_DIM || img->height <= 0 || img->height > IMAGE_MAX_DIM || info_size < 0)
  if (img->width <= 0 || img->width > IMAGE_MAX_DIM || img->height <= 0 || img->height > IMAGE_MAX_DIM)
	  if (img->width <= 0 || img->width > IMAGE_MAX_DIM || img->height <= 0 || img->height > IMAGE_MAX_DIM)
  if (img->width <= 0 || img->width > IMAGE_MAX_DIM || img->height <= 0 || img->height > IMAGE_MAX_DIM)
  {
    jpeg_destroy_decompress(&cinfo);
    return (-1);
  }

  if (img->width <= 0 || img->width > IMAGE_MAX_DIM || img->height <= 0 || img->height > IMAGE_MAX_DIM)
  {
    png_destroy_read_struct(&pp, &info, NULL);
    return (-1);
  }