Backport security fixes from 0.26 branch

This commit is contained in:
Jan Grulich 2018-08-02 12:59:21 +02:00
parent 3370565138
commit b326000085
21 changed files with 1605 additions and 207 deletions

1
.gitignore vendored
View File

@ -1,2 +1,3 @@
/exiv2-0.25.tar.gz
/exiv2-0.26-trunk.tar.gz
/exiv2-0.26.tar.gz

View File

@ -0,0 +1,41 @@
From 1f1715c086d8dcdf5165b19164af9aee7aa12e98 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Dan=20=C4=8Cerm=C3=A1k?= <dan.cermak@cgc-instruments.com>
Date: Fri, 6 Oct 2017 00:37:43 +0200
Subject: =?UTF-8?q?Use=20nullptr=20check=20instead=20of=20assertion,=20by?=
=?UTF-8?q?=20Rapha=C3=ABl=20Hertzog?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Source:
https://github.com/Exiv2/exiv2/issues/57#issuecomment-333086302
tc can be a null pointer when the TIFF tag is unknown (the factory
then returns an auto_ptr(0)) => as this can happen for corrupted
files, an explicit check should be used because an assertion can be
turned of in release mode (with NDEBUG defined)
This also fixes #57
diff --git a/src/tiffvisitor.cpp b/src/tiffvisitor.cpp
index 74f8d078..4ab733d4 100644
--- a/src/tiffvisitor.cpp
+++ b/src/tiffvisitor.cpp
@@ -1294,11 +1294,12 @@ namespace Exiv2 {
}
uint16_t tag = getUShort(p, byteOrder());
TiffComponent::AutoPtr tc = TiffCreator::create(tag, object->group());
- // The assertion typically fails if a component is not configured in
- // the TIFF structure table
- assert(tc.get());
- tc->setStart(p);
- object->addChild(tc);
+ if (tc.get()) {
+ tc->setStart(p);
+ object->addChild(tc);
+ } else {
+ EXV_WARNING << "Unable to handle tag " << tag << ".\n";
+ }
p += 12;
}

View File

@ -0,0 +1,36 @@
From 6ede8aa1975177705450abb816163f0b8d33a597 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Dan=20=C4=8Cerm=C3=A1k?= <dan.cermak@cgc-instruments.com>
Date: Fri, 6 Oct 2017 23:09:08 +0200
Subject: Fix for CVE-2017-14860
A heap buffer overflow could occur in memcpy when icc.size_ is larger
than data.size_ - pad, as then memcpy would read out of bounds of data.
This commit adds a sanity check to iccLength (= icc.size_): if it is
larger than data.size_ - pad (i.e. an overflow would be caused) an
exception is thrown.
This fixes #71.
diff --git a/src/jp2image.cpp b/src/jp2image.cpp
index 1892fd43..09d023e2 100644
--- a/src/jp2image.cpp
+++ b/src/jp2image.cpp
@@ -269,10 +269,15 @@ namespace Exiv2
std::cout << "Exiv2::Jp2Image::readMetadata: "
<< "Color data found" << std::endl;
#endif
- long pad = 3 ; // 3 padding bytes 2 0 0
+ const long pad = 3 ; // 3 padding bytes 2 0 0
DataBuf data(subBox.length+8);
io_->read(data.pData_,data.size_);
- long iccLength = getULong(data.pData_+pad, bigEndian);
+ const long iccLength = getULong(data.pData_+pad, bigEndian);
+ // subtracting pad from data.size_ is safe:
+ // size_ is at least 8 and pad = 3
+ if (iccLength > data.size_ - pad) {
+ throw Error(58);
+ }
DataBuf icc(iccLength);
::memcpy(icc.pData_,data.pData_+pad,icc.size_);
#ifdef DEBUG

View File

@ -0,0 +1,53 @@
From d4e4288d839d0d9546a05986771f8738c382060c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Dan=20=C4=8Cerm=C3=A1k?= <dan.cermak@cgc-instruments.com>
Date: Sat, 7 Oct 2017 23:08:36 +0200
Subject: Fix for CVE-2017-14864, CVE-2017-14862 and CVE-2017-14859
The invalid memory dereference in
Exiv2::getULong()/Exiv2::StringValueBase::read()/Exiv2::DataValue::read()
is caused further up the call-stack, by
v->read(pData, size, byteOrder) in TiffReader::readTiffEntry()
passing an invalid pData pointer (pData points outside of the Tiff
file). pData can be set out of bounds in the (size > 4) branch where
baseOffset() and offset are added to pData_ without checking whether
the result is still in the file. As offset comes from an untrusted
source, an attacker can craft an arbitrarily large offset into the
file.
This commit adds a check into the problematic branch, whether the
result of the addition would be out of bounds of the Tiff
file. Furthermore the whole operation is checked for possible
overflows.
diff --git a/src/tiffvisitor.cpp b/src/tiffvisitor.cpp
index 4ab733d4..ef13542e 100644
--- a/src/tiffvisitor.cpp
+++ b/src/tiffvisitor.cpp
@@ -47,6 +47,7 @@ EXIV2_RCSID("@(#) $Id$")
#include <iostream>
#include <iomanip>
#include <cassert>
+#include <limits>
// *****************************************************************************
namespace {
@@ -1517,7 +1518,19 @@ namespace Exiv2 {
size = 0;
}
if (size > 4) {
+ // setting pData to pData_ + baseOffset() + offset can result in pData pointing to invalid memory,
+ // as offset can be arbitrarily large
+ if ((static_cast<uintptr_t>(baseOffset()) > std::numeric_limits<uintptr_t>::max() - static_cast<uintptr_t>(offset))
+ || (static_cast<uintptr_t>(baseOffset() + offset) > std::numeric_limits<uintptr_t>::max() - reinterpret_cast<uintptr_t>(pData_)))
+ {
+ throw Error(59);
+ }
+ if (pData_ + static_cast<uintptr_t>(baseOffset()) + static_cast<uintptr_t>(offset) > pLast_) {
+ throw Error(58);
+ }
pData = const_cast<byte*>(pData_) + baseOffset() + offset;
+
+ // check for size being invalid
if (size > static_cast<uint32_t>(pLast_ - pData)) {
#ifndef SUPPRESS_WARNINGS
EXV_ERROR << "Upper boundary of data for "

View File

@ -0,0 +1,37 @@
From 06aa7ab69d0c4f3d14644bd84fc9d1346154430d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Dan=20=C4=8Cerm=C3=A1k?= <dan.cermak@cgc-instruments.com>
Date: Mon, 22 Jan 2018 23:56:08 +0100
Subject: Fix out of bounds read in src/pngchunk_int.cpp by @brianmay
- consider that key is advanced by 8 bytes if stripHeader is true
=> length is reduced by same amount
Fixed by adding offset to the check in the loop
- Rewrote loop so that keysize is checked before the next
iteration (preventing an out of bounds read)
diff --git a/src/pngchunk.cpp b/src/pngchunk.cpp
index da4ccd01..b54bcdac 100644
--- a/src/pngchunk.cpp
+++ b/src/pngchunk.cpp
@@ -107,15 +107,17 @@ namespace Exiv2 {
{
// From a tEXt, zTXt, or iTXt chunk,
// we get the key, it's a null terminated string at the chunk start
- if (data.size_ <= (stripHeader ? 8 : 0)) throw Error(14);
- const byte *key = data.pData_ + (stripHeader ? 8 : 0);
+ const int offset = stripHeader ? 8 : 0;
+ if (data.size_ <= offset) throw Error(14);
+ const byte *key = data.pData_ + offset;
// Find null string at end of key.
int keysize=0;
- for ( ; key[keysize] != 0 ; keysize++)
+ while (key[keysize] != 0)
{
+ keysize++;
// look if keysize is valid.
- if (keysize >= data.size_)
+ if (keysize+offset >= data.size_)
throw Error(14);
}

View File

@ -1,59 +0,0 @@
diff --git a/include/exiv2/value.hpp b/include/exiv2/value.hpp
index 64a8ca7..4e9f285 100644
--- a/include/exiv2/value.hpp
+++ b/include/exiv2/value.hpp
@@ -1658,11 +1658,13 @@ namespace Exiv2 {
ok_ = true;
return static_cast<long>(value_[n]);
}
+// #55 crash when value_[n].first == LONG_MIN
+#define LARGE_INT 1000000
// Specialization for rational
template<>
inline long ValueType<Rational>::toLong(long n) const
{
- ok_ = (value_[n].second != 0);
+ ok_ = (value_[n].second != 0 && -LARGE_INT < value_[n].first && value_[n].first < LARGE_INT);
if (!ok_) return 0;
return value_[n].first / value_[n].second;
}
@@ -1670,7 +1672,7 @@ namespace Exiv2 {
template<>
inline long ValueType<URational>::toLong(long n) const
{
- ok_ = (value_[n].second != 0);
+ ok_ = (value_[n].second != 0 && value_[n].first < LARGE_INT);
if (!ok_) return 0;
return value_[n].first / value_[n].second;
}
diff --git a/src/basicio.cpp b/src/basicio.cpp
index 1ede931..eac756f 100644
--- a/src/basicio.cpp
+++ b/src/basicio.cpp
@@ -990,6 +990,7 @@ namespace Exiv2 {
DataBuf FileIo::read(long rcount)
{
assert(p_->fp_ != 0);
+ if ( (size_t) rcount > size() ) throw Error(57);
DataBuf buf(rcount);
long readCount = read(buf.pData_, buf.size_);
buf.size_ = readCount;
diff --git a/src/image.cpp b/src/image.cpp
index 31b9b81..eeb1f37 100644
--- a/src/image.cpp
+++ b/src/image.cpp
@@ -399,7 +399,13 @@ namespace Exiv2 {
;
// if ( offset > io.size() ) offset = 0; // Denial of service?
- DataBuf buf(size*count + pad+20); // allocate a buffer
+
+ // #55 memory allocation crash test/data/POC8
+ long long allocate = (long long) size*count + pad+20;
+ if ( allocate > (long long) io.size() ) {
+ throw Error(57);
+ }
+ DataBuf buf(allocate); // allocate a buffer
std::memcpy(buf.pData_,dir.pData_+8,4); // copy dir[8:11] into buffer (short strings)
if ( count*size > 4 ) { // read into buffer
size_t restore = io.tell(); // save

View File

@ -1,89 +1,14 @@
diff --git a/src/actions.cpp b/src/actions.cpp
index 35c7965..cb905f6 100644
--- a/src/actions.cpp
+++ b/src/actions.cpp
@@ -59,6 +59,7 @@ EXIV2_RCSID("@(#) $Id: actions.cpp 4719 2017-03-08 20:42:28Z robinwmills $")
#include <ctime>
#include <cmath>
#include <cassert>
+#include <stdexcept>
#include <sys/types.h> // for stat()
#include <sys/stat.h> // for stat()
#ifdef EXV_HAVE_UNISTD_H
@@ -236,33 +237,43 @@ namespace Action {
}
From 7c6f59619616a01e242401cf4c8e06428539a035 Mon Sep 17 00:00:00 2001
From: Luis Diaz Mas <piponazo@gmail.com>
Date: Sat, 16 Dec 2017 16:05:08 +0100
Subject: Fix arithmetic operation overflow
int Print::run(const std::string& path)
- try {
- path_ = path;
- int rc = 0;
- Exiv2::PrintStructureOption option = Exiv2::kpsNone ;
- switch (Params::instance().printMode_) {
- case Params::pmSummary: rc = printSummary(); break;
- case Params::pmList: rc = printList(); break;
- case Params::pmComment: rc = printComment(); break;
- case Params::pmPreview: rc = printPreviewList(); break;
- case Params::pmStructure: rc = printStructure(std::cout,Exiv2::kpsBasic) ; break;
- case Params::pmRecursive: rc = printStructure(std::cout,Exiv2::kpsRecursive) ; break;
-
- case Params::pmXMP:
- option = option == Exiv2::kpsNone ? Exiv2::kpsXMP : option; // drop
- case Params::pmIccProfile:{
- option = option == Exiv2::kpsNone ? Exiv2::kpsIccProfile : option;
- _setmode(_fileno(stdout),O_BINARY);
- rc = printStructure(std::cout,option);
- } break;
+ {
+ try {
+ path_ = path;
+ int rc = 0;
+ Exiv2::PrintStructureOption option = Exiv2::kpsNone ;
+ switch (Params::instance().printMode_) {
+ case Params::pmSummary: rc = printSummary(); break;
+ case Params::pmList: rc = printList(); break;
+ case Params::pmComment: rc = printComment(); break;
+ case Params::pmPreview: rc = printPreviewList(); break;
+ case Params::pmStructure: rc = printStructure(std::cout,Exiv2::kpsBasic) ; break;
+ case Params::pmRecursive: rc = printStructure(std::cout,Exiv2::kpsRecursive) ; break;
+
+ case Params::pmXMP:
+ if (option == Exiv2::kpsNone)
+ option = Exiv2::kpsXMP;
+ // drop
+ case Params::pmIccProfile:
+ if (option == Exiv2::kpsNone)
+ option = Exiv2::kpsIccProfile;
+ _setmode(_fileno(stdout),O_BINARY);
+ rc = printStructure(std::cout,option);
+ break;
+ }
+ return rc;
+ }
+ catch(const Exiv2::AnyError& e) {
+ std::cerr << "Exiv2 exception in print action for file "
+ << path << ":\n" << e << "\n";
+ return 1;
+ }
+ catch(const std::overflow_error& e) {
+ std::cerr << "std::overflow_error exception in print action for file "
+ << path << ":\n" << e.what() << "\n";
+ return 1;
}
- return rc;
}
- catch(const Exiv2::AnyError& e) {
- std::cerr << "Exiv2 exception in print action for file "
- << path << ":\n" << e << "\n";
- return 1;
- } // Print::run
int Print::printStructure(std::ostream& out, Exiv2::PrintStructureOption option)
{
diff --git a/src/jp2image.cpp b/src/jp2image.cpp
index ac31257..4c072d7 100644
index 09d023e2..a308bfd9 100644
--- a/src/jp2image.cpp
+++ b/src/jp2image.cpp
@@ -41,6 +41,7 @@ EXIV2_RCSID("@(#) $Id: jp2image.cpp 4759 2017-04-23 10:58:54Z robinwmills $")
@@ -41,6 +41,7 @@ EXIV2_RCSID("@(#) $Id$")
#include "error.hpp"
#include "futils.hpp"
#include "types.hpp"
@ -91,23 +16,31 @@ index ac31257..4c072d7 100644
// + standard includes
#include <string>
@@ -269,8 +270,9 @@ namespace Exiv2
@@ -269,15 +270,16 @@ namespace Exiv2
std::cout << "Exiv2::Jp2Image::readMetadata: "
<< "Color data found" << std::endl;
#endif
+
long pad = 3 ; // 3 padding bytes 2 0 0
const long pad = 3 ; // 3 padding bytes 2 0 0
- DataBuf data(subBox.length+8);
+ DataBuf data(Safe::add(subBox.length, static_cast<uint32_t>(8)));
io_->read(data.pData_,data.size_);
long iccLength = getULong(data.pData_+pad, bigEndian);
const long iccLength = getULong(data.pData_+pad, bigEndian);
// subtracting pad from data.size_ is safe:
// size_ is at least 8 and pad = 3
if (iccLength > data.size_ - pad) {
throw Error(58);
- }
+ }
DataBuf icc(iccLength);
::memcpy(icc.pData_,data.pData_+pad,icc.size_);
#ifdef DEBUG
diff --git a/src/safe_op.hpp b/src/safe_op.hpp
new file mode 100644
index 0000000..014b7f3
index 00000000..55d690e3
--- /dev/null
+++ b/src/safe_op.hpp
@@ -0,0 +1,310 @@
@@ -0,0 +1,308 @@
+// ********************************************************* -*- C++ -*-
+/*
+ * Copyright (C) 2004-2017 Exiv2 maintainers
@ -318,7 +251,6 @@ index 0000000..014b7f3
+ };
+
+#if defined(__GNUC__) || defined(__clang__)
+#if __GNUC__ >= 5
+
+/*!
+ * This macro pastes a specialization of builtin_add_overflow using gcc's &
@ -349,7 +281,6 @@ index 0000000..014b7f3
+ SPECIALIZE_builtin_add_overflow(unsigned long long, __builtin_uaddll_overflow);
+
+#undef SPECIALIZE_builtin_add_overflow
+#endif
+
+#elif defined(_MSC_VER)
+

344
exiv2-CVE-2018-10958.patch Normal file
View File

@ -0,0 +1,344 @@
diff --git a/include/exiv2/error.hpp b/include/exiv2/error.hpp
index 24a70bf6..cc67725b 100644
--- a/include/exiv2/error.hpp
+++ b/include/exiv2/error.hpp
@@ -192,6 +192,74 @@ namespace Exiv2 {
return os << error.what();
}
+ //! Complete list of all Exiv2 error codes
+ enum ErrorCode {
+ kerGeneralError = -1,
+ kerSuccess = 0,
+ kerErrorMessage,
+ kerCallFailed,
+ kerNotAnImage,
+ kerInvalidDataset,
+ kerInvalidRecord,
+ kerInvalidKey,
+ kerInvalidTag,
+ kerValueNotSet,
+ kerDataSourceOpenFailed,
+ kerFileOpenFailed,
+ kerFileContainsUnknownImageType,
+ kerMemoryContainsUnknownImageType,
+ kerUnsupportedImageType,
+ kerFailedToReadImageData,
+ kerNotAJpeg,
+ kerFailedToMapFileForReadWrite,
+ kerFileRenameFailed,
+ kerTransferFailed,
+ kerMemoryTransferFailed,
+ kerInputDataReadFailed,
+ kerImageWriteFailed,
+ kerNoImageInInputData,
+ kerInvalidIfdId,
+ //! Entry::setValue: Value too large
+ kerValueTooLarge,
+ //! Entry::setDataArea: Value too large
+ kerDataAreaValueTooLarge,
+ kerOffsetOutOfRange,
+ kerUnsupportedDataAreaOffsetType,
+ kerInvalidCharset,
+ kerUnsupportedDateFormat,
+ kerUnsupportedTimeFormat,
+ kerWritingImageFormatUnsupported,
+ kerInvalidSettingForImage,
+ kerNotACrwImage,
+ kerFunctionNotSupported,
+ kerNoNamespaceInfoForXmpPrefix,
+ kerNoPrefixForNamespace,
+ kerTooLargeJpegSegment,
+ kerUnhandledXmpdatum,
+ kerUnhandledXmpNode,
+ kerXMPToolkitError,
+ kerDecodeLangAltPropertyFailed,
+ kerDecodeLangAltQualifierFailed,
+ kerEncodeLangAltPropertyFailed,
+ kerPropertyNameIdentificationFailed,
+ kerSchemaNamespaceNotRegistered,
+ kerNoNamespaceForPrefix,
+ kerAliasesNotSupported,
+ kerInvalidXmpText,
+ kerTooManyTiffDirectoryEntries,
+ kerMultipleTiffArrayElementTagsInDirectory,
+ kerWrongTiffArrayElementTagType,
+ kerInvalidKeyXmpValue,
+ kerInvalidIccProfile,
+ kerInvalidXMP,
+ kerTiffDirectoryTooLarge,
+ kerInvalidTypeValue,
+ kerInvalidMalloc,
+ kerCorruptedMetadata,
+ kerArithmeticOverflow,
+ kerMallocFailed,
+ };
+
/*!
@brief Simple error class used for exceptions. An output operator is
provided to print errors to a stream.
diff --git a/src/enforce.hpp b/src/enforce.hpp
new file mode 100644
index 00000000..b2d77eea
--- /dev/null
+++ b/src/enforce.hpp
@@ -0,0 +1,96 @@
+// ********************************************************* -*- C++ -*-
+/*
+ * Copyright (C) 2004-2018 Exiv2 maintainers
+ *
+ * This program is part of the Exiv2 distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA.
+ */
+/*!
+ @file enforce.hpp
+ @brief Port of D's enforce() to C++ & Exiv2
+ @author Dan Čermák (D4N)
+ <a href="mailto:dan.cermak@cgc-instruments.com">dan.cermak@cgc-instruments.com</a>
+ @date 11-March-18, D4N: created
+ */
+
+#include <string>
+
+#include "error.hpp"
+
+/*!
+ * @brief Ensure that condition is true, otherwise throw an exception of the
+ * type exception_t
+ *
+ * @tparam exception_t Exception type that is thrown, must provide a
+ * constructor that accepts a single argument to which arg1 is forwarded.
+ *
+ * @todo once we have C++>=11 use variadic templates and std::forward to remove
+ * all overloads of enforce
+ */
+template <typename exception_t, typename T>
+inline void enforce(bool condition, const T& arg1)
+{
+ if (!condition) {
+ throw exception_t(arg1);
+ }
+}
+
+/*!
+ * @brief Ensure that condition is true, otherwise throw an Exiv2::Error with
+ * the given error_code.
+ */
+inline void enforce(bool condition, Exiv2::ErrorCode err_code)
+{
+ if (!condition) {
+ throw Exiv2::Error(err_code);
+ }
+}
+
+/*!
+ * @brief Ensure that condition is true, otherwise throw an Exiv2::Error with
+ * the given error_code & arg1.
+ */
+template <typename T>
+inline void enforce(bool condition, Exiv2::ErrorCode err_code, const T& arg1)
+{
+ if (!condition) {
+ throw Exiv2::Error(err_code, arg1);
+ }
+}
+
+/*!
+ * @brief Ensure that condition is true, otherwise throw an Exiv2::Error with
+ * the given error_code, arg1 & arg2.
+ */
+template <typename T, typename U>
+inline void enforce(bool condition, Exiv2::ErrorCode err_code, const T& arg1, const U& arg2)
+{
+ if (!condition) {
+ throw Exiv2::Error(err_code, arg1, arg2);
+ }
+}
+
+/*!
+ * @brief Ensure that condition is true, otherwise throw an Exiv2::Error with
+ * the given error_code, arg1, arg2 & arg3.
+ */
+template <typename T, typename U, typename V>
+inline void enforce(bool condition, Exiv2::ErrorCode err_code, const T& arg1, const U& arg2, const V& arg3)
+{
+ if (!condition) {
+ throw Exiv2::Error(err_code, arg1, arg2, arg3);
+ }
+}
diff --git a/src/pngchunk.cpp b/src/pngchunk.cpp
index 4dcca4d..aae0f5f 100644
--- a/src/pngchunk.cpp
+++ b/src/pngchunk.cpp
@@ -37,6 +37,7 @@ EXIV2_RCSID("@(#) $Id$")
#include "iptc.hpp"
#include "image.hpp"
#include "error.hpp"
+#include "enforce.hpp"
// + standard includes
#include <sstream>
@@ -46,6 +47,7 @@ EXIV2_RCSID("@(#) $Id$")
#include <iostream>
#include <cassert>
#include <cstdio>
+#include <algorithm>
#include <zlib.h> // To uncompress or compress text chunk
@@ -86,7 +88,7 @@ namespace Exiv2 {
#ifdef DEBUG
std::cout << "Exiv2::PngChunk::decodeTXTChunk: TXT chunk data: "
- << std::string((const char*)arr.pData_, arr.size_) << "\n";
+ << std::string((const char*)arr.pData_, arr.size_) << std::endl;
#endif
parseChunkContent(pImage, key.pData_, key.size_, arr);
@@ -99,7 +101,7 @@ namespace Exiv2 {
#ifdef DEBUG
std::cout << "Exiv2::PngChunk::decodeTXTChunk: TXT chunk key: "
- << std::string((const char*)key.pData_, key.size_) << "\n";
+ << std::string((const char*)key.pData_, key.size_) << std::endl;
#endif
return parseTXTChunk(data, key.size_, type);
@@ -164,12 +166,18 @@ namespace Exiv2 {
}
else if(type == iTXt_Chunk)
{
+ const int nullSeparators = std::count(&data.pData_[keysize+3], &data.pData_[data.size_], '\0');
+
+ enforce(nullSeparators >= 2, Exiv2::kerCorruptedMetadata);
+
// Extract a deflate compressed or uncompressed UTF-8 text chunk
// we get the compression flag after the key
- const byte* compressionFlag = data.pData_ + keysize + 1;
+ const byte compressionFlag = data.pData_[keysize + 1];
// we get the compression method after the compression flag
- const byte* compressionMethod = data.pData_ + keysize + 2;
+ const byte compressionMethod = data.pData_[keysize + 2];
+ enforce(compressionFlag == 0x00 || compressionFlag == 0x01, Exiv2::kerCorruptedMetadata);
+ enforce(compressionMethod == 0x00, Exiv2::kerCorruptedMetadata);
// language description string after the compression technique spec
std::string languageText((const char*)(data.pData_ + keysize + 3));
unsigned int languageTextSize = static_cast<unsigned int>(languageText.size());
@@ -177,7 +185,7 @@ namespace Exiv2 {
std::string translatedKeyText((const char*)(data.pData_ + keysize + 3 + languageTextSize +1));
unsigned int translatedKeyTextSize = static_cast<unsigned int>(translatedKeyText.size());
- if ( compressionFlag[0] == 0x00 )
+ if ( compressionFlag == 0x00 )
{
// then it's an uncompressed iTXt chunk
#ifdef DEBUG
@@ -191,7 +199,7 @@ namespace Exiv2 {
arr.alloc(textsize);
arr = DataBuf(text, textsize);
}
- else if ( compressionFlag[0] == 0x01 && compressionMethod[0] == 0x00 )
+ else if ( compressionFlag == 0x01 && compressionMethod == 0x00 )
{
// then it's a zlib compressed iTXt chunk
#ifdef DEBUG
diff --git a/src/pngimage.cpp b/src/pngimage.cpp
index ed7399a..991da6c 100644
--- a/src/pngimage.cpp
+++ b/src/pngimage.cpp
@@ -375,7 +375,7 @@ namespace Exiv2 {
void PngImage::readMetadata()
{
#ifdef DEBUG
- std::cerr << "Exiv2::PngImage::readMetadata: Reading PNG file " << io_->path() << "\n";
+ std::cerr << "Exiv2::PngImage::readMetadata: Reading PNG file " << io_->path() << std::endl;
#endif
if (io_->open() != 0)
{
@@ -398,7 +398,7 @@ namespace Exiv2 {
// Read chunk header.
#ifdef DEBUG
- std::cout << "Exiv2::PngImage::readMetadata: Position: " << io_->tell() << "\n";
+ std::cout << "Exiv2::PngImage::readMetadata: Position: " << io_->tell() << std::endl;
#endif
std::memset(cheaderBuf.pData_, 0x0, cheaderBuf.size_);
long bufRead = io_->read(cheaderBuf.pData_, cheaderBuf.size_);
@@ -432,14 +432,14 @@ namespace Exiv2 {
{
// Last chunk found: we stop parsing.
#ifdef DEBUG
- std::cout << "Exiv2::PngImage::readMetadata: Found IEND chunk (length: " << dataOffset << ")\n";
+ std::cout << "Exiv2::PngImage::readMetadata: Found IEND chunk with length: " << dataOffset << std::endl;
#endif
return;
}
else if (!memcmp(cheaderBuf.pData_ + 4, "IHDR", 4))
{
#ifdef DEBUG
- std::cout << "Exiv2::PngImage::readMetadata: Found IHDR chunk (length: " << dataOffset << ")\n";
+ std::cout << "Exiv2::PngImage::readMetadata: Found IHDR chunk with length: " << dataOffset << std::endl;
#endif
if (cdataBuf.size_ >= 8) {
PngChunk::decodeIHDRChunk(cdataBuf, &pixelWidth_, &pixelHeight_);
@@ -448,21 +448,21 @@ namespace Exiv2 {
else if (!memcmp(cheaderBuf.pData_ + 4, "tEXt", 4))
{
#ifdef DEBUG
- std::cout << "Exiv2::PngImage::readMetadata: Found tEXt chunk (length: " << dataOffset << ")\n";
+ std::cout << "Exiv2::PngImage::readMetadata: Found tEXt chunk with length: " << dataOffset << std::endl;
#endif
PngChunk::decodeTXTChunk(this, cdataBuf, PngChunk::tEXt_Chunk);
}
else if (!memcmp(cheaderBuf.pData_ + 4, "zTXt", 4))
{
#ifdef DEBUG
- std::cout << "Exiv2::PngImage::readMetadata: Found zTXt chunk (length: " << dataOffset << ")\n";
+ std::cout << "Exiv2::PngImage::readMetadata: Found zTXt chunk with length: " << dataOffset << std::endl;
#endif
PngChunk::decodeTXTChunk(this, cdataBuf, PngChunk::zTXt_Chunk);
}
else if (!memcmp(cheaderBuf.pData_ + 4, "iTXt", 4))
{
#ifdef DEBUG
- std::cout << "Exiv2::PngImage::readMetadata: Found iTXt chunk (length: " << dataOffset << ")\n";
+ std::cout << "Exiv2::PngImage::readMetadata: Found iTXt chunk with length: " << dataOffset << std::endl;
#endif
PngChunk::decodeTXTChunk(this, cdataBuf, PngChunk::iTXt_Chunk);
}
@@ -481,7 +481,7 @@ namespace Exiv2 {
// Move to the next chunk: chunk data size + 4 CRC bytes.
#ifdef DEBUG
- std::cout << "Exiv2::PngImage::readMetadata: Seek to offset: " << dataOffset + 4 << "\n";
+ std::cout << "Exiv2::PngImage::readMetadata: Seek to offset: " << dataOffset + 4 << std::endl;
#endif
io_->seek(dataOffset + 4 , BasicIo::cur);
if (io_->error() || io_->eof()) throw Error(14);
@@ -511,8 +511,8 @@ namespace Exiv2 {
if (!outIo.isopen()) throw Error(21);
#ifdef DEBUG
- std::cout << "Exiv2::PngImage::doWriteMetadata: Writing PNG file " << io_->path() << "\n";
- std::cout << "Exiv2::PngImage::doWriteMetadata: tmp file created " << outIo.path() << "\n";
+ std::cout << "Exiv2::PngImage::doWriteMetadata: Writing PNG file " << io_->path() << std::endl;
+ std::cout << "Exiv2::PngImage::doWriteMetadata: tmp file created " << outIo.path() << std::endl;
#endif
// Ensure that this is the correct image type

View File

@ -0,0 +1,61 @@
diff --git a/src/exiv2.cpp b/src/exiv2.cpp
index d6a45e1..dbd2834 100644
--- a/src/exiv2.cpp
+++ b/src/exiv2.cpp
@@ -150,31 +150,35 @@ int main(int argc, char* const argv[])
return 0;
}
- // Create the required action class
- Action::TaskFactory& taskFactory = Action::TaskFactory::instance();
- Action::Task::AutoPtr task
- = taskFactory.create(Action::TaskType(params.action_));
- assert(task.get());
-
- // Process all files
int rc = 0;
- int n = 1;
- int s = static_cast<int>(params.files_.size());
- int w = s > 9 ? s > 99 ? 3 : 2 : 1;
- for (Params::Files::const_iterator i = params.files_.begin();
- i != params.files_.end(); ++i) {
- if (params.verbose_) {
- std::cout << _("File") << " " << std::setw(w) << std::right << n++ << "/" << s << ": "
- << *i << std::endl;
+ try {
+ // Create the required action class
+ Action::TaskFactory& taskFactory = Action::TaskFactory::instance();
+ Action::Task::AutoPtr task = taskFactory.create(Action::TaskType(params.action_));
+ assert(task.get());
+
+ // Process all files
+ int n = 1;
+ int s = static_cast<int>(params.files_.size());
+ int w = s > 9 ? s > 99 ? 3 : 2 : 1;
+ for (Params::Files::const_iterator i = params.files_.begin(); i != params.files_.end(); ++i) {
+ if (params.verbose_) {
+ std::cout << _("File") << " " << std::setw(w) << std::right << n++ << "/" << s << ": " << *i
+ << std::endl;
+ }
+ int ret = task->run(*i);
+ if (rc == 0)
+ rc = ret;
}
- int ret = task->run(*i);
- if (rc == 0) rc = ret;
- }
- taskFactory.cleanup();
- params.cleanup();
- Exiv2::XmpParser::terminate();
+ taskFactory.cleanup();
+ params.cleanup();
+ Exiv2::XmpParser::terminate();
+ } catch (const std::exception& exc) {
+ std::cerr << "Uncaught exception: " << exc.what() << std::endl;
+ rc = 1;
+ }
// Return a positive one byte code for better consistency across platforms
return static_cast<unsigned int>(rc) % 256;
} // main

View File

@ -0,0 +1,31 @@
diff --git a/src/preview.cpp b/src/preview.cpp
index c34c8bd..69f8e01 100644
--- a/src/preview.cpp
+++ b/src/preview.cpp
@@ -36,6 +36,7 @@ EXIV2_RCSID("@(#) $Id$")
#include "preview.hpp"
#include "futils.hpp"
+#include "enforce.hpp"
#include "image.hpp"
#include "cr2image.hpp"
@@ -807,13 +808,14 @@ namespace {
else {
// FIXME: the buffer is probably copied twice, it should be optimized
DataBuf buf(size_);
- Exiv2::byte* pos = buf.pData_;
+ uint32_t idxBuf = 0;
for (int i = 0; i < sizes.count(); i++) {
uint32_t offset = dataValue.toLong(i);
uint32_t size = sizes.toLong(i);
- if (offset + size <= static_cast<uint32_t>(io.size()))
- memcpy(pos, base + offset, size);
- pos += size;
+ enforce(idxBuf + size < size_, kerCorruptedMetadata);
+ if (size!=0 && offset + size <= static_cast<uint32_t>(io.size()))
+ memcpy(&buf.pData_[idxBuf], base + offset, size);
+ idxBuf += size;
}
dataValue.setDataArea(buf.pData_, buf.size_);
}

View File

@ -0,0 +1,60 @@
diff --git a/src/preview.cpp b/src/preview.cpp
index 69f8e01..d20de04 100644
--- a/src/preview.cpp
+++ b/src/preview.cpp
@@ -37,6 +37,7 @@ EXIV2_RCSID("@(#) $Id$")
#include "preview.hpp"
#include "futils.hpp"
#include "enforce.hpp"
+#include "safe_op.hpp"
#include "image.hpp"
#include "cr2image.hpp"
@@ -386,7 +387,7 @@ namespace {
return AutoPtr();
if (loaderList_[id].imageMimeType_ &&
- std::string(loaderList_[id].imageMimeType_) != std::string(image.mimeType()))
+ std::string(loaderList_[id].imageMimeType_) != image.mimeType())
return AutoPtr();
AutoPtr loader = loaderList_[id].create_(id, image, loaderList_[id].parIdx_);
@@ -548,7 +549,8 @@ namespace {
}
}
- if (offset_ + size_ > static_cast<uint32_t>(image_.io().size())) return;
+ if (Safe::add(offset_, size_) > static_cast<uint32_t>(image_.io().size()))
+ return;
valid_ = true;
}
@@ -802,7 +804,7 @@ namespace {
// this saves one copying of the buffer
uint32_t offset = dataValue.toLong(0);
uint32_t size = sizes.toLong(0);
- if (offset + size <= static_cast<uint32_t>(io.size()))
+ if (Safe::add(offset, size) <= static_cast<uint32_t>(io.size()))
dataValue.setDataArea(base + offset, size);
}
else {
@@ -812,8 +814,8 @@ namespace {
for (int i = 0; i < sizes.count(); i++) {
uint32_t offset = dataValue.toLong(i);
uint32_t size = sizes.toLong(i);
- enforce(idxBuf + size < size_, kerCorruptedMetadata);
- if (size!=0 && offset + size <= static_cast<uint32_t>(io.size()))
+ enforce(Safe::add(idxBuf, size) < size_, kerCorruptedMetadata);
+ if (size!=0 && Safe::add(offset, size) <= static_cast<uint32_t>(io.size()))
memcpy(&buf.pData_[idxBuf], base + offset, size);
idxBuf += size;
}
@@ -930,7 +932,7 @@ namespace {
DataBuf decodeBase64(const std::string& src)
{
- const unsigned long srcSize = static_cast<const unsigned long>(src.size());
+ const unsigned long srcSize = src.size();
// create decoding table
unsigned long invalid = 64;

View File

@ -0,0 +1,49 @@
diff --git a/src/webpimage.cpp b/src/webpimage.cpp
index e4057d6..f1dd77c 100644
--- a/src/webpimage.cpp
+++ b/src/webpimage.cpp
@@ -44,6 +44,8 @@
#include "tiffimage.hpp"
#include "tiffimage_int.hpp"
#include "convert.hpp"
+#include "enforce.hpp"
+
#include <cmath>
#include <iomanip>
#include <string>
@@ -516,6 +518,8 @@ namespace Exiv2 {
DataBuf payload(size);
if (equalsWebPTag(chunkId, WEBP_CHUNK_HEADER_VP8X) && !has_canvas_data) {
+ enforce(size >= 10, Exiv2::kerCorruptedMetadata);
+
has_canvas_data = true;
byte size_buf[WEBP_TAG_SIZE];
@@ -531,6 +535,8 @@ namespace Exiv2 {
size_buf[3] = 0;
pixelHeight_ = Exiv2::getULong(size_buf, littleEndian) + 1;
} else if (equalsWebPTag(chunkId, WEBP_CHUNK_HEADER_VP8) && !has_canvas_data) {
+ enforce(size >= 10, Exiv2::kerCorruptedMetadata);
+
has_canvas_data = true;
io_->read(payload.pData_, payload.size_);
byte size_buf[WEBP_TAG_SIZE];
@@ -547,6 +553,8 @@ namespace Exiv2 {
size_buf[3] = 0;
pixelHeight_ = Exiv2::getULong(size_buf, littleEndian) & 0x3fff;
} else if (equalsWebPTag(chunkId, WEBP_CHUNK_HEADER_VP8L) && !has_canvas_data) {
+ enforce(size >= 5, Exiv2::kerCorruptedMetadata);
+
has_canvas_data = true;
byte size_buf_w[2];
byte size_buf_h[3];
@@ -564,6 +572,8 @@ namespace Exiv2 {
size_buf_h[1] = ((size_buf_h[1] >> 6) & 0x3) | ((size_buf_h[2] & 0xF) << 0x2);
pixelHeight_ = Exiv2::getUShort(size_buf_h, littleEndian) + 1;
} else if (equalsWebPTag(chunkId, WEBP_CHUNK_HEADER_ANMF) && !has_canvas_data) {
+ enforce(size >= 12, Exiv2::kerCorruptedMetadata);
+
has_canvas_data = true;
byte size_buf[WEBP_TAG_SIZE];

View File

@ -1,5 +1,5 @@
diff --git a/src/cr2image.cpp b/src/cr2image.cpp
index 516e170..8a752b0 100644
index 2907426..b6fa315 100644
--- a/src/cr2image.cpp
+++ b/src/cr2image.cpp
@@ -107,8 +107,6 @@ namespace Exiv2 {
@ -12,7 +12,7 @@ index 516e170..8a752b0 100644
iptcData_,
xmpData_,
diff --git a/src/crwimage.cpp b/src/crwimage.cpp
index 232919c..58240fd 100644
index ca79aa7..11cd14c 100644
--- a/src/crwimage.cpp
+++ b/src/crwimage.cpp
@@ -131,15 +131,8 @@ namespace Exiv2 {
@ -34,7 +34,7 @@ index 232919c..58240fd 100644
CrwParser::decode(this, io_->mmap(), io_->size());
diff --git a/src/orfimage.cpp b/src/orfimage.cpp
index 25651bd..9bd7a02 100644
index c516591..9a17a50 100644
--- a/src/orfimage.cpp
+++ b/src/orfimage.cpp
@@ -119,8 +119,6 @@ namespace Exiv2 {
@ -47,7 +47,7 @@ index 25651bd..9bd7a02 100644
iptcData_,
xmpData_,
diff --git a/src/rw2image.cpp b/src/rw2image.cpp
index 07de437..5922602 100644
index 95f3b28..764de6f 100644
--- a/src/rw2image.cpp
+++ b/src/rw2image.cpp
@@ -130,8 +130,6 @@ namespace Exiv2 {
@ -60,7 +60,7 @@ index 07de437..5922602 100644
iptcData_,
xmpData_,
diff --git a/src/tiffimage.cpp b/src/tiffimage.cpp
index de66068..98da12b 100644
index f20c69e..9e6eda4 100644
--- a/src/tiffimage.cpp
+++ b/src/tiffimage.cpp
@@ -185,10 +185,6 @@ namespace Exiv2 {
@ -74,12 +74,3 @@ index de66068..98da12b 100644
ByteOrder bo = TiffParser::decode(exifData_,
iptcData_,
xmpData_,
@@ -200,7 +196,7 @@ namespace Exiv2 {
Exiv2::ExifKey key("Exif.Image.InterColorProfile");
Exiv2::ExifData::iterator pos = exifData_.findKey(key);
if ( pos != exifData_.end() ) {
- iccProfile_.alloc(pos->count());
+ iccProfile_.alloc(pos->count()*pos->typeSize());
pos->copy(iccProfile_.pData_,bo);
}

466
exiv2-CVE-2018-8976.patch Normal file
View File

@ -0,0 +1,466 @@
diff --git a/src/jpgimage.cpp b/src/jpgimage.cpp
index 9afcb58..ca83f14 100644
--- a/src/jpgimage.cpp
+++ b/src/jpgimage.cpp
@@ -34,6 +34,7 @@ EXIV2_RCSID("@(#) $Id$")
#include "image_int.hpp"
#include "error.hpp"
#include "futils.hpp"
+#include "enforce.hpp"
#ifdef WIN32
#include <windows.h>
@@ -328,12 +329,14 @@ namespace Exiv2 {
int c = -1;
// Skips potential padding between markers
while ((c=io_->getb()) != 0xff) {
- if (c == EOF) return -1;
+ if (c == EOF)
+ return -1;
}
// Markers can start with any number of 0xff
while ((c=io_->getb()) == 0xff) {
- if (c == EOF) return -2;
+ if (c == EOF)
+ return -2;
}
return c;
}
@@ -564,85 +567,88 @@ namespace Exiv2 {
out << Internal::stringFormat("%8ld | 0xff%02x %-5s", \
io_->tell()-2,marker,nm[marker].c_str())
- void JpegBase::printStructure(std::ostream& out, PrintStructureOption option,int depth)
+ void JpegBase::printStructure(std::ostream& out, PrintStructureOption option, int depth)
{
- if (io_->open() != 0) throw Error(9, io_->path(), strError());
+ if (io_->open() != 0)
+ throw Error(9, io_->path(), strError());
// Ensure that this is the correct image type
if (!isThisType(*io_, false)) {
- if (io_->error() || io_->eof()) throw Error(14);
+ if (io_->error() || io_->eof())
+ throw Error(14);
throw Error(15);
}
- bool bPrint = option==kpsBasic || option==kpsRecursive;
+ bool bPrint = option == kpsBasic || option == kpsRecursive;
Exiv2::Uint32Vector iptcDataSegs;
- if ( bPrint || option == kpsXMP || option == kpsIccProfile || option == kpsIptcErase ) {
+ if (bPrint || option == kpsXMP || option == kpsIccProfile || option == kpsIptcErase) {
// nmonic for markers
- std::string nm[256] ;
- nm[0xd8]="SOI" ;
- nm[0xd9]="EOI" ;
- nm[0xda]="SOS" ;
- nm[0xdb]="DQT" ;
- nm[0xdd]="DRI" ;
- nm[0xfe]="COM" ;
+ std::string nm[256];
+ nm[0xd8] = "SOI";
+ nm[0xd9] = "EOI";
+ nm[0xda] = "SOS";
+ nm[0xdb] = "DQT";
+ nm[0xdd] = "DRI";
+ nm[0xfe] = "COM";
// 0xe0 .. 0xef are APPn
// 0xc0 .. 0xcf are SOFn (except 4)
- nm[0xc4]="DHT" ;
- for ( int i = 0 ; i <= 15 ; i++ ) {
+ nm[0xc4] = "DHT";
+ for (int i = 0; i <= 15; i++) {
char MN[10];
- sprintf(MN,"APP%d",i);
- nm[0xe0+i] = MN;
- if ( i != 4 ) {
- sprintf(MN,"SOF%d",i);
- nm[0xc0+i] = MN;
+ sprintf(MN, "APP%d", i);
+ nm[0xe0 + i] = MN;
+ if (i != 4) {
+ sprintf(MN, "SOF%d", i);
+ nm[0xc0 + i] = MN;
}
}
// which markers have a length field?
bool mHasLength[256];
- for ( int i = 0 ; i < 256 ; i ++ )
- mHasLength[i]
- = ( i >= sof0_ && i <= sof15_)
- || ( i >= app0_ && i <= (app0_ | 0x0F))
- || ( i == dht_ || i == dqt_ || i == dri_ || i == com_ || i == sos_ )
- ;
+ for (int i = 0; i < 256; i++)
+ mHasLength[i] = (i >= sof0_ && i <= sof15_) || (i >= app0_ && i <= (app0_ | 0x0F)) ||
+ (i == dht_ || i == dqt_ || i == dri_ || i == com_ || i == sos_);
// Container for the signature
- bool bExtXMP = false;
- long bufRead = 0;
- const long bufMinSize = 36;
- DataBuf buf(bufMinSize);
+ bool bExtXMP = false;
+ long bufRead = 0;
+ const long bufMinSize = 36;
+ DataBuf buf(bufMinSize);
// Read section marker
int marker = advanceToMarker();
- if (marker < 0) throw Error(15);
+ if (marker < 0)
+ throw Error(15);
- bool done = false;
- bool first= true;
+ bool done = false;
+ bool first = true;
while (!done) {
// print marker bytes
- if ( first && bPrint ) {
+ if (first && bPrint) {
out << "STRUCTURE OF JPEG FILE: " << io_->path() << std::endl;
- out << " address | marker | length | data" << std::endl ;
+ out << " address | marker | length | data" << std::endl;
REPORT_MARKER;
}
- first = false;
+ first = false;
bool bLF = bPrint;
// Read size and signature
std::memset(buf.pData_, 0x0, buf.size_);
bufRead = io_->read(buf.pData_, bufMinSize);
- if (io_->error()) throw Error(14);
- if (bufRead < 2) throw Error(15);
- uint16_t size = mHasLength[marker] ? getUShort(buf.pData_, bigEndian) : 0 ;
- if ( bPrint && mHasLength[marker] ) out << Internal::stringFormat(" | %7d ", size);
+ if (io_->error())
+ throw Error(14);
+ if (bufRead < 2)
+ throw Error(15);
+ uint16_t size = mHasLength[marker] ? getUShort(buf.pData_, bigEndian) : 0;
+ if (bPrint && mHasLength[marker])
+ out << Internal::stringFormat(" | %7d ", size);
// print signature for APPn
if (marker >= app0_ && marker <= (app0_ | 0x0F)) {
// http://www.adobe.com/content/dam/Adobe/en/devnet/xmp/pdfs/XMPSpecificationPart3.pdf p75
- const char* signature = (const char*) buf.pData_+2;
+ const char* signature = (const char*)buf.pData_ + 2;
// 728 rmills@rmillsmbp:~/gnu/exiv2/ttt $ exiv2 -pS test/data/exiv2-bug922.jpg
// STRUCTURE OF JPEG FILE: test/data/exiv2-bug922.jpg
@@ -651,13 +657,13 @@ namespace Exiv2 {
// 2 | 0xe1 APP1 | 911 | Exif..MM.*.......%.........#....
// 915 | 0xe1 APP1 | 870 | http://ns.adobe.com/xap/1.0/.<x:
// 1787 | 0xe1 APP1 | 65460 | http://ns.adobe.com/xmp/extensio
- if ( option == kpsXMP && std::string(signature).find("http://ns.adobe.com/x")== 0 ) {
+ if (option == kpsXMP && std::string(signature).find("http://ns.adobe.com/x") == 0) {
// extract XMP
- if ( size > 0 ) {
- io_->seek(-bufRead , BasicIo::cur);
- byte* xmp = new byte[size+1];
- io_->read(xmp,size);
- int start = 0 ;
+ if (size > 0) {
+ io_->seek(-bufRead, BasicIo::cur);
+ byte* xmp = new byte[size + 1];
+ io_->read(xmp, size);
+ int start = 0;
// http://wwwimages.adobe.com/content/dam/Adobe/en/devnet/xmp/pdfs/XMPSpecificationPart3.pdf
// if we find HasExtendedXMP, set the flag and ignore this block
@@ -666,79 +672,80 @@ namespace Exiv2 {
// we could implement out of sequence with a dictionary of sequence/offset
// and dumping the XMP in a post read operation similar to kpsIptcErase
// for the moment, dumping 'on the fly' is working fine
- if ( ! bExtXMP ) {
- while (xmp[start]) start++;
+ if (!bExtXMP) {
+ while (xmp[start])
+ start++;
start++;
- if ( ::strstr((char*)xmp+start,"HasExtendedXMP") ) {
- start = size ; // ignore this packet, we'll get on the next time around
+ if (::strstr((char*)xmp + start, "HasExtendedXMP")) {
+ start = size; // ignore this packet, we'll get on the next time around
bExtXMP = true;
}
} else {
- start = 2+35+32+4+4; // Adobe Spec, p19
+ start = 2 + 35 + 32 + 4 + 4; // Adobe Spec, p19
}
- out.write((const char*)(xmp+start),size-start);
- delete [] xmp;
+ out.write((const char*)(xmp + start), size - start);
+ delete[] xmp;
bufRead = size;
done = !bExtXMP;
}
- } else if ( option == kpsIccProfile && std::strcmp(signature,iccId_) == 0 ) {
+ } else if (option == kpsIccProfile && std::strcmp(signature, iccId_) == 0) {
// extract ICCProfile
- if ( size > 0 ) {
- io_->seek(-bufRead, BasicIo::cur); // back to buffer (after marker)
- io_->seek( 14+2, BasicIo::cur); // step over header
- DataBuf icc(size-(14+2));
- io_->read( icc.pData_,icc.size_);
- out.write((const char*)icc.pData_,icc.size_);
+ if (size > 0) {
+ io_->seek(-bufRead, BasicIo::cur); // back to buffer (after marker)
+ io_->seek(14 + 2, BasicIo::cur); // step over header
+ DataBuf icc(size - (14 + 2));
+ io_->read(icc.pData_, icc.size_);
+ out.write((const char*)icc.pData_, icc.size_);
#ifdef DEBUG
std::cout << "iccProfile size = " << icc.size_ << std::endl;
#endif
bufRead = size;
}
- } else if ( option == kpsIptcErase && std::strcmp(signature,"Photoshop 3.0") == 0 ) {
+ } else if (option == kpsIptcErase && std::strcmp(signature, "Photoshop 3.0") == 0) {
// delete IPTC data segment from JPEG
- if ( size > 0 ) {
- io_->seek(-bufRead , BasicIo::cur);
+ if (size > 0) {
+ io_->seek(-bufRead, BasicIo::cur);
iptcDataSegs.push_back(io_->tell());
iptcDataSegs.push_back(size);
}
- } else if ( bPrint ) {
- out << "| " << Internal::binaryToString(buf,size>32?32:size,size>0?2:0);
- if ( std::strcmp(signature,iccId_) == 0 ) {
- int chunk = (int) signature[12];
- int chunks = (int) signature[13];
- out << Internal::stringFormat(" chunk %d/%d",chunk,chunks);
+ } else if (bPrint) {
+ out << "| " << Internal::binaryToString(buf, size > 32 ? 32 : size, size > 0 ? 2 : 0);
+ if (std::strcmp(signature, iccId_) == 0) {
+ int chunk = (int)signature[12];
+ int chunks = (int)signature[13];
+ out << Internal::stringFormat(" chunk %d/%d", chunk, chunks);
}
}
// for MPF: http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/MPF.html
// for FLIR: http://owl.phy.queensu.ca/~phil/exiftool/TagNames/FLIR.html
- bool bFlir = option == kpsRecursive && marker == (app0_+1) && std::strcmp(signature,"FLIR")==0;
- bool bExif = option == kpsRecursive && marker == (app0_+1) && std::strcmp(signature,"Exif")==0;
- bool bMPF = option == kpsRecursive && marker == (app0_+2) && std::strcmp(signature,"MPF")==0;
- bool bPS = option == kpsRecursive && std::strcmp(signature,"Photoshop 3.0")==0;
- if( bFlir || bExif || bMPF || bPS ) {
+ bool bFlir = option == kpsRecursive && marker == (app0_ + 1) && std::strcmp(signature, "FLIR") == 0;
+ bool bExif = option == kpsRecursive && marker == (app0_ + 1) && std::strcmp(signature, "Exif") == 0;
+ bool bMPF = option == kpsRecursive && marker == (app0_ + 2) && std::strcmp(signature, "MPF") == 0;
+ bool bPS = option == kpsRecursive && std::strcmp(signature, "Photoshop 3.0") == 0;
+ if (bFlir || bExif || bMPF || bPS) {
// extract Exif data block which is tiff formatted
- if ( size > 0 ) {
+ if (size > 0) {
out << std::endl;
// allocate storage and current file position
- byte* exif = new byte[size];
- uint32_t restore = io_->tell();
+ byte* exif = new byte[size];
+ uint32_t restore = io_->tell();
// copy the data to memory
- io_->seek(-bufRead , BasicIo::cur);
- io_->read(exif,size);
- uint32_t start = std::strcmp(signature,"Exif")==0 ? 8 : 6;
- uint32_t max = (uint32_t) size -1;
+ io_->seek(-bufRead, BasicIo::cur);
+ io_->read(exif, size);
+ uint32_t start = std::strcmp(signature, "Exif") == 0 ? 8 : 6;
+ uint32_t max = (uint32_t)size - 1;
// is this an fff block?
- if ( bFlir ) {
- start = 0 ;
+ if (bFlir) {
+ start = 0;
bFlir = false;
- while ( start < max ) {
- if ( std::strcmp((const char*)(exif+start),"FFF")==0 ) {
- bFlir = true ;
+ while (start < max) {
+ if (std::strcmp((const char*)(exif + start), "FFF") == 0) {
+ bFlir = true;
break;
}
start++;
@@ -747,78 +754,90 @@ namespace Exiv2 {
// there is a header in FLIR, followed by a tiff block
// Hunt down the tiff using brute force
- if ( bFlir ) {
+ if (bFlir) {
// FLIRFILEHEAD* pFFF = (FLIRFILEHEAD*) (exif+start) ;
- while ( start < max ) {
- if ( exif[start] == 'I' && exif[start+1] == 'I' ) break;
- if ( exif[start] == 'M' && exif[start+1] == 'M' ) break;
+ while (start < max) {
+ if (exif[start] == 'I' && exif[start + 1] == 'I')
+ break;
+ if (exif[start] == 'M' && exif[start + 1] == 'M')
+ break;
start++;
}
- if ( start < max ) std::cout << " FFF start = " << start << std::endl ;
+ if ( start < max )
+ std::cout << " FFF start = " << start << std::endl;
// << " index = " << pFFF->dwIndexOff << std::endl;
}
- if ( bPS ) {
- IptcData::printStructure(out,exif,size,depth);
+ if (bPS) {
+ IptcData::printStructure(out, exif, size, depth);
} else {
// create a copy on write memio object with the data, then print the structure
- BasicIo::AutoPtr p = BasicIo::AutoPtr(new MemIo(exif+start,size-start));
- if ( start < max ) printTiffStructure(*p,out,option,depth);
+ BasicIo::AutoPtr p = BasicIo::AutoPtr(new MemIo(exif + start, size - start));
+ if (start < max)
+ printTiffStructure(*p, out, option, depth);
}
// restore and clean up
- io_->seek(restore,Exiv2::BasicIo::beg);
- delete [] exif;
- bLF = false;
+ io_->seek(restore, Exiv2::BasicIo::beg);
+ delete[] exif;
+ bLF = false;
}
}
}
// print COM marker
- if ( bPrint && marker == com_ ) {
- int n = (size-2)>32?32:size-2; // size includes 2 for the two bytes for size!
- out << "| " << Internal::binaryToString(buf,n,2); // start after the two bytes
+ if (bPrint && marker == com_) {
+ int n = (size - 2) > 32 ? 32 : size - 2; // size includes 2 for the two bytes for size!
+ out << "| " << Internal::binaryToString(buf, n, 2); // start after the two bytes
}
// Skip the segment if the size is known
- if (io_->seek(size - bufRead, BasicIo::cur)) throw Error(14);
+ if (io_->seek(size - bufRead, BasicIo::cur))
+ throw Error(14);
- if ( bLF ) out << std::endl;
+ if (bLF)
+ out << std::endl;
if (marker != sos_) {
// Read the beginning of the next segment
marker = advanceToMarker();
+ enforce(marker>=0, kerNoImageInInputData);
REPORT_MARKER;
}
done |= marker == eoi_ || marker == sos_;
- if ( done && bPrint ) out << std::endl;
+ if (done && bPrint)
+ out << std::endl;
}
}
- if ( option == kpsIptcErase && iptcDataSegs.size() ) {
+ if (option == kpsIptcErase && iptcDataSegs.size()) {
#ifdef DEBUG
std::cout << "iptc data blocks: " << iptcDataSegs.size() << std::endl;
- uint32_t toggle = 0 ;
- for ( Uint32Vector_i i = iptcDataSegs.begin(); i != iptcDataSegs.end() ; i++ ) {
- std::cout << *i ;
- if ( toggle++ % 2 ) std::cout << std::endl; else std::cout << ' ' ;
+ uint32_t toggle = 0;
+ for (Uint32Vector_i i = iptcDataSegs.begin(); i != iptcDataSegs.end(); i++) {
+ std::cout << *i;
+ if (toggle++ % 2)
+ std::cout << std::endl;
+ else
+ std::cout << ' ';
}
#endif
- uint32_t count = (uint32_t) iptcDataSegs.size();
+ uint32_t count = (uint32_t)iptcDataSegs.size();
// figure out which blocks to copy
- uint64_t* pos = new uint64_t[count+2];
- pos[0] = 0 ;
+ uint64_t* pos = new uint64_t[count + 2];
+ pos[0] = 0;
// copy the data that is not iptc
Uint32Vector_i it = iptcDataSegs.begin();
- for ( uint64_t i = 0 ; i < count ; i++ ) {
- bool bOdd = (i%2)!=0;
- bool bEven = !bOdd;
- pos[i+1] = bEven ? *it : pos[i] + *it;
+ for (uint64_t i = 0; i < count; i++) {
+ bool bOdd = (i % 2) != 0;
+ bool bEven = !bOdd;
+ pos[i + 1] = bEven ? *it : pos[i] + *it;
it++;
}
- pos[count+1] = io_->size() - pos[count];
+ pos[count + 1] = io_->size() - pos[count];
#ifdef DEBUG
- for ( uint64_t i = 0 ; i < count+2 ; i++ ) std::cout << pos[i] << " " ;
+ for (uint64_t i = 0; i < count + 2; i++)
+ std::cout << pos[i] << " ";
std::cout << std::endl;
#endif
// $ dd bs=1 skip=$((0)) count=$((13164)) if=ETH0138028.jpg of=E1.jpg
@@ -829,29 +848,30 @@ namespace Exiv2 {
// binary copy io_ to a temporary file
BasicIo::AutoPtr tempIo(new MemIo);
- assert (tempIo.get() != 0);
- for ( uint64_t i = 0 ; i < (count/2)+1 ; i++ ) {
- uint64_t start = pos[2*i]+2 ; // step JPG 2 byte marker
- if ( start == 2 ) start = 0 ; // read the file 2 byte SOI
- long length = (long) (pos[2*i+1] - start) ;
- if ( length ) {
+ assert(tempIo.get() != 0);
+ for (uint64_t i = 0; i < (count / 2) + 1; i++) {
+ uint64_t start = pos[2 * i] + 2; // step JPG 2 byte marker
+ if (start == 2)
+ start = 0; // read the file 2 byte SOI
+ long length = (long)(pos[2 * i + 1] - start);
+ if (length) {
#ifdef DEBUG
- std::cout << start <<":"<< length << std::endl;
+ std::cout << start << ":" << length << std::endl;
#endif
- io_->seek(start,BasicIo::beg);
+ io_->seek(start, BasicIo::beg);
DataBuf buf(length);
- io_->read(buf.pData_,buf.size_);
- tempIo->write(buf.pData_,buf.size_);
+ io_->read(buf.pData_, buf.size_);
+ tempIo->write(buf.pData_, buf.size_);
}
}
- delete [] pos;
+ delete[] pos;
io_->seek(0, BasicIo::beg);
- io_->transfer(*tempIo); // may throw
+ io_->transfer(*tempIo); // may throw
io_->seek(0, BasicIo::beg);
readMetadata();
}
- } // JpegBase::printStructure
+ } // JpegBase::printStructure
void JpegBase::writeMetadata()
{

21
exiv2-CVE-2018-8977.patch Normal file
View File

@ -0,0 +1,21 @@
diff --git a/src/canonmn.cpp b/src/canonmn.cpp
index 450c7d9..f768c05 100644
--- a/src/canonmn.cpp
+++ b/src/canonmn.cpp
@@ -1774,9 +1774,13 @@ namespace Exiv2 {
{
try {
// 1140
- if( metadata->findKey(ExifKey("Exif.Image.Model" ))->value().toString() == "Canon EOS 30D"
- && metadata->findKey(ExifKey("Exif.CanonCs.Lens" ))->value().toString() == "24 24 1"
- && metadata->findKey(ExifKey("Exif.CanonCs.MaxAperture"))->value().toString() == "95" // F2.8
+ const ExifData::const_iterator itModel = metadata->findKey(ExifKey("Exif.Image.Model"));
+ const ExifData::const_iterator itLens = metadata->findKey(ExifKey("Exif.CanonCs.Lens"));
+ const ExifData::const_iterator itApert = metadata->findKey(ExifKey("Exif.CanonCs.MaxAperture"));
+
+ if( itModel != metadata->end() && itModel->value().toString() == "Canon EOS 30D"
+ && itLens != metadata->end() && itLens->value().toString() == "24 24 1"
+ && itApert != metadata->end() && itApert->value().toString() == "95" // F2.8
){
return os << "Canon EF-S 24mm f/2.8 STM" ;
}

View File

@ -0,0 +1,176 @@
diff --git a/src/actions.cpp b/src/actions.cpp
index 0ebe850..3cd398e 100644
--- a/src/actions.cpp
+++ b/src/actions.cpp
@@ -59,6 +59,7 @@ EXIV2_RCSID("@(#) $Id$")
#include <ctime>
#include <cmath>
#include <cassert>
+#include <stdexcept>
#include <sys/types.h> // for stat()
#include <sys/stat.h> // for stat()
#ifdef EXV_HAVE_UNISTD_H
@@ -236,33 +237,43 @@ namespace Action {
}
int Print::run(const std::string& path)
- try {
- path_ = path;
- int rc = 0;
- Exiv2::PrintStructureOption option = Exiv2::kpsNone ;
- switch (Params::instance().printMode_) {
- case Params::pmSummary: rc = printSummary(); break;
- case Params::pmList: rc = printList(); break;
- case Params::pmComment: rc = printComment(); break;
- case Params::pmPreview: rc = printPreviewList(); break;
- case Params::pmStructure: rc = printStructure(std::cout,Exiv2::kpsBasic) ; break;
- case Params::pmRecursive: rc = printStructure(std::cout,Exiv2::kpsRecursive) ; break;
-
- case Params::pmXMP:
- option = option == Exiv2::kpsNone ? Exiv2::kpsXMP : option; // drop
- case Params::pmIccProfile:{
- option = option == Exiv2::kpsNone ? Exiv2::kpsIccProfile : option;
- _setmode(_fileno(stdout),O_BINARY);
- rc = printStructure(std::cout,option);
- } break;
+ {
+ try {
+ path_ = path;
+ int rc = 0;
+ Exiv2::PrintStructureOption option = Exiv2::kpsNone ;
+ switch (Params::instance().printMode_) {
+ case Params::pmSummary: rc = printSummary(); break;
+ case Params::pmList: rc = printList(); break;
+ case Params::pmComment: rc = printComment(); break;
+ case Params::pmPreview: rc = printPreviewList(); break;
+ case Params::pmStructure: rc = printStructure(std::cout,Exiv2::kpsBasic) ; break;
+ case Params::pmRecursive: rc = printStructure(std::cout,Exiv2::kpsRecursive) ; break;
+
+ case Params::pmXMP:
+ if (option == Exiv2::kpsNone)
+ option = Exiv2::kpsXMP;
+ // drop
+ case Params::pmIccProfile:
+ if (option == Exiv2::kpsNone)
+ option = Exiv2::kpsIccProfile;
+ _setmode(_fileno(stdout),O_BINARY);
+ rc = printStructure(std::cout,option);
+ break;
+ }
+ return rc;
}
- return rc;
- }
- catch(const Exiv2::AnyError& e) {
- std::cerr << "Exiv2 exception in print action for file "
- << path << ":\n" << e << "\n";
- return 1;
- } // Print::run
+ catch(const Exiv2::AnyError& e) {
+ std::cerr << "Exiv2 exception in print action for file "
+ << path << ":\n" << e << "\n";
+ return 1;
+ }
+ catch(const std::overflow_error& e) {
+ std::cerr << "std::overflow_error exception in print action for file "
+ << path << ":\n" << e.what() << "\n";
+ return 1;
+ }
+ }
int Print::printStructure(std::ostream& out, Exiv2::PrintStructureOption option)
{
diff --git a/src/error.cpp b/src/error.cpp
index e90a9c0..5d63957 100644
--- a/src/error.cpp
+++ b/src/error.cpp
@@ -109,6 +109,8 @@ namespace {
{ 55, N_("tiff directory length is too large") },
{ 56, N_("invalid type value detected in Image::printIFDStructure") },
{ 57, N_("invalid memory allocation request") },
+ { 58, N_("corrupted image metadata") },
+ { 59, N_("Arithmetic operation overflow") },
};
}
diff --git a/src/nikonmn.cpp b/src/nikonmn.cpp
index 571ab80..34bf601 100644
--- a/src/nikonmn.cpp
+++ b/src/nikonmn.cpp
@@ -299,6 +299,8 @@ namespace Exiv2 {
const Value& value,
const ExifData* exifData)
{
+ if ( ! exifData ) return os << "undefined" ;
+
if ( value.count() >= 9 ) {
ByteOrder bo = getKeyString("Exif.MakerNote.ByteOrder",exifData) == "MM" ? bigEndian : littleEndian;
byte p[4];
diff --git a/src/pentaxmn.cpp b/src/pentaxmn.cpp
index 4fc38be..b22cb43 100644
--- a/src/pentaxmn.cpp
+++ b/src/pentaxmn.cpp
@@ -1167,6 +1167,8 @@ namespace Exiv2 {
std::ostream& PentaxMakerNote::printShutterCount(std::ostream& os, const Value& value, const ExifData* metadata)
{
+ if ( ! metadata ) return os << "undefined" ;
+
ExifData::const_iterator dateIt = metadata->findKey(
ExifKey("Exif.PentaxDng.Date"));
if (dateIt == metadata->end()) {
diff --git a/src/pngchunk.cpp b/src/pngchunk.cpp
index da4ccd0..4dcca4d 100644
--- a/src/pngchunk.cpp
+++ b/src/pngchunk.cpp
@@ -68,6 +68,8 @@ namespace Exiv2 {
int* outWidth,
int* outHeight)
{
+ assert(data.size_ >= 8);
+
// Extract image width and height from IHDR chunk.
*outWidth = getLong((const byte*)data.pData_, bigEndian);
diff --git a/src/pngimage.cpp b/src/pngimage.cpp
index 11b4198..ed7399a 100644
--- a/src/pngimage.cpp
+++ b/src/pngimage.cpp
@@ -441,7 +441,9 @@ namespace Exiv2 {
#ifdef DEBUG
std::cout << "Exiv2::PngImage::readMetadata: Found IHDR chunk (length: " << dataOffset << ")\n";
#endif
- PngChunk::decodeIHDRChunk(cdataBuf, &pixelWidth_, &pixelHeight_);
+ if (cdataBuf.size_ >= 8) {
+ PngChunk::decodeIHDRChunk(cdataBuf, &pixelWidth_, &pixelHeight_);
+ }
}
else if (!memcmp(cheaderBuf.pData_ + 4, "tEXt", 4))
{
diff --git a/src/tiffvisitor.cpp b/src/tiffvisitor.cpp
index 74f8d07..fad39b6 100644
--- a/src/tiffvisitor.cpp
+++ b/src/tiffvisitor.cpp
@@ -1493,6 +1493,11 @@ namespace Exiv2 {
}
p += 4;
uint32_t isize= 0; // size of Exif.Sony1.PreviewImage
+
+ if (count > std::numeric_limits<uint32_t>::max() / typeSize) {
+ throw Error(59);
+ }
+
uint32_t size = typeSize * count;
uint32_t offset = getLong(p, byteOrder());
byte* pData = p;
@@ -1536,7 +1541,9 @@ namespace Exiv2 {
}
}
Value::AutoPtr v = Value::create(typeId);
- assert(v.get());
+ if (!v.get()) {
+ throw Error(58);
+ }
if ( !isize ) {
v->read(pData, size, byteOrder());
} else {

View File

@ -0,0 +1,84 @@
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 7034bb6..27e90de 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -217,13 +217,16 @@ ADD_CUSTOM_TARGET(geotag-test COMMAND env EXIV2_BINDIR="${CMAKE_BINARY_DIR}"/bin
# effectively does a make doc on the root directory
# has to run 'make config' and './configure'
# and copy bin/taglist to <exiv2dir>/bin/taglist for use by 'make doc'
-IF( MINGW OR UNIX OR APPLE)
- ADD_CUSTOM_TARGET(doc
- WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/doc"
- COMMAND chmod +x ./cmake_doc.sh
- COMMAND ./cmake_doc.sh "${CMAKE_BINARY_DIR}"
- )
-ENDIF()
+# IF( MINGW OR UNIX OR APPLE)
+# ADD_CUSTOM_TARGET(doc
+# WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/doc"
+# COMMAND chmod +x ./cmake_doc.sh
+# COMMAND ./cmake_doc.sh "${CMAKE_BINARY_DIR}"
+# )
+# ENDIF()
+
+include(config/generateDoc.cmake REQUIRED)
+generate_documentation("${PROJECT_SOURCE_DIR}/config/Doxyfile")
# That's all Folks!
##
diff --git a/config/Doxyfile b/config/Doxyfile
index db62e1d..5d357a7 100644
--- a/config/Doxyfile
+++ b/config/Doxyfile
@@ -52,7 +52,7 @@ PROJECT_LOGO =
# If a relative path is entered, it will be relative to the location
# where doxygen was started. If left blank the current directory will be used.
-OUTPUT_DIRECTORY =
+OUTPUT_DIRECTORY = doc
# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
# 4096 sub-directories (in 2 levels) under the output directory of each output
@@ -1637,7 +1637,7 @@ TAGFILES =
# When a file name is specified after GENERATE_TAGFILE, doxygen will create
# a tag file that is based on the input files it reads.
-GENERATE_TAGFILE = html/exiv2.xml
+GENERATE_TAGFILE = doc/html/exiv2.xml
# If the ALLEXTERNALS tag is set to YES all external classes will be listed
# in the class index. If set to NO only the inherited external classes
diff --git a/config/generateDoc.cmake b/config/generateDoc.cmake
new file mode 100644
index 0000000..2b66078
--- /dev/null
+++ b/config/generateDoc.cmake
@@ -0,0 +1,28 @@
+# -helper macro to add a "doc" target with CMake build system.
+# and configure doxy.config.in to doxy.config
+#
+# target "doc" allows building the documentation with doxygen/dot on WIN32, Linux and Mac
+#
+
+find_package(Doxygen REQUIRED)
+
+macro(generate_documentation DOX_CONFIG_FILE)
+ if(NOT EXISTS "${DOX_CONFIG_FILE}")
+ message(FATAL_ERROR "Configuration file for doxygen not found")
+ endif()
+
+ #Define variables
+ set(INCDIR "${PROJECT_SOURCE_DIR}/include/exiv2")
+ set(SRCDIR "${PROJECT_SOURCE_DIR}/src")
+ set(ROOTDIR "${PROJECT_SOURCE_DIR}")
+ #set(TESTSDIR "${PROJECT_SOURCE_DIR}/tests")
+
+ configure_file(${DOX_CONFIG_FILE} ${CMAKE_CURRENT_BINARY_DIR}/doxy.config @ONLY) #OUT-OF-PLACE LOCATION
+ set(DOXY_CONFIG "${CMAKE_CURRENT_BINARY_DIR}/doxy.config")
+ add_custom_target(doc ${DOXYGEN_EXECUTABLE} ${DOXY_CONFIG})
+
+ install(DIRECTORY "${PROJECT_BINARY_DIR}/doc/html/" DESTINATION "share/doc/html/lib${PROJECT_NAME}")
+
+ set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES doc)
+endmacro()
+

View File

@ -0,0 +1,43 @@
From f9e3c712fe23a9cb661c998fc4fd14e7e5d641f5 Mon Sep 17 00:00:00 2001
From: Luis Diaz Mas <piponazo@gmail.com>
Date: Thu, 17 Aug 2017 22:40:50 +0200
Subject: Simplify compiler info handling in CMake
(cherry picked from commit 69fb40fdc6d5797d10a025b9f5123978dda3bfa4)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index f2103c44..e49fb78b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -67,8 +67,8 @@ ENDIF()
# set include path for FindXXX.cmake files
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/config/")
-IF( MINGW OR UNIX )
- IF ( CMAKE_CXX_COMPILER STREQUAL "g++" OR CMAKE_C_COMPILER STREQUAL "gcc" )
+if( MINGW OR UNIX )
+ if (${CMAKE_CXX_COMPILER_ID} STREQUAL GNU)
ADD_DEFINITIONS(-Wall
-Wcast-align
-Wpointer-arith
@@ -79,18 +79,8 @@ IF( MINGW OR UNIX )
)
ENDIF()
- execute_process(COMMAND ${CMAKE_CXX_COMPILER} --version OUTPUT_VARIABLE COMPILER_VERSION)
- string(REGEX MATCHALL "[a-z\+]+" GCC_COMPILER_COMPONENTS ${COMPILER_VERSION})
- list(GET GCC_COMPILER_COMPONENTS 0 COMPILER)
-
- execute_process(COMMAND ${CMAKE_CXX_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION)
- string(REGEX MATCHALL "[0-9]+" GCC_VERSION_COMPONENTS ${GCC_VERSION})
- list(GET GCC_VERSION_COMPONENTS 0 GCC_MAJOR)
- list(GET GCC_VERSION_COMPONENTS 1 GCC_MINOR)
-
- message(STATUS Compiler: ${COMPILER} " Major:" ${GCC_MAJOR} " Minor:" ${GCC_MINOR})
-
- IF ( CYGWIN OR ( ${GCC_MAJOR} GREATER 5 ))
+ message(STATUS "Compiler info: ${CMAKE_CXX_COMPILER_ID} (${CMAKE_CXX_COMPILER}) ; version: ${CMAKE_CXX_COMPILER_VERSION}")
+ IF ( CYGWIN OR (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 5.0))
ADD_DEFINITIONS( -std=gnu++98 ) # to support snprintf
ELSE()
ADD_DEFINITIONS( -std=c++98 )

View File

@ -0,0 +1,39 @@
From 1e07c98dfcbd8ac10ee02088f08235f5e1700148 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Dan=20=C4=8Cerm=C3=A1k?= <dan.cermak@cgc-instruments.com>
Date: Wed, 27 Sep 2017 23:38:49 +0200
Subject: Fixed wrong brackets: size*count + pad can overflow before the cast
=> Should fix #76 (most of the work has been done by Robin Mills in
6e3855aed7ba8bb4731fc4087ca7f9078b2f3d97)
The problem with #76 is the contents of the 26th IFD, with the
following contents:
tag: 0x8649
type: 0x1
count: 0xffff ffff
offset: 0x4974
The issue is the size of count (uint32_t), as adding anything to it
causes an overflow. Especially the expression:
(size*count + pad+20)
results in an overflow and gives 20 as a result instead of
0x100000014, thus the condition in the if in the next line is false
and the program continues to run (until it crashes at io.read).
To properly account for the overflow, the brackets have to be removed,
as then the result is saved in the correctly sized type and not cast
after being calculated in the smaller type.
diff --git a/src/image.cpp b/src/image.cpp
index ec5b873e..199671b9 100644
--- a/src/image.cpp
+++ b/src/image.cpp
@@ -401,7 +401,7 @@ namespace Exiv2 {
// if ( offset > io.size() ) offset = 0; // Denial of service?
// #55 memory allocation crash test/data/POC8
- long long allocate = (long long) (size*count + pad+20);
+ long long allocate = (long long) size*count + pad+20;
if ( allocate > (long long) io.size() ) {
throw Error(57);
}

View File

@ -4,30 +4,43 @@
#global cmake_build 1
Summary: Exif and Iptc metadata manipulation library
Name: exiv2
Name: exiv2
Version: 0.26
Release: 11%{?dist}
Release: 12%{?dist}
License: GPLv2+
URL: http://www.exiv2.org/
Source0: http://www.exiv2.org/builds/exiv2-%{version}-trunk.tar.gz
URL: http://www.exiv2.org/
Source0: https://github.com/Exiv2/%{name}/archive/exiv2-%{version}.tar.gz
## upstream patches
Patch6: 0006-1296-Fix-submitted.patch
Patch0: exiv2-simplify-compiler-info-in-cmake.patch
Patch1: exiv2-fix-documentation-build.patch
## rhel patches
## upstream patches (lookaside cache)
Patch6: 0006-1296-Fix-submitted.patch
# Security fixes
Patch10: exiv2-CVE-2017-17723.patch
Patch11: exiv2-CVE-2017-17725.patch
Patch12: exiv2-CVE-2017-5772.patch
Patch11: exiv2-wrong-brackets.patch
Patch12: exiv2-CVE-2017-11683.patch
Patch13: exiv2-CVE-2017-14860.patch
Patch14: exiv2-CVE-2017-14864-CVE-2017-14862-CVE-2017-14859.patch
Patch15: exiv2-CVE-2017-17725.patch
Patch16: exiv2-CVE-2017-17669.patch
Patch17: exiv2-additional-security-fixes.patch
Patch18: exiv2-CVE-2018-10958.patch
Patch19: exiv2-CVE-2018-10998.patch
Patch20: exiv2-CVE-2018-11531.patch
Patch21: exiv2-CVE-2018-12264-CVE-2018-12265.patch
Patch22: exiv2-CVE-2018-14046.patch
Patch23: exiv2-CVE-2018-5772.patch
Patch24: exiv2-CVE-2018-8976.patch
Patch25: exiv2-CVE-2018-8977.patch
## upstreamable patches
Patch100: exiv2-doxygen.patch
%if 0%{?cmake_build}
BuildRequires: cmake
%endif
BuildRequires: expat-devel
BuildRequires: gcc-c++
BuildRequires: gettext
BuildRequires: pkgconfig
BuildRequires: pkgconfig(libcurl)
@ -66,7 +79,7 @@ Recommends: %{name} = %{version}-%{release}
%endif
%description libs
A C++ library to access image metadata, supporting full read and write access
to the Exif and Iptc metadata, Exif MakerNote support, extract and delete
to the Exif and Iptc metadata, Exif MakerNote support, extract and delete
methods for Exif thumbnails, classes to access Ifd and so on.
%package doc
@ -77,58 +90,33 @@ BuildArch: noarch
%prep
%autosetup -n %{name}-trunk -p1
%autosetup -n %{name}-%{version} -p1
%build
# exiv2: embedded copy of exempi should be compiled with BanAllEntityUsage
# https://bugzilla.redhat.com/show_bug.cgi?id=888769
export CPPFLAGS="-DBanAllEntityUsage=1"
%if 0%{?cmake_build}
%{cmake} \
-DEXIV2_ENABLE_BUILD_PO:BOOL=ON \
-DEXIV2_ENABLE_BUILD_SAMPLES:BOOL=OFF \
.
-DEXIV2_ENABLE_LIBXMP:BOOL=ON .
# FIXME: build this because it adds Threads library and it doesn't build without
# it from some reason
make %{?_smp_mflags}
make doc -k ||:
%else
%configure \
--disable-rpath \
--disable-static
## these options not enabled by default, find out why before considering
## manually enabling them
# --enable-video \
# --enable-webready
# rpath
sed -i 's|^hardcode_libdir_flag_spec=.*|hardcode_libdir_flag_spec=""|g' libtool
sed -i 's|^runpath_var=LD_RUN_PATH|runpath_var=DIE_RPATH_DIE|g' libtool
make %{?_smp_mflags}
make doc -k ||:
%endif
%install
%if 0%{?cmake_build}
make install/fast DESTDIR=%{buildroot}
%else
make install DESTDIR=%{buildroot}
## fix perms on installed lib
ls -l %{buildroot}%{_libdir}/libexiv2.so.*
chmod 755 %{buildroot}%{_libdir}/libexiv2.so.*
%endif
%find_lang exiv2 --with-man
## unpackaged files
rm -fv %{buildroot}%{_libdir}/libexiv2.la
rm -fv %{buildroot}%{_libdir}/libxmp.a
rm -fv %{buildroot}%{_libdir}/pkgconfig//exiv2.lsm
%check
export PKG_CONFIG_PATH=%{buildroot}%{_libdir}/pkgconfig
@ -155,10 +143,15 @@ test -x %{buildroot}%{_libdir}/libexiv2.so
%{_libdir}/pkgconfig/exiv2.pc
%files doc
%doc doc/html
%{_datadir}/doc/html/
%changelog
* Tue Jul 24 2018 Jan Grulich <jgrulich@redhat.com> - 0.26-12
- Security fix for CVE-2017-17723, CVE-2017-17725, CVE-2018-10958, CVE-2018-10998,
CVE-2018-11531, CVE-2018-12264, CVE-2018-12265, CVE-2018-14046, CVE-2018-5772,
CVE-2018-8976, CVE-2018-8977, CVE-2018-9144
* Fri Jul 13 2018 Fedora Release Engineering <releng@fedoraproject.org> - 0.26-11
- Rebuilt for https://fedoraproject.org/wiki/Fedora_29_Mass_Rebuild

View File

@ -1 +1 @@
SHA512 (exiv2-0.26-trunk.tar.gz) = 0caab1aeaab171201c1d19d21b8484a91d076e78c93c4a5fbb7e21510cc0eaff81b04f45434207d857ba0de5bd6e368743a1cc571d78a27b44e157f6b031f481
SHA512 (exiv2-0.26.tar.gz) = 559455d792d7ad9bf7fbeed6268b90c5fe72e3f094770599e20983a6113039f3c12f31849e15752a4bd68610e129f5dab98e29888c0e2141613ea34582beffd7