CVE-2021-20224: Integer Overflow or Wraparound (CWE-190)
value: An integer overflow issue was discovered in ImageMagick's ExportIndexQuantum() function in MagickCore/quantum-export.c. Function calls to GetPixelIndex() could result in values outside the range of representable for the 'unsigned char'. When ImageMagick processes a crafted pdf file, this could lead to an undefined behaviour or a crash.
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-08-25T20:15Z
Repository: https://github.com/ImageMagick/ImageMagick6
Language: C
Files changed: magick/quantum-export.c
Commit date: 2021-01-06 18:34:31 -0500
Commit message: https://github.com/ImageMagick/ImageMagick/pull/3083

Diff: diff --git a/magick/quantum-export.c b/magick/quantum-export.c
index 7a13973d8e9..dc85b97af8b 100644
--- a/magick/quantum-export.c
+++ b/magick/quantum-export.c
@@ -2514,34 +2514,34 @@ static void ExportIndexQuantum(const Image *image,QuantumInfo *quantum_info,
       unsigned char
         pixel;
 
       for (x=((ssize_t) number_pixels-7); x > 0; x-=8)
       {
-        pixel=(unsigned char) *indexes++;
+        pixel=(unsigned char) ((ssize_t) *indexes++);
         *q=((pixel & 0x01) << 7);
-        pixel=(unsigned char) *indexes++;
+        pixel=(unsigned char) ((ssize_t) *indexes++);
         *q|=((pixel & 0x01) << 6);
-        pixel=(unsigned char) *indexes++;
+        pixel=(unsigned char) ((ssize_t) *indexes++);
         *q|=((pixel & 0x01) << 5);
-        pixel=(unsigned char) *indexes++;
+        pixel=(unsigned char) ((ssize_t) *indexes++);
         *q|=((pixel & 0x01) << 4);
-        pixel=(unsigned char) *indexes++;
+        pixel=(unsigned char) ((ssize_t) *indexes++);
         *q|=((pixel & 0x01) << 3);
-        pixel=(unsigned char) *indexes++;
+        pixel=(unsigned char) ((ssize_t) *indexes++);
         *q|=((pixel & 0x01) << 2);
-        pixel=(unsigned char) *indexes++;
+        pixel=(unsigned char) ((ssize_t) *indexes++);
         *q|=((pixel & 0x01) << 1);
-        pixel=(unsigned char) *indexes++;
+        pixel=(unsigned char) ((ssize_t) *indexes++);
         *q|=((pixel & 0x01) << 0);
         q++;
       }
       if ((number_pixels % 8) != 0)
         {
           *q='\0';
           for (bit=7; bit >= (ssize_t) (8-(number_pixels % 8)); bit--)
           {
-            pixel=(unsigned char) *indexes++;
+            pixel=(unsigned char) ((ssize_t) *indexes++);
             *q|=((pixel & 0x01) << (unsigned char) bit);
           }
           q++;
         }
       break;
@@ -2551,19 +2551,19 @@ static void ExportIndexQuantum(const Image *image,QuantumInfo *quantum_info,
       unsigned char
         pixel;
 
       for (x=0; x < (ssize_t) (number_pixels-1) ; x+=2)
       {
-        pixel=(unsigned char) *indexes++;
+        pixel=(unsigned char) ((ssize_t) *indexes++);
         *q=((pixel & 0xf) << 4);
-        pixel=(unsigned char) *indexes++;
+        pixel=(unsigned char) ((ssize_t) *indexes++);
         *q|=((pixel & 0xf) << 0);
         q++;
       }
       if ((number_pixels % 2) != 0)
         {
-          pixel=(unsigned char) *indexes++;
+          pixel=(unsigned char) ((ssize_t) *indexes++);
           *q=((pixel & 0xf) << 4);
           q++;
         }
       break;
     }
@@ -2667,29 +2667,29 @@ static void ExportIndexAlphaQuantum(const Image *image,
       unsigned char
         pixel;
 
       for (x=((ssize_t) number_pixels-3); x > 0; x-=4)
       {
-        pixel=(unsigned char) *indexes++;
+        pixel=(unsigned char) ((ssize_t) *indexes++);
         *q=((pixel & 0x01) << 7);
         pixel=(unsigned char) (GetPixelOpacity(p) == (Quantum)
           TransparentOpacity ? 1 : 0);
         *q|=((pixel & 0x01) << 6);
         p++;
-        pixel=(unsigned char) *indexes++;
+        pixel=(unsigned char) ((ssize_t) *indexes++);
         *q|=((pixel & 0x01) << 5);
         pixel=(unsigned char) (GetPixelOpacity(p) == (Quantum)
           TransparentOpacity ? 1 : 0);
         *q|=((pixel & 0x01) << 4);
         p++;
-        pixel=(unsigned char) *indexes++;
+        pixel=(unsigned char) ((ssize_t) *indexes++);
         *q|=((pixel & 0x01) << 3);
         pixel=(unsigned char) (GetPixelOpacity(p) == (Quantum)
           TransparentOpacity ? 1 : 0);
         *q|=((pixel & 0x01) << 2);
         p++;
-        pixel=(unsigned char) *indexes++;
+        pixel=(unsigned char) ((ssize_t) *indexes++);
         *q|=((pixel & 0x01) << 1);
         pixel=(unsigned char) (GetPixelOpacity(p) == (Quantum)
           TransparentOpacity ? 1 : 0);
         *q|=((pixel & 0x01) << 0);
         p++;
@@ -2698,11 +2698,11 @@ static void ExportIndexAlphaQuantum(const Image *image,
       if ((number_pixels % 4) != 0)
         {
           *q='\0';
           for (bit=3; bit >= (ssize_t) (4-(number_pixels % 4)); bit-=2)
           {
-            pixel=(unsigned char) *indexes++;
+            pixel=(unsigned char) ((ssize_t) *indexes++);
             *q|=((pixel & 0x01) << (unsigned char) (bit+4));
             pixel=(unsigned char) (GetPixelOpacity(p) == (Quantum)
               TransparentOpacity ? 1 : 0);
             *q|=((pixel & 0x01) << (unsigned char) (bit+4-1));
             p++;
@@ -2716,14 +2716,14 @@ static void ExportIndexAlphaQuantum(const Image *image,
       unsigned char
         pixel;
 
       for (x=0; x < (ssize_t) number_pixels ; x++)
       {
-        pixel=(unsigned char) *indexes++;
+        pixel=(unsigned char) ((ssize_t) *indexes++);
         *q=((pixel & 0xf) << 4);
-        pixel=(unsigned char) (16*QuantumScale*((Quantum) (QuantumRange-
-          GetPixelOpacity(p)))+0.5);
+        pixel=(unsigned char) ((ssize_t) (16*QuantumScale*((Quantum)
+          (QuantumRange-GetPixelOpacity(p)))+0.5));
         *q|=((pixel & 0xf) << 0);
         p++;
         q++;
       }
       break;
@@ -2750,21 +2750,23 @@ static void ExportIndexAlphaQuantum(const Image *image,
 
       if (quantum_info->format == FloatingPointQuantumFormat)
         {
           for (x=0; x < (ssize_t) number_pixels; x++)
           {
-            q=PopShortPixel(quantum_info->endian,(unsigned short) GetPixelIndex(indexes+x),q);
+            q=PopShortPixel(quantum_info->endian,(unsigned short)
+              ((ssize_t) GetPixelIndex(indexes+x)),q);
             pixel=SinglePrecisionToHalf(QuantumScale*GetPixelAlpha(p));
             q=PopShortPixel(quantum_info->endian,pixel,q);
             p++;
             q+=quantum_info->pad;
           }
           break;
         }
       for (x=0; x < (ssize_t) number_pixels; x++)
       {
-        q=PopShortPixel(quantum_info->endian,(unsigned short) GetPixelIndex(indexes+x),q);
+        q=PopShortPixel(quantum_info->endian,(unsigned short)
+          ((ssize_t) GetPixelIndex(indexes+x)),q);
         pixel=ScaleQuantumToShort((Quantum) (QuantumRange-GetPixelOpacity(p)));
         q=PopShortPixel(quantum_info->endian,pixel,q);
         p++;
         q+=quantum_info->pad;
       }
@@ -2790,11 +2792,12 @@ static void ExportIndexAlphaQuantum(const Image *image,
           }
           break;
         }
       for (x=0; x < (ssize_t) number_pixels; x++)
       {
-        q=PopLongPixel(quantum_info->endian,(unsigned int) GetPixelIndex(indexes+x),q);
+        q=PopLongPixel(quantum_info->endian,(unsigned int)
+          GetPixelIndex(indexes+x),q);
         pixel=ScaleQuantumToLong((Quantum) (QuantumRange-GetPixelOpacity(p)));
         q=PopLongPixel(quantum_info->endian,pixel,q);
         p++;
         q+=quantum_info->pad;
       }
@@ -2825,14 +2828,13 @@ static void ExportIndexAlphaQuantum(const Image *image,
         range;
 
       range=GetQuantumRange(quantum_info->depth);
       for (x=0; x < (ssize_t) number_pixels; x++)
       {
-        q=PopQuantumPixel(quantum_info,
-          GetPixelIndex(indexes+x),q);
-        q=PopQuantumPixel(quantum_info,
-          ScaleQuantumToAny((Quantum) (GetPixelAlpha(p)),range),q);
+        q=PopQuantumPixel(quantum_info,GetPixelIndex(indexes+x),q);
+        q=PopQuantumPixel(quantum_info,ScaleQuantumToAny((Quantum)
+          (GetPixelAlpha(p)),range),q);
         p++;
         q+=quantum_info->pad;
       }
       break;
     }
@@ -3033,12 +3035,12 @@ static void ExportRedQuantum(QuantumInfo *quantum_info,
     default:
     {
       range=GetQuantumRange(quantum_info->depth);
       for (x=0; x < (ssize_t) number_pixels; x++)
       {
-        q=PopQuantumPixel(quantum_info,
-          ScaleQuantumToAny(GetPixelRed(p),range),q);
+        q=PopQuantumPixel(quantum_info,ScaleQuantumToAny(GetPixelRed(p),range),
+          q);
         p++;
         q+=quantum_info->pad;
       }
       break;
     }
@@ -3148,11 +3150,12 @@ static void ExportRGBQuantum(QuantumInfo *quantum_info,
                 pixel=(unsigned int) ScaleQuantumToAny(GetPixelBlue(p),range);
                 p++;
                 break;
               }
             }
-            q=PopShortPixel(quantum_info->endian,(unsigned short) (pixel << 4),q);
+            q=PopShortPixel(quantum_info->endian,(unsigned short) (pixel << 4),
+              q);
             switch ((x+1) % 3)
             {
               default:
               case 0:
               {
@@ -3169,11 +3172,12 @@ static void ExportRGBQuantum(QuantumInfo *quantum_info,
                 pixel=(unsigned int) ScaleQuantumToAny(GetPixelBlue(p),range);
                 p++;
                 break;
               }
             }
-            q=PopShortPixel(quantum_info->endian,(unsigned short) (pixel << 4),q);
+            q=PopShortPixel(quantum_info->endian,(unsigned short) (pixel << 4),
+              q);
             q+=quantum_info->pad;
           }
           for (bit=0; bit < (ssize_t) (3*number_pixels % 2); bit++)
           {
             switch ((x+bit) % 3)
@@ -3194,11 +3198,12 @@ static void ExportRGBQuantum(QuantumInfo *quantum_info,
                 pixel=(unsigned int) ScaleQuantumToAny(GetPixelBlue(p),range);
                 p++;
                 break;
               }
             }
-            q=PopShortPixel(quantum_info->endian,(unsigned short) (pixel << 4),q);
+            q=PopShortPixel(quantum_info->endian,(unsigned short) (pixel << 4),
+              q);
             q+=quantum_info->pad;
           }
           if (bit != 0)
             p++;
           break;

Vulnerable code:         pixel=(unsigned char) *indexes++;
        pixel=(unsigned char) *indexes++;
        pixel=(unsigned char) *indexes++;
        pixel=(unsigned char) *indexes++;
        pixel=(unsigned char) *indexes++;
        pixel=(unsigned char) *indexes++;
        pixel=(unsigned char) *indexes++;
        pixel=(unsigned char) *indexes++;
            pixel=(unsigned char) *indexes++;
        pixel=(unsigned char) *indexes++;
        pixel=(unsigned char) *indexes++;
          pixel=(unsigned char) *indexes++;
        pixel=(unsigned char) *indexes++;
        pixel=(unsigned char) *indexes++;
        pixel=(unsigned char) *indexes++;
        pixel=(unsigned char) *indexes++;
            pixel=(unsigned char) *indexes++;
        pixel=(unsigned char) *indexes++;
        pixel=(unsigned char) (16*QuantumScale*((Quantum) (QuantumRange-
          GetPixelOpacity(p)))+0.5);
            q=PopShortPixel(quantum_info->endian,(unsigned short) GetPixelIndex(indexes+x),q);
        q=PopShortPixel(quantum_info->endian,(unsigned short) GetPixelIndex(indexes+x),q);
        q=PopLongPixel(quantum_info->endian,(unsigned int) GetPixelIndex(indexes+x),q);
        q=PopQuantumPixel(quantum_info,
          GetPixelIndex(indexes+x),q);
        q=PopQuantumPixel(quantum_info,
          ScaleQuantumToAny((Quantum) (GetPixelAlpha(p)),range),q);
        q=PopQuantumPixel(quantum_info,
          ScaleQuantumToAny(GetPixelRed(p),range),q);
            q=PopShortPixel(quantum_info->endian,(unsigned short) (pixel << 4),q);
            q=PopShortPixel(quantum_info->endian,(unsigned short) (pixel << 4),q);
            q=PopShortPixel(quantum_info->endian,(unsigned short) (pixel << 4),q);
Fixed code:         pixel=(unsigned char) ((ssize_t) *indexes++);
        pixel=(unsigned char) ((ssize_t) *indexes++);
        pixel=(unsigned char) ((ssize_t) *indexes++);
        pixel=(unsigned char) ((ssize_t) *indexes++);
        pixel=(unsigned char) ((ssize_t) *indexes++);
        pixel=(unsigned char) ((ssize_t) *indexes++);
        pixel=(unsigned char) ((ssize_t) *indexes++);
        pixel=(unsigned char) ((ssize_t) *indexes++);
            pixel=(unsigned char) ((ssize_t) *indexes++);
        pixel=(unsigned char) ((ssize_t) *indexes++);
        pixel=(unsigned char) ((ssize_t) *indexes++);
          pixel=(unsigned char) ((ssize_t) *indexes++);
        pixel=(unsigned char) ((ssize_t) *indexes++);
        pixel=(unsigned char) ((ssize_t) *indexes++);
        pixel=(unsigned char) ((ssize_t) *indexes++);
        pixel=(unsigned char) ((ssize_t) *indexes++);
            pixel=(unsigned char) ((ssize_t) *indexes++);
        pixel=(unsigned char) ((ssize_t) *indexes++);
        pixel=(unsigned char) ((ssize_t) (16*QuantumScale*((Quantum)
          (QuantumRange-GetPixelOpacity(p)))+0.5));
            q=PopShortPixel(quantum_info->endian,(unsigned short)
              ((ssize_t) GetPixelIndex(indexes+x)),q);
        q=PopShortPixel(quantum_info->endian,(unsigned short)
          ((ssize_t) GetPixelIndex(indexes+x)),q);
        q=PopLongPixel(quantum_info->endian,(unsigned int)
          GetPixelIndex(indexes+x),q);
        q=PopQuantumPixel(quantum_info,GetPixelIndex(indexes+x),q);
        q=PopQuantumPixel(quantum_info,ScaleQuantumToAny((Quantum)
          (GetPixelAlpha(p)),range),q);
        q=PopQuantumPixel(quantum_info,ScaleQuantumToAny(GetPixelRed(p),range),
          q);
            q=PopShortPixel(quantum_info->endian,(unsigned short) (pixel << 4),
              q);
            q=PopShortPixel(quantum_info->endian,(unsigned short) (pixel << 4),
              q);
            q=PopShortPixel(quantum_info->endian,(unsigned short) (pixel << 4),
              q);