CVE-2017-16909: Improper Restriction of Operations within the Bounds of a Memory Buffer (CWE-119)
value: An error related to the "LibRaw::panasonic_load_raw()" function (dcraw_common.cpp) in LibRaw versions prior to 0.18.6 can be exploited to cause a heap-based buffer overflow and subsequently cause a crash via a specially crafted TIFF image.
CWE description: The product performs operations on a memory buffer, but it reads from or writes to a memory location outside the buffer's intended boundary. This may result in read or write operations on unexpected memory locations that could be linked to other variables, data structures, or internal program data.
CVSS v3 base score: 8.8
Published: 2018-12-07T22:29Z
Repository: https://github.com/LibRaw/LibRaw
Language: C++
Files changed: dcraw/dcraw.c, internal/dcraw_common.cpp, libraw/libraw_const.h
Commit date: 2017-12-02 12:01:40 +0300
Commit message: SECUNIA advisory 76000 #1 (wrong fuji width set via tiff tag

Diff: diff --git a/dcraw/dcraw.c b/dcraw/dcraw.c
index a072a40..7ce50e6 100644
--- a/dcraw/dcraw.c
+++ b/dcraw/dcraw.c
@@ -3170,11 +3170,11 @@ unsigned CLASS pana_bits(int nbits)
 void CLASS panasonic_load_raw()
 {
   int row, col, i, j, sh = 0, pred[2], nonz[2];
 
   pana_bits(0);
-  for (row = 0; row < height; row++)
+  for (row = 0; row < raw_height; row++)
   {
 #ifdef LIBRAW_LIBRARY_BUILD
     checkCancel();
 #endif
     for (col = 0; col < raw_width; col++)
@@ -3192,11 +3192,11 @@ void CLASS panasonic_load_raw()
           pred[i & 1] += j << sh;
         }
       }
       else if ((nonz[i & 1] = pana_bits(8)) || i > 11)
         pred[i & 1] = nonz[i & 1] << 4 | pana_bits(4);
-      if ((RAW(row, col) = pred[col & 1]) > 4098 && col < width)
+      if ((RAW(row, col) = pred[col & 1]) > 4098 && col < width && row < height)
         derror();
     }
   }
 }
 void CLASS panasonic_16x10_load_raw()
@@ -15035,10 +15035,13 @@ void CLASS parse_fuji(int offset)
 
   fseek(ifp, offset, SEEK_SET);
   entries = get4();
   if (entries > 255)
     return;
+#ifdef LIBRAW_LIBRARY_BUILD
+  imgdata.process_warnings |=  LIBRAW_WARN_PARSEFUJI_PROCESSED; 
+#endif
   while (entries--)
   {
     tag = get2();
     len = get2();
     save = ftell(ifp);
@@ -19578,10 +19581,15 @@ dng_skip:
 
   if (load_raw == &CLASS kodak_radc_load_raw)
     if (raw_color)
       adobe_coeff("Apple", "Quicktake");
 
+#ifdef LIBRAW_LIBRARY_BUILD
+  // Clear erorneus fuji_width if not set through parse_fuji or for DNG
+  if(fuji_width && !dng_version && !(imgdata.process_warnings & LIBRAW_WARN_PARSEFUJI_PROCESSED ))
+     fuji_width = 0;
+#endif
   if (fuji_width)
   {
     fuji_width = width >> !fuji_layout;
     filters = fuji_width & 1 ? 0x94949494 : 0x49494949;
     width = (height >> fuji_layout) + fuji_width;
diff --git a/internal/dcraw_common.cpp b/internal/dcraw_common.cpp
index 5cd5153..56f37a3 100644
--- a/internal/dcraw_common.cpp
+++ b/internal/dcraw_common.cpp
@@ -2873,11 +2873,11 @@ unsigned CLASS pana_bits(int nbits)
 void CLASS panasonic_load_raw()
 {
   int row, col, i, j, sh = 0, pred[2], nonz[2];
 
   pana_bits(0);
-  for (row = 0; row < height; row++)
+  for (row = 0; row < raw_height; row++)
   {
 #ifdef LIBRAW_LIBRARY_BUILD
     checkCancel();
 #endif
     for (col = 0; col < raw_width; col++)
@@ -2895,11 +2895,11 @@ void CLASS panasonic_load_raw()
           pred[i & 1] += j << sh;
         }
       }
       else if ((nonz[i & 1] = pana_bits(8)) || i > 11)
         pred[i & 1] = nonz[i & 1] << 4 | pana_bits(4);
-      if ((RAW(row, col) = pred[col & 1]) > 4098 && col < width)
+      if ((RAW(row, col) = pred[col & 1]) > 4098 && col < width && row < height)
         derror();
     }
   }
 }
 void CLASS panasonic_16x10_load_raw()
@@ -13706,10 +13706,13 @@ void CLASS parse_fuji(int offset)
 
   fseek(ifp, offset, SEEK_SET);
   entries = get4();
   if (entries > 255)
     return;
+#ifdef LIBRAW_LIBRARY_BUILD
+  imgdata.process_warnings |=  LIBRAW_WARN_PARSEFUJI_PROCESSED; 
+#endif
   while (entries--)
   {
     tag = get2();
     len = get2();
     save = ftell(ifp);
@@ -18089,10 +18092,15 @@ dng_skip:
 
   if (load_raw == &CLASS kodak_radc_load_raw)
     if (raw_color)
       adobe_coeff("Apple", "Quicktake");
 
+#ifdef LIBRAW_LIBRARY_BUILD
+  // Clear erorneus fuji_width if not set through parse_fuji or for DNG
+  if(fuji_width && !dng_version && !(imgdata.process_warnings & LIBRAW_WARN_PARSEFUJI_PROCESSED ))
+     fuji_width = 0;
+#endif
   if (fuji_width)
   {
     fuji_width = width >> !fuji_layout;
     filters = fuji_width & 1 ? 0x94949494 : 0x49494949;
     width = (height >> fuji_layout) + fuji_width;
diff --git a/libraw/libraw_const.h b/libraw/libraw_const.h
index 0437e92..6974492 100644
--- a/libraw/libraw_const.h
+++ b/libraw/libraw_const.h
@@ -229,11 +229,12 @@ enum LibRaw_warnings
   LIBRAW_WARN_BAD_DARKFRAME_DIM = 1 << 10,
   LIBRAW_WARN_NO_JASPER = 1 << 11,
   LIBRAW_WARN_RAWSPEED_PROBLEM = 1 << 12,
   LIBRAW_WARN_RAWSPEED_UNSUPPORTED = 1 << 13,
   LIBRAW_WARN_RAWSPEED_PROCESSED = 1 << 14,
-  LIBRAW_WARN_FALLBACK_TO_AHD = 1 << 15
+  LIBRAW_WARN_FALLBACK_TO_AHD = 1 << 15,
+  LIBRAW_WARN_PARSEFUJI_PROCESSED = 1 << 16
 };
 
 enum LibRaw_exceptions
 {
   LIBRAW_EXCEPTION_NONE = 0,

Vulnerable code:   for (row = 0; row < height; row++)
      if ((RAW(row, col) = pred[col & 1]) > 4098 && col < width)
  for (row = 0; row < height; row++)
      if ((RAW(row, col) = pred[col & 1]) > 4098 && col < width)
  LIBRAW_WARN_FALLBACK_TO_AHD = 1 << 15
Fixed code:   for (row = 0; row < raw_height; row++)
      if ((RAW(row, col) = pred[col & 1]) > 4098 && col < width && row < height)
#ifdef LIBRAW_LIBRARY_BUILD
  imgdata.process_warnings |=  LIBRAW_WARN_PARSEFUJI_PROCESSED; 
#endif
#ifdef LIBRAW_LIBRARY_BUILD
  // Clear erorneus fuji_width if not set through parse_fuji or for DNG
  if(fuji_width && !dng_version && !(imgdata.process_warnings & LIBRAW_WARN_PARSEFUJI_PROCESSED ))
     fuji_width = 0;
#endif
  for (row = 0; row < raw_height; row++)
      if ((RAW(row, col) = pred[col & 1]) > 4098 && col < width && row < height)
#ifdef LIBRAW_LIBRARY_BUILD
  imgdata.process_warnings |=  LIBRAW_WARN_PARSEFUJI_PROCESSED; 
#endif
#ifdef LIBRAW_LIBRARY_BUILD
  // Clear erorneus fuji_width if not set through parse_fuji or for DNG
  if(fuji_width && !dng_version && !(imgdata.process_warnings & LIBRAW_WARN_PARSEFUJI_PROCESSED ))
     fuji_width = 0;
#endif
  LIBRAW_WARN_FALLBACK_TO_AHD = 1 << 15,
  LIBRAW_WARN_PARSEFUJI_PROCESSED = 1 << 16