CVE-2022-1325: Allocation of Resources Without Limits or Throttling (CWE-770)
value: A flaw was found in Clmg, where with the help of a maliciously crafted pandore or bmp file with modified dx and dy header field values it is possible to trick the application into allocating huge buffer sizes like 64 Gigabyte upon reading the file from disk or from a virtual buffer.
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-08-31T16:15Z
Repository: https://github.com/GreycLab/CImg
Language: C
Files changed: CImg.h
Commit date: 2022-04-07 12:43:39 +0200
Commit message: CImg<>::load_bmp() and CImg<>::load_pandore(): Check that dimensions encoded in file does not exceed file size.

Diff: diff --git a/CImg.h b/CImg.h
index 9dc5a55..5a04974 100644
--- a/CImg.h
+++ b/CImg.h
@@ -53182,10 +53182,11 @@ namespace cimg_library_suffixed {
       if (!file && !filename)
         throw CImgArgumentException(_cimg_instance
                                     "load_bmp(): Specified filename is (null).",
                                     cimg_instance);
 
+      const ulongT fsiz = file?cimg::type<ulongT>::max():(ulongT)cimg::fsize(filename);
       std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
       CImg<ucharT> header(54);
       cimg::fread(header._data,54,nfile);
       if (*header!='B' || header[1]!='M') {
         if (!file) cimg::fclose(nfile);
@@ -53218,10 +53219,16 @@ namespace cimg_library_suffixed {
         align_bytes = (4 - dx_bytes%4)%4;
       const ulongT
         cimg_iobuffer = (ulongT)24*1024*1024,
         buf_size = (ulongT)cimg::abs(dy)*(dx_bytes + align_bytes);
 
+      if (buf_size>fsiz)
+          throw CImgIOException(_cimg_instance
+                                "load_bmp(): File size %lu for filename '%s' does not match encoded image dimensions (%d,%d).",
+                                cimg_instance,
+                                (long)fsiz,filename?filename:"(FILE*)",dx,dy);
+
       CImg<intT> colormap;
       if (bpp<16) { if (!nb_colors) nb_colors = 1<<bpp; } else nb_colors = 0;
       if (nb_colors) { colormap.assign(nb_colors); cimg::fread(colormap._data,nb_colors,nfile); }
       const int xoffset = offset - 14 - header_size - 4*nb_colors;
       if (xoffset>0) cimg::fseek(nfile,xoffset,SEEK_CUR);
@@ -55024,10 +55031,15 @@ namespace cimg_library_suffixed {
 
     CImg<T>& _load_pandore(std::FILE *const file, const char *const filename) {
 #define __cimg_load_pandore_case(nbdim,nwidth,nheight,ndepth,ndim,stype) \
         cimg::fread(dims,nbdim,nfile); \
         if (endian) cimg::invert_endianness(dims,nbdim); \
+        if ((ulongT)nwidth*nheight*ndepth*ndim>fsiz) \
+          throw CImgIOException(_cimg_instance \
+                                "load_pandore(): File size %lu for filename '%s' does not match encoded image dimensions (%d,%d,%d,%d).",\
+                                cimg_instance,\
+                                (long)fsiz,filename?filename:"(FILE*)",(int)nwidth,(int)nheight,(int)ndepth,(int)ndim); \
         assign(nwidth,nheight,ndepth,ndim); \
         const size_t siz = size(); \
         stype *buffer = new stype[siz]; \
         cimg::fread(buffer,siz,nfile); \
         if (endian) cimg::invert_endianness(buffer,siz); \
@@ -55047,10 +55059,11 @@ namespace cimg_library_suffixed {
       if (!file && !filename)
         throw CImgArgumentException(_cimg_instance
                                     "load_pandore(): Specified filename is (null).",
                                     cimg_instance);
 
+      const ulongT fsiz = file?cimg::type<ulongT>::max():(ulongT)cimg::fsize(filename);
       std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
       CImg<charT> header(32);
       cimg::fread(header._data,12,nfile);
       if (cimg::strncasecmp("PANDORE",header,7)) {
         if (!file) cimg::fclose(nfile);

Fixed code:       const ulongT fsiz = file?cimg::type<ulongT>::max():(ulongT)cimg::fsize(filename);
      if (buf_size>fsiz)
          throw CImgIOException(_cimg_instance
                                "load_bmp(): File size %lu for filename '%s' does not match encoded image dimensions (%d,%d).",
                                cimg_instance,
                                (long)fsiz,filename?filename:"(FILE*)",dx,dy);

        if ((ulongT)nwidth*nheight*ndepth*ndim>fsiz) \
          throw CImgIOException(_cimg_instance \
                                "load_pandore(): File size %lu for filename '%s' does not match encoded image dimensions (%d,%d,%d,%d).",\
                                cimg_instance,\
                                (long)fsiz,filename?filename:"(FILE*)",(int)nwidth,(int)nheight,(int)ndepth,(int)ndim); \
      const ulongT fsiz = file?cimg::type<ulongT>::max():(ulongT)cimg::fsize(filename);