Blame SOURCES/exiv2-CVE-2018-16336.patch

3f58c5
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
3f58c5
index aecd621..cbbd859 100644
3f58c5
--- a/src/CMakeLists.txt
3f58c5
+++ b/src/CMakeLists.txt
3f58c5
@@ -26,6 +26,7 @@ SET( LIBEXIV2_PRIVATE_HDR canonmn_int.hpp
3f58c5
                           pngchunk_int.hpp
3f58c5
                           rcsid_int.hpp
3f58c5
                           rw2image_int.hpp
3f58c5
+                          safe_op.hpp
3f58c5
                           samsungmn_int.hpp
3f58c5
                           sigmamn_int.hpp
3f58c5
                           sonymn_int.hpp
3f58c5
@@ -102,6 +103,7 @@ SET( LIBEXIV2_SRC         asfvideo.cpp
3f58c5
                           futils.cpp
3f58c5
                           fujimn.cpp
3f58c5
                           gifimage.cpp
3f58c5
+                          helper_functions.cpp
3f58c5
                           http.cpp
3f58c5
                           image.cpp
3f58c5
                           ini.cpp
3f58c5
diff --git a/src/helper_functions.cpp b/src/helper_functions.cpp
3f58c5
new file mode 100644
3f58c5
index 0000000..623fbc1
3f58c5
--- /dev/null
3f58c5
+++ b/src/helper_functions.cpp
3f58c5
@@ -0,0 +1,39 @@
3f58c5
+// ********************************************************* -*- C++ -*-
3f58c5
+/*
3f58c5
+ * Copyright (C) 2004-2018 Exiv2 authors
3f58c5
+ *
3f58c5
+ * This program is part of the Exiv2 distribution.
3f58c5
+ *
3f58c5
+ * This program is free software; you can redistribute it and/or
3f58c5
+ * modify it under the terms of the GNU General Public License
3f58c5
+ * as published by the Free Software Foundation; either version 2
3f58c5
+ * of the License, or (at your option) any later version.
3f58c5
+ *
3f58c5
+ * This program is distributed in the hope that it will be useful,
3f58c5
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3f58c5
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
3f58c5
+ * GNU General Public License for more details.
3f58c5
+ *
3f58c5
+ * You should have received a copy of the GNU General Public License
3f58c5
+ * along with this program; if not, write to the Free Software
3f58c5
+ * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA.
3f58c5
+ */
3f58c5
+/*!
3f58c5
+  @file    helper_functions.cpp
3f58c5
+  @brief   A collection of helper functions
3f58c5
+  @author  Dan Čermák (D4N)
3f58c5
+           dan.cermak@cgc-instruments.com
3f58c5
+  @date    25-May-18, D4N: created
3f58c5
+ */
3f58c5
+
3f58c5
+#include "helper_functions.hpp"
3f58c5
+
3f58c5
+#include <string.h>
3f58c5
+
3f58c5
+
3f58c5
+std::string string_from_unterminated(const char* data, size_t data_length)
3f58c5
+{
3f58c5
+    const size_t StringLength = strnlen(data, data_length);
3f58c5
+
3f58c5
+    return std::string(data, StringLength);
3f58c5
+}
3f58c5
diff --git a/src/helper_functions.hpp b/src/helper_functions.hpp
3f58c5
new file mode 100644
3f58c5
index 0000000..d70cbc1
3f58c5
--- /dev/null
3f58c5
+++ b/src/helper_functions.hpp
3f58c5
@@ -0,0 +1,50 @@
3f58c5
+// ********************************************************* -*- C++ -*-
3f58c5
+/*
3f58c5
+ * Copyright (C) 2004-2018 Exiv2 authors
3f58c5
+ *
3f58c5
+ * This program is part of the Exiv2 distribution.
3f58c5
+ *
3f58c5
+ * This program is free software; you can redistribute it and/or
3f58c5
+ * modify it under the terms of the GNU General Public License
3f58c5
+ * as published by the Free Software Foundation; either version 2
3f58c5
+ * of the License, or (at your option) any later version.
3f58c5
+ *
3f58c5
+ * This program is distributed in the hope that it will be useful,
3f58c5
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3f58c5
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
3f58c5
+ * GNU General Public License for more details.
3f58c5
+ *
3f58c5
+ * You should have received a copy of the GNU General Public License
3f58c5
+ * along with this program; if not, write to the Free Software
3f58c5
+ * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA.
3f58c5
+ */
3f58c5
+/*!
3f58c5
+  @file    helper_functions.hpp
3f58c5
+  @brief   A collection of helper functions
3f58c5
+  @author  Dan Čermák (D4N)
3f58c5
+           dan.cermak@cgc-instruments.com
3f58c5
+  @date    25-May-18, D4N: created
3f58c5
+ */
3f58c5
+#ifndef HELPER_FUNCTIONS_HPP
3f58c5
+#define HELPER_FUNCTIONS_HPP
3f58c5
+
3f58c5
+#include <string>
3f58c5
+
3f58c5
+/*!
3f58c5
+  @brief Convert a (potentially not null terminated) array into a
3f58c5
+  std::string.
3f58c5
+
3f58c5
+  Convert a C style string that may or may not be null terminated safely
3f58c5
+  into a std::string. The string's termination is either set at the first \0
3f58c5
+  or after data_length characters.
3f58c5
+
3f58c5
+  @param[in] data  A c-string from which the std::string shall be
3f58c5
+      constructed. Does not need to be null terminated.
3f58c5
+  @param[in] data_length  An upper bound for the string length (must be at most
3f58c5
+      the allocated length of `buffer`). If no null terminator is found in data,
3f58c5
+      then the resulting std::string will be null terminated at `data_length`.
3f58c5
+
3f58c5
+ */
3f58c5
+std::string string_from_unterminated(const char* data, size_t data_length);
3f58c5
+
3f58c5
+#endif  // HELPER_FUNCTIONS_HPP
3f58c5
diff --git a/src/pngchunk.cpp b/src/pngchunk.cpp
3f58c5
index 29ffcfa..e4e3274 100644
3f58c5
--- a/src/pngchunk.cpp
3f58c5
+++ b/src/pngchunk.cpp
3f58c5
@@ -38,6 +38,8 @@ EXIV2_RCSID("@(#) $Id$")
3f58c5
 #include "image.hpp"
3f58c5
 #include "error.hpp"
3f58c5
 #include "enforce.hpp"
3f58c5
+#include "helper_functions.hpp"
3f58c5
+#include "safe_op.hpp"
3f58c5
 
3f58c5
 // + standard includes
3f58c5
 #include <sstream>
3f58c5
@@ -137,6 +139,8 @@ namespace Exiv2 {
3f58c5
 
3f58c5
         if(type == zTXt_Chunk)
3f58c5
         {
3f58c5
+            enforce(data.size_ >= Safe::add(keysize, 2), Exiv2::kerCorruptedMetadata);
3f58c5
+
3f58c5
             // Extract a deflate compressed Latin-1 text chunk
3f58c5
 
3f58c5
             // we get the compression method after the key
3f58c5
@@ -153,11 +157,13 @@ namespace Exiv2 {
3f58c5
             // compressed string after the compression technique spec
3f58c5
             const byte* compressedText      = data.pData_ + keysize + 2;
3f58c5
             unsigned int compressedTextSize = data.size_  - keysize - 2;
3f58c5
+            enforce(compressedTextSize < data.size_, kerCorruptedMetadata);
3f58c5
 
3f58c5
             zlibUncompress(compressedText, compressedTextSize, arr);
3f58c5
         }
3f58c5
         else if(type == tEXt_Chunk)
3f58c5
         {
3f58c5
+            enforce(data.size_ >= Safe::add(keysize, 1), Exiv2::kerCorruptedMetadata);
3f58c5
             // Extract a non-compressed Latin-1 text chunk
3f58c5
 
3f58c5
             // the text comes after the key, but isn't null terminated
3f58c5
@@ -168,6 +174,7 @@ namespace Exiv2 {
3f58c5
         }
3f58c5
         else if(type == iTXt_Chunk)
3f58c5
         {
3f58c5
+            enforce(data.size_ >= Safe::add(keysize, 3), Exiv2::kerCorruptedMetadata);
3f58c5
             const int nullSeparators = std::count(&data.pData_[keysize+3], &data.pData_[data.size_], '\0');
3f58c5
 
3f58c5
             enforce(nullSeparators >= 2, Exiv2::kerCorruptedMetadata);
3f58c5
@@ -180,42 +187,46 @@ namespace Exiv2 {
3f58c5
             const byte compressionMethod = data.pData_[keysize + 2];
3f58c5
             enforce(compressionFlag == 0x00 || compressionFlag == 0x01, Exiv2::kerCorruptedMetadata);
3f58c5
             enforce(compressionMethod == 0x00, Exiv2::kerCorruptedMetadata);
3f58c5
+
3f58c5
             // language description string after the compression technique spec
3f58c5
-            std::string languageText((const char*)(data.pData_ + keysize + 3));
3f58c5
-            unsigned int languageTextSize = static_cast<unsigned int>(languageText.size());
3f58c5
+            const size_t languageTextMaxSize = data.size_ - keysize - 3;
3f58c5
+            std::string languageText =
3f58c5
+                string_from_unterminated((const char*)(data.pData_ + Safe::add(keysize, 3)), languageTextMaxSize);
3f58c5
+            const unsigned int languageTextSize = static_cast<unsigned int>(languageText.size());
3f58c5
+            enforce(data.size_ >= Safe::add(static_cast<unsigned int>(Safe::add(keysize, 4)), languageTextSize),
3f58c5
+                    Exiv2::kerCorruptedMetadata);
3f58c5
+
3f58c5
             // translated keyword string after the language description
3f58c5
-            std::string translatedKeyText((const char*)(data.pData_ + keysize + 3 + languageTextSize +1));
3f58c5
-            unsigned int translatedKeyTextSize = static_cast<unsigned int>(translatedKeyText.size());
3f58c5
+            std::string translatedKeyText =
3f58c5
+                string_from_unterminated((const char*)(data.pData_ + keysize + 3 + languageTextSize + 1),
3f58c5
+                                         data.size_ - (keysize + 3 + languageTextSize + 1));
3f58c5
+            const unsigned int translatedKeyTextSize = static_cast<unsigned int>(translatedKeyText.size());
3f58c5
 
3f58c5
-            if ( compressionFlag == 0x00 )
3f58c5
-            {
3f58c5
-                // then it's an uncompressed iTXt chunk
3f58c5
-#ifdef DEBUG
3f58c5
-                std::cout << "Exiv2::PngChunk::parseTXTChunk: We found an uncompressed iTXt field\n";
3f58c5
-#endif
3f58c5
+            if ((compressionFlag == 0x00) || (compressionFlag == 0x01 && compressionMethod == 0x00)) {
3f58c5
+                enforce(Safe::add(static_cast<unsigned int>(keysize + 3 + languageTextSize + 1),
3f58c5
+                                  Safe::add(translatedKeyTextSize, 1u)) <= data.size_,
3f58c5
+                        Exiv2::kerCorruptedMetadata);
3f58c5
 
3f58c5
-                // the text comes after the translated keyword, but isn't null terminated
3f58c5
                 const byte* text = data.pData_ + keysize + 3 + languageTextSize + 1 + translatedKeyTextSize + 1;
3f58c5
-                long textsize    = data.size_ - (keysize + 3 + languageTextSize + 1 + translatedKeyTextSize + 1);
3f58c5
+                const long textsize = data.size_ - (keysize + 3 + languageTextSize + 1 + translatedKeyTextSize + 1);
3f58c5
 
3f58c5
-                arr.alloc(textsize);
3f58c5
-                arr = DataBuf(text, textsize);
3f58c5
-            }
3f58c5
-            else if ( compressionFlag == 0x01 && compressionMethod == 0x00 )
3f58c5
-            {
3f58c5
-                // then it's a zlib compressed iTXt chunk
3f58c5
+                if (compressionFlag == 0x00) {
3f58c5
+                    // then it's an uncompressed iTXt chunk
3f58c5
 #ifdef DEBUG
3f58c5
-                std::cout << "Exiv2::PngChunk::parseTXTChunk: We found a zlib compressed iTXt field\n";
3f58c5
+                    std::cout << "Exiv2::PngChunk::parseTXTChunk: We found an uncompressed iTXt field\n";
3f58c5
 #endif
3f58c5
 
3f58c5
-                // the compressed text comes after the translated keyword, but isn't null terminated
3f58c5
-                const byte* compressedText = data.pData_ + keysize + 3 + languageTextSize + 1 + translatedKeyTextSize + 1;
3f58c5
-                long compressedTextSize    = data.size_ - (keysize + 3 + languageTextSize + 1 + translatedKeyTextSize + 1);
3f58c5
-
3f58c5
-                zlibUncompress(compressedText, compressedTextSize, arr);
3f58c5
-            }
3f58c5
-            else
3f58c5
-            {
3f58c5
+                    arr.alloc(textsize);
3f58c5
+                    arr = DataBuf(text, textsize);
3f58c5
+                } else if (compressionFlag == 0x01 && compressionMethod == 0x00) {
3f58c5
+                    // then it's a zlib compressed iTXt chunk
3f58c5
+#ifdef DEBUG
3f58c5
+                    std::cout << "Exiv2::PngChunk::parseTXTChunk: We found a zlib compressed iTXt field\n";
3f58c5
+#endif
3f58c5
+                    // the compressed text comes after the translated keyword, but isn't null terminated
3f58c5
+                    zlibUncompress(text, textsize, arr);
3f58c5
+                }
3f58c5
+            } else {
3f58c5
                 // then it isn't zlib compressed and we are sunk
3f58c5
 #ifdef DEBUG
3f58c5
                 std::cerr << "Exiv2::PngChunk::parseTXTChunk: Non-standard iTXt compression method.\n";