CVE-2020-35534: Allocation of Resources Without Limits or Throttling (CWE-770)
value: In LibRaw, there is a memory corruption vulnerability within the "crxFreeSubbandData()" function (libraw\src\decoders\crx.cpp) when processing cr3 files.
CWE description: The product allocates a reusable resource or group of resources on behalf of an actor without imposing any restrictions on the size or number of resources that can be allocated, in violation of the intended security policy for that actor.
CVSS v3 base score: 5.5
Published: 2022-09-01T18:15Z
Repository: https://github.com/LibRaw/LibRaw
Language: C++
Files changed: libraw/libraw_const.h, src/decoders/crx.cpp
Commit date: 2020-04-26 18:49:36 +0300
Commit message: CR3 decoder: use mempool for memory

Diff: diff --git a/libraw/libraw_const.h b/libraw/libraw_const.h
index 2a352b5c0..7923e5160 100644
--- a/libraw/libraw_const.h
+++ b/libraw/libraw_const.h
@@ -24,10 +24,15 @@ it under the terms of the one of two licenses as you choose:
 
 /* Check if enough file space exists before tag read */
 #ifndef LIBRAW_NO_IOSPACE_CHECK
 #define LIBRAW_IOSPACE_CHECK
 #endif
+#ifndef LIBRAW_NO_CR3_MEMPOOL
+#define LIBRAW_CR3_MEMPOOL
+#endif
+
+
 /* LibRaw uses own memory pool management, with LIBRAW_MSIZE (512)
 entries. It is enough for parsing/decoding non-damaged files, but
 may overflow on specially crafted files (eg. with many string values
 like XMP blocks.
 LIBRAW_MEMPOOL_CHECK define will result in error on pool overflow */
diff --git a/src/decoders/crx.cpp b/src/decoders/crx.cpp
index 020a5c12c..4e49356ea 100644
--- a/src/decoders/crx.cpp
+++ b/src/decoders/crx.cpp
@@ -151,10 +151,14 @@ struct CrxImage
   uint64_t mdatOffset;
   uint64_t mdatSize;
   int16_t *outBufs[4]; // one per plane
   int16_t *planeBuf;
   LibRaw_abstract_datastream *input;
+#ifdef LIBRAW_CR3_MEMPOOL
+  libraw_memmgr memmgr;
+  CrxImage() : memmgr(0){}
+#endif
 };
 
 enum TileFlags
 {
   E_HAS_TILES_ON_THE_RIGHT = 1,
@@ -1735,18 +1739,26 @@ void crxConvertPlaneLine(CrxImage *img, int imageRow, int imageCol = 0,
       img->outBufs[3][rawLineOffset + 2 * i] = _constrain(val, 0, maxVal);
     }
   }
 }
 
-int crxParamInit(CrxBandParam **param, uint64_t subbandMdatOffset,
+int crxParamInit(
+#ifdef LIBRAW_CR3_MEMPOOL
+	libraw_memmgr&  mm,
+#endif	
+	CrxBandParam **param, uint64_t subbandMdatOffset,
                  uint64_t subbandDataSize, uint32_t subbandWidth,
                  uint32_t subbandHeight, int32_t supportsPartial,
                  uint32_t roundedBitsMask, LibRaw_abstract_datastream *input)
 {
   int32_t progrDataSize = supportsPartial ? 0 : sizeof(int32_t) * subbandWidth;
   int32_t paramLength = 2 * subbandWidth + 4;
-  uint8_t *paramBuf = (uint8_t *)calloc(
+  uint8_t *paramBuf = (uint8_t *)
+#ifdef LIBRAW_CR3_MEMPOOL
+	  mm.
+#endif
+	  calloc(
       1, sizeof(CrxBandParam) + sizeof(int32_t) * paramLength + progrDataSize);
 
   if (!paramBuf)
     return -1;
 
@@ -1811,11 +1823,15 @@ int crxSetupSubbandData(CrxImage *img, CrxPlaneComp *planeComp,
       else
         compDataSize += 8 * sizeof(int32_t) * tile->width;
   }
 
   // buffer allocation
-  planeComp->compBuf = (uint8_t *)malloc(compDataSize);
+  planeComp->compBuf = (uint8_t *)
+#ifdef LIBRAW_CR3_MEMPOOL
+	  img->memmgr.
+#endif
+	  malloc(compDataSize);
   if (!planeComp->compBuf)
     return -1;
 
   // subbands buffer and sizes initialisation
   uint64_t subbandMdatOffset = img->mdatOffset + mdatOffset;
@@ -1893,11 +1909,15 @@ int crxSetupSubbandData(CrxImage *img, CrxPlaneComp *planeComp,
       if (planeComp->supportsPartial && subbandNum == 0)
       {
         roundedBitsMask = planeComp->roundedBitsMask;
         supportsPartial = 1;
       }
-      if (crxParamInit(&subbands[subbandNum].bandParam,
+      if (crxParamInit(
+#ifdef LIBRAW_CR3_MEMPOOL
+		  img->memmgr,
+#endif
+		  &subbands[subbandNum].bandParam,
                        subbands[subbandNum].mdatOffset,
                        subbands[subbandNum].dataSize,
                        subbands[subbandNum].width, subbands[subbandNum].height,
                        supportsPartial, roundedBitsMask, img->input))
         return -1;
@@ -2085,14 +2105,18 @@ int crxReadImageHeaders(crx_data_header_t *hdr, CrxImage *img, uint8_t *mdatPtr,
   if (!nTiles)
     return -1;
 
   if (!img->tiles)
   {
-    img->tiles = (CrxTile *)malloc(
+    img->tiles = (CrxTile *)
+#ifdef LIBRAW_CR3_MEMPOOL
+		img->memmgr.
+#endif
+		calloc(
         sizeof(CrxTile) * nTiles +
         sizeof(CrxPlaneComp) * nTiles * img->nPlanes +
-        sizeof(CrxSubband) * nTiles * img->nPlanes * img->subbandCount);
+        sizeof(CrxSubband) * nTiles * img->nPlanes * img->subbandCount,1);
     if (!img->tiles)
       return -1;
 
     // memory areas in allocated chunk
     CrxTile *tile = img->tiles;
@@ -2280,11 +2304,15 @@ int crxSetupImageData(crx_data_header_t *hdr, CrxImage *img, int16_t *outBuf,
   // intermediate plane buffer. At the moment though it's too many changes so
   // left as is.
   if (img->encType == 3 && img->nPlanes == 4 && img->nBits > 8)
   {
     img->planeBuf =
-        (int16_t *)malloc(img->planeHeight * img->planeWidth * img->nPlanes *
+        (int16_t *)
+#ifdef LIBRAW_CR3_MEMPOOL
+		img->memmgr.
+#endif
+		malloc(img->planeHeight * img->planeWidth * img->nPlanes *
                           ((img->samplePrecision + 7) >> 3));
     if (!img->planeBuf)
       return -1;
   }
 
@@ -2333,10 +2361,13 @@ int crxSetupImageData(crx_data_header_t *hdr, CrxImage *img, int16_t *outBuf,
   return crxReadImageHeaders(hdr, img, mdatHdrPtr, mdatSize);
 }
 
 int crxFreeImageData(CrxImage *img)
 {
+#ifdef LIBRAW_CR3_MEMPOOL
+	img->memmgr.cleanup();
+#else
   CrxTile *tile = img->tiles;
   int nTiles = img->tileRows * img->tileCols;
 
   if (img->tiles)
   {
@@ -2351,13 +2382,14 @@ int crxFreeImageData(CrxImage *img)
   if (img->planeBuf)
   {
     free(img->planeBuf);
     img->planeBuf = 0;
   }
-
+#endif
   return 0;
 }
+
 void LibRaw::crxLoadDecodeLoop(void *img, int nPlanes)
 {
 #ifdef LIBRAW_USE_OPENMP
   int results[4]; // nPlanes is always <= 4
 #pragma omp parallel for

Vulnerable code: int crxParamInit(CrxBandParam **param, uint64_t subbandMdatOffset,
  uint8_t *paramBuf = (uint8_t *)calloc(
  planeComp->compBuf = (uint8_t *)malloc(compDataSize);
      if (crxParamInit(&subbands[subbandNum].bandParam,
    img->tiles = (CrxTile *)malloc(
        sizeof(CrxSubband) * nTiles * img->nPlanes * img->subbandCount);
        (int16_t *)malloc(img->planeHeight * img->planeWidth * img->nPlanes *

Fixed code: #ifndef LIBRAW_NO_CR3_MEMPOOL
#define LIBRAW_CR3_MEMPOOL
#endif


#ifdef LIBRAW_CR3_MEMPOOL
  libraw_memmgr memmgr;
  CrxImage() : memmgr(0){}
#endif
int crxParamInit(
#ifdef LIBRAW_CR3_MEMPOOL
	libraw_memmgr&  mm,
#endif	
	CrxBandParam **param, uint64_t subbandMdatOffset,
  uint8_t *paramBuf = (uint8_t *)
#ifdef LIBRAW_CR3_MEMPOOL
	  mm.
#endif
	  calloc(
  planeComp->compBuf = (uint8_t *)
#ifdef LIBRAW_CR3_MEMPOOL
	  img->memmgr.
#endif
	  malloc(compDataSize);
      if (crxParamInit(
#ifdef LIBRAW_CR3_MEMPOOL
		  img->memmgr,
#endif
		  &subbands[subbandNum].bandParam,
    img->tiles = (CrxTile *)
#ifdef LIBRAW_CR3_MEMPOOL
		img->memmgr.
#endif
		calloc(
        sizeof(CrxSubband) * nTiles * img->nPlanes * img->subbandCount,1);
        (int16_t *)
#ifdef LIBRAW_CR3_MEMPOOL
		img->memmgr.
#endif
		malloc(img->planeHeight * img->planeWidth * img->nPlanes *
#ifdef LIBRAW_CR3_MEMPOOL
	img->memmgr.cleanup();
#else
#endif