|
|
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";
|