CVE-2022-31620 (published 2022-05-25T21:15Z)

In libjpeg before 1.64, BitStream<false>::Get in bitstream.hpp has an assertion failure that may cause denial of service. This is related to out-of-bounds array access during arithmetically coded lossless scan or arithmetically coded sequential scan.

Severity: MEDIUM
CVSS v2 base score: 4.3 (AV:N/AC:M/Au:N/C:N/I:N/A:P)
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-617
cwe_name: Reachable Assertion
description: The product contains an assert() or similar statement that can be triggered by an attacker, which leads to an application exit or other behavior that is more severe than necessary.
extended_description: 
            While assertion is good for catching logic errors and reducing the chances of reaching more serious vulnerability conditions, it can still lead to a denial of service.
            For example, if a server handles multiple simultaneous connections, and an assert() occurs in one single connection that causes all other connections to be dropped, this is a reachable assertion that leads to a denial of service.
         
         

Fix information:
repo_url: https://github.com/thorfdbg/libjpeg
commit_details: repo_url: https://github.com/thorfdbg/libjpeg
author: Thomas Richter
author_date: 2022-05-23 07:57:40+02:00
msg: Added out-of-bounds checks for lossless symbol decoding and AC context
indices. Worked around some gcc warnings. Bumped to 1.64.
repository: repo_url: https://github.com/thorfdbg/libjpeg
repo_name: thorfdbg/libjpeg
description: A complete implementation of 10918-1 (JPEG) coming from jpeg.org (the ISO group) with extensions for HDR, lossless and alpha channel coding standardized as ISO/IEC 18477 (JPEG XT).
repo_language: C++
owner: thorfdbg
file_changes: filename: README
change_type: ModificationType.MODIFY
diff: @@ -452,6 +452,17 @@ file for the alpha channel with the "-al" command line option.
 
 --------------------------------------------------------------------------
 
+Release 1.64:
+
+The lossless scan, the arithmetically coded lossless scan and the
+arithmetically coded sequential scan could run into cases where an
+out-of-bounds symbol triggered and out-of-bounds array access and could
+have crashed the decoder. The code is now more carefully changing the
+validity of the symbols and aborts with an error if it finds illegal
+codes.
+
+--------------------------------------------------------------------------
+
 For license conditions, please check the file README.license in this
 directory.
 

programming_language: Markdown
filename: README.history
change_type: ModificationType.MODIFY
diff: @@ -555,3 +555,14 @@ now in this case simply disregarded. Note that you can define the output
 file for the alpha channel with the "-al" command line option.
 
 --------------------------------------------------------------------------
+
+Release 1.64:
+
+The lossless scan, the arithmetically coded lossless scan and the
+arithmetically coded sequential scan could run into cases where an
+out-of-bounds symbol triggered and out-of-bounds array access and could
+have crashed the decoder. The code is now more carefully changing the
+validity of the symbols and aborts with an error if it finds illegal
+codes.
+
+--------------------------------------------------------------------------

programming_language: Markdown
filename: aclosslessscan.cpp
change_type: ModificationType.MODIFY
diff: @@ -42,7 +42,7 @@
 **
 ** Represents the scan including the scan header.
 **
-** $Id: aclosslessscan.cpp,v 1.42 2020/08/31 07:50:43 thor Exp $
+** $Id: aclosslessscan.cpp,v 1.43 2022/05/23 05:56:51 thor Exp $
 **
 */
 
@@ -359,7 +359,9 @@ void ACLosslessScan::ParseMCU(struct Line **prev,struct Line **top)
             //
             while(m_Coder.Get(mset.X[i])) {
               m <<= 1;
-              i++;
+              if (++i >= QMContextSet::MagnitudeSet::MagnitudeContexts)
+                JPG_THROW(MALFORMED_STREAM,"ACLosslessScan::ParseMCU",
+                          "received an out-of-bounds signal while parsing an AC-coded lossless symbol");
             }
             //
             m >>= 1;

programming_language: C++
filename: aclosslessscan.hpp
change_type: ModificationType.MODIFY
diff: @@ -43,7 +43,7 @@
 ** Represents the lossless scan - lines are coded directly with predictive
 ** coding, though here residuals are encoded with the arithmetic encoder.
 **
-** $Id: aclosslessscan.hpp,v 1.28 2014/11/16 15:49:58 thor Exp $
+** $Id: aclosslessscan.hpp,v 1.29 2022/05/23 05:56:51 thor Exp $
 **
 */
 
@@ -111,12 +111,16 @@ class ACLosslessScan : public PredictiveScan {
     //
     // The Magnitude/refinement coding contexts.
     struct MagnitudeSet {
-      QMContext X[15];
-      QMContext M[15];
+      enum {
+        MagnitudeContexts = 15
+      };
+      //
+      QMContext X[MagnitudeContexts];
+      QMContext M[MagnitudeContexts];
       //
       void Init(void)
       {
-        for(int i = 0;i < 15;i++) {
+        for(int i = 0;i < MagnitudeContexts;i++) {
           X[i].Init();
           M[i].Init();
         }

programming_language: C++
filename: acsequentialscan.cpp
change_type: ModificationType.MODIFY
diff: @@ -42,7 +42,7 @@
 **
 ** Represents the scan including the scan header.
 **
-** $Id: acsequentialscan.cpp,v 1.51 2016/10/28 13:58:53 thor Exp $
+** $Id: acsequentialscan.cpp,v 1.52 2022/05/23 05:56:51 thor Exp $
 **
 */
 
@@ -582,8 +582,7 @@ void ACSequentialScan::DecodeBlock(LONG *block,
         
         while(m_Coder.Get(m_Context[dc].DCMagnitude.X[i])) {
           m <<= 1;
-          i++;
-          if (m == 0) 
+          if(++i >= QMContextSet::DCContextMagnitudeSet::MagnitudeContexts)
             JPG_THROW(MALFORMED_STREAM,"ACSequentialScan::DecodeBlock",
                       "QMDecoder is out of sync");
         }
@@ -653,8 +652,7 @@ void ACSequentialScan::DecodeBlock(LONG *block,
           
           while(m_Coder.Get(acm.X[i])) {
             m <<= 1;
-            i++;
-            if (m == 0)
+            if(++i >= QMContextSet::ACContextMagnitudeSet::MagnitudeContexts)
               JPG_THROW(MALFORMED_STREAM,"ACSequentialScan::DecodeBlock",
                         "QMDecoder is out of sync");
           }

programming_language: C++
filename: acsequentialscan.hpp
change_type: ModificationType.MODIFY
diff: @@ -43,7 +43,7 @@
 ** Represents the scan including the scan header for the
 ** arithmetic coding procedure.
 **
-** $Id: acsequentialscan.hpp,v 1.38 2016/10/28 13:58:53 thor Exp $
+** $Id: acsequentialscan.hpp,v 1.39 2022/05/23 05:56:51 thor Exp $
 **
 */
 
@@ -120,13 +120,17 @@ class ACSequentialScan : public EntropyParser {
     //
     // The DC Magnitude coding contexts.
     struct DCContextMagnitudeSet {
-      QMContext X[19];
-      QMContext M[19];
+      enum {
+        MagnitudeContexts = 19
+      };
+      //
+      QMContext X[MagnitudeContexts];
+      QMContext M[MagnitudeContexts];
       //
       // Initialize
       void Init(void)
       {
-        for(int i = 0;i < 19;i++) {
+        for(int i = 0;i < MagnitudeContexts;i++) {
 #ifdef DEBUG_QMCODER
           char string[5] = "X0  ";
           string[1] = (i / 10) + '0';
@@ -171,14 +175,17 @@ class ACSequentialScan : public EntropyParser {
     //
     // The AC Magnitude coder.
     struct ACContextMagnitudeSet {
-      QMContext X[18];
-      QMContext M[18];
+      enum {
+        MagnitudeContexts = 18
+      };
+      //
+      QMContext X[MagnitudeContexts];
+      QMContext M[MagnitudeContexts];
       //
-
 #ifdef DEBUG_QMCODER
       void Init(bool hi) 
       {
-        for(int i = 0;i < 18;i++) {
+        for(int i = 0;i < MagnitudeContexts;i++) {
           char string[5] = "xl00";
           string[1] = (hi)?('h'):('l');
           string[2] = (i / 10) + '0';
@@ -191,7 +198,7 @@ class ACSequentialScan : public EntropyParser {
 #else
       void Init(void)
       {
-        for(int i = 0;i < 18;i++) {
+        for(int i = 0;i < MagnitudeContexts;i++) {
           X[i].Init();
           M[i].Init();
         }

programming_language: C++
filename: losslessscan.cpp
change_type: ModificationType.MODIFY
diff: @@ -42,7 +42,7 @@
 **
 ** Represents the scan including the scan header.
 **
-** $Id: losslessscan.cpp,v 1.50 2015/03/25 08:45:43 thor Exp $
+** $Id: losslessscan.cpp,v 1.51 2022/05/23 05:56:51 thor Exp $
 **
 */
 
@@ -377,6 +377,9 @@ void LosslessScan::ParseMCU(struct Line **prev,struct Line **top)
           v = 0;
         } else if (symbol == 16) {
           v = -32768;
+        } else if (symbol > 16) {
+          JPG_THROW(MALFORMED_STREAM,"LosslessScan::ParseMCU",
+                    "received an out-of-bounds symbol in a lossless JPEG scan");
         } else {
           LONG thre = 1L << (symbol - 1);
           LONG diff = m_Stream.Get(symbol); // get the number of bits 

programming_language: C++
filename: rectanglerequest.hpp
change_type: ModificationType.MODIFY
diff: @@ -42,7 +42,7 @@
  * Definition of how to request a given rectangle for display,
  * for load or for checking for a necessary update.
  * 
- * $Id: rectanglerequest.hpp,v 1.12 2017/11/28 13:08:07 thor Exp $
+ * $Id: rectanglerequest.hpp,v 1.13 2022/05/23 05:56:51 thor Exp $
  *
  */
 
@@ -105,19 +105,29 @@ struct RectangleRequest : public JObject, private Explicit {
   RectangleRequest(const struct RectangleRequest &req)
     : Explicit()
   {
-    // Not nice, but this is really faster and simpler
-    memcpy(this,&req,sizeof(struct RectangleRequest));
     // Not linked in any way if this is new.
-    rr_pNext = NULL;
+    rr_pNext            = NULL;
+    rr_Request          = req.rr_Request;
+    rr_usFirstComponent = req.rr_usFirstComponent;
+    rr_usLastComponent  = req.rr_usLastComponent;
+    rr_cPriority        = req.rr_cPriority;
+    rr_bIncludeAlpha    = req.rr_bIncludeAlpha;
+    rr_bUpsampling      = req.rr_bUpsampling;
+    rr_bColorTrafo      = req.rr_bColorTrafo;
   }
   //
   // Assignment operator.
   RectangleRequest &operator=(const struct RectangleRequest &req)
   { 
-    // Not nice, but this is really faster and simpler
-    memcpy(this,&req,sizeof(struct RectangleRequest));
-    // Not linked in any way if this is new.
-    rr_pNext = NULL;
+   // Not linked in any way if this is new.
+    rr_pNext            = NULL;
+    rr_Request          = req.rr_Request;
+    rr_usFirstComponent = req.rr_usFirstComponent;
+    rr_usLastComponent  = req.rr_usLastComponent;
+    rr_cPriority        = req.rr_cPriority;
+    rr_bIncludeAlpha    = req.rr_bIncludeAlpha;
+    rr_bUpsampling      = req.rr_bUpsampling;
+    rr_bColorTrafo      = req.rr_bColorTrafo;
     //
     return *this;
   }

programming_language: C++