Package init

This commit is contained in:
overweight 2019-09-30 10:38:30 -04:00
commit 66fd93ad95
33 changed files with 2592 additions and 0 deletions

View File

@ -0,0 +1,25 @@
From 2f8681e120d277e418941c4361c83b5028f67fd8 Mon Sep 17 00:00:00 2001
From: clanmills <robin@clanmills.com>
Date: Sat, 27 May 2017 10:18:17 +0100
Subject: [PATCH 6/6] #1296 Fix submitted.
---
src/tiffcomposite.cpp | 2 ++
1 file changed, 2 insertions(+)
diff --git a/src/tiffcomposite.cpp b/src/tiffcomposite.cpp
index c6b860d..0c9b9c4 100644
--- a/src/tiffcomposite.cpp
+++ b/src/tiffcomposite.cpp
@@ -1611,6 +1611,8 @@ namespace Exiv2 {
uint32_t TiffImageEntry::doWriteImage(IoWrapper& ioWrapper,
ByteOrder /*byteOrder*/) const
{
+ if ( !pValue() ) throw Error(21); // #1296
+
uint32_t len = pValue()->sizeDataArea();
if (len > 0) {
#ifdef DEBUG
--
2.9.4

42
CVE-2017-1000126.patch Normal file
View File

@ -0,0 +1,42 @@
From 0d04a6d900010c754d578ef27d5c26190dc59d2b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Dan=20=C4=8Cerm=C3=A1k?= <dan.cermak@cgc-instruments.com>
Date: Mon, 26 Mar 2018 00:34:25 +0200
Subject: [PATCH] Fix CVE-2017-1000126
CVE-2017-1000126 is a Stack out of bounds read in the WebP parser caused by the
parameter size & filesize being too large, causing the parser to land in an
infinite loop and eventually crash. Enforcing that the size over which the
parser iterates is smaller than the file fixes this issue.
This fixes #175.
(cherry picked from commit 3c20cc06a9ede4e277a9efe94e211c20ceb0ce8d)
---
src/webpimage.cpp | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/src/webpimage.cpp b/src/webpimage.cpp
index 45d642109..eb5649728 100644
--- a/src/webpimage.cpp
+++ b/src/webpimage.cpp
@@ -493,7 +494,9 @@ namespace Exiv2 {
io_->read(data, WEBP_TAG_SIZE * 3);
- WebPImage::decodeChunks(Exiv2::getULong(data + WEBP_TAG_SIZE, littleEndian) + 12);
+ const uint32_t filesize = Exiv2::getULong(data + WEBP_TAG_SIZE, littleEndian) + 8;
+ enforce(filesize <= io_->size(), Exiv2::kerCorruptedMetadata);
+ WebPImage::decodeChunks(filesize);
} // WebPImage::readMetadata
@@ -511,7 +514,8 @@ namespace Exiv2 {
while ( !io_->eof() && (uint64_t) io_->tell() < filesize) {
io_->read(chunkId.pData_, WEBP_TAG_SIZE);
io_->read(size_buff, WEBP_TAG_SIZE);
- long size = Exiv2::getULong(size_buff, littleEndian);
+ const uint32_t size = Exiv2::getULong(size_buff, littleEndian);
+ enforce(size <= (filesize - io_->tell()), Exiv2::kerCorruptedMetadata);
DataBuf payload(size);

View File

@ -0,0 +1,22 @@
From afb98cbc6e288dc8ea75f3394a347fb9b37abc55 Mon Sep 17 00:00:00 2001
From: Robin Mills <robin@clanmills.com>
Date: Mon, 22 Jan 2018 23:27:08 +0100
Subject: [PATCH] Allocate correct amount of memory for the ICC profile
---
src/tiffimage.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/tiffimage.cpp b/src/tiffimage.cpp
index 8731449cd..a69c7afd5 100644
--- a/src/tiffimage.cpp
+++ b/src/tiffimage.cpp
@@ -191,7 +191,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);
}

40
CVE-2018-17282.patch Normal file
View File

@ -0,0 +1,40 @@
--- a/src/tiffimage.cpp
+++ b/src/tiffimage.cpp
@@ -171,11 +171,15 @@
#ifdef DEBUG
std::cerr << "Reading TIFF file " << io_->path() << "\n";
#endif
- if (io_->open() != 0) throw Error(9, io_->path(), strError());
+ if (io_->open() != 0) {
+ throw Error(kerDataSourceOpenFailed, io_->path(), strError());
+ }
+
IoCloser closer(*io_);
// Ensure that this is the correct image type
if (!isTiffType(*io_, false)) {
- if (io_->error() || io_->eof()) throw Error(14);
+ if (io_->error() || io_->eof())
+ throw Error(kerFailedToReadImageData);
throw Error(3, "TIFF");
}
clearMetadata();
@@ -190,12 +194,16 @@
// read profile from the metadata
Exiv2::ExifKey key("Exif.Image.InterColorProfile");
Exiv2::ExifData::iterator pos = exifData_.findKey(key);
- if ( pos != exifData_.end() ) {
- iccProfile_.alloc(pos->count()*pos->typeSize());
+ if ( pos != exifData_.end() ) {
+ long size = pos->count() * pos->typeSize();
+ if (size == 0) {
+ throw Error(kerFailedToReadImageData);
+ }
+ iccProfile_.alloc(size);
pos->copy(iccProfile_.pData_,bo);
}
- } // TiffImage::readMetadata
+ }
void TiffImage::writeMetadata()
{

27
CVE-2018-18915.patch Normal file
View File

@ -0,0 +1,27 @@
From ae49250942f4395639961abeed3c15920fcd7241 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Luis=20D=C3=ADaz=20M=C3=A1s?= <piponazo@gmail.com>
Date: Sun, 4 Nov 2018 18:44:38 +0100
Subject: [PATCH] Check in Image::printIFDStructure if seek and reads are OK
---
src/image.cpp | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/src/image.cpp b/src/image.cpp
index e0eebf3d4..75991f7d5 100644
--- a/src/image.cpp
+++ b/src/image.cpp
@@ -344,8 +344,11 @@ namespace Exiv2 {
do {
// Read top of directory
- io.seek(start,BasicIo::beg);
- io.read(dir.pData_, 2);
+ const int seekSuccess = !io.seek(start,BasicIo::beg);
+ const long bytesRead = io.read(dir.pData_, 2);
+ if (!seekSuccess || bytesRead == 0) {
+ throw Error(kerCorruptedMetadata);
+ }
uint16_t dirLength = byteSwap2(dir,0,bSwap);
bool tooBig = dirLength > 500;

View File

@ -0,0 +1,31 @@
From 68966932510213b5656fcf433ab6d7e26f48e23b Mon Sep 17 00:00:00 2001
From: Luis Diaz Mas <piponazo@gmail.com>
Date: Sun, 4 Nov 2018 22:33:03 +0100
Subject: [PATCH] PSD: Use Safe::add for preventing overflows in PSD files
---
src/psdimage.cpp | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/src/psdimage.cpp b/src/psdimage.cpp
index 02e0e87b0..a5a8d9fe9 100644
--- a/src/psdimage.cpp
+++ b/src/psdimage.cpp
@@ -33,6 +33,7 @@
#include "basicio.hpp"
#include "error.hpp"
#include "futils.hpp"
+#include "safe_op.hpp"
// + standard includes
#include <string>
@@ -228,7 +229,8 @@ namespace Exiv2 {
readResourceBlock(resourceId, resourceSize);
resourceSize = (resourceSize + 1) & ~1; // pad to even
io_->seek(curOffset + resourceSize, BasicIo::beg);
- resourcesLength -= (12 + resourceNameLength + resourceSize);
+ resourcesLength -= Safe::add(Safe::add(static_cast<uint32_t>(12), resourceNameLength),
+ resourceSize);
}
} // PsdImage::readMetadata

View File

@ -0,0 +1,32 @@
From b7c71f3ad0386cd7af3b73443c0615ada073f0d5 Mon Sep 17 00:00:00 2001
From: Luis Diaz Mas <piponazo@gmail.com>
Date: Mon, 5 Nov 2018 13:30:18 +0100
Subject: [PATCH] PSD: enforce Length of image resource section < file size
---
src/psdimage.cpp | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/src/psdimage.cpp b/src/psdimage.cpp
index a5a8d9fe9..8ed67544d 100644
--- a/src/psdimage.cpp
+++ b/src/psdimage.cpp
@@ -33,7 +33,9 @@
#include "basicio.hpp"
#include "error.hpp"
#include "futils.hpp"
+
#include "safe_op.hpp"
+#include "enforce.hpp"
// + standard includes
#include <string>
@@ -197,6 +199,8 @@ namespace Exiv2 {
throw Error(3, "Photoshop");
}
uint32_t resourcesLength = getULong(buf, bigEndian);
+ enforce(resourcesLength < io_->size(), Exiv2::kerCorruptedMetadata);
+
while (resourcesLength > 0)
{
if (io_->read(buf, 8) != 8)

31
CVE-2018-19607.patch Normal file
View File

@ -0,0 +1,31 @@
From 6e42c1b55e0fc4f360cc56010b0ffe19aa6062d9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Luis=20D=C3=ADaz=20M=C3=A1s?= <piponazo@gmail.com>
Date: Mon, 26 Nov 2018 14:24:14 +0100
Subject: [PATCH] Fix #561. Use proper counter for the idx variable
---
src/easyaccess.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/easyaccess.cpp b/src/easyaccess.cpp
index 1eed30c47..9302d6cc9 100644
--- a/src/easyaccess.cpp
+++ b/src/easyaccess.cpp
@@ -154,7 +154,7 @@ namespace Exiv2 {
std::ostringstream os;
md_st->write(os, &ed);
bool ok = false;
- long st_val = parseLong(os.str(), ok);
+ const long st_val = parseLong(os.str(), ok);
// SensivityType out of range or cannot be parsed properly
if (!ok || st_val < 1 || st_val > 7)
break;
@@ -175,7 +175,7 @@ namespace Exiv2 {
md = md_st;
break;
}
- while (strcmp(sensKeys->keys[idx++], md_st->key().c_str()) != 0 && idx < cnt) {}
+ while (strcmp(sensKeys->keys[idx++], md_st->key().c_str()) != 0 && idx < sensKeys->count) {}
}
break;
}

11
CVE-2019-13110.patch Normal file
View File

@ -0,0 +1,11 @@
--- a/src/crwimage.cpp 2019-07-17 16:22:44.284000000 +0800
+++ b/src/crwimage_1.cpp 2019-07-17 16:23:57.032000000 +0800
@@ -460,7 +460,7 @@ namespace Exiv2 {
#endif
o += 2;
for (uint16_t i = 0; i < count; ++i) {
- if (o + 10 > size) throw Error(33);
+ if (size < 10 || o > size-10) throw Error(33);
uint16_t tag = getUShort(pData + o, byteOrder);
CiffComponent::AutoPtr m;
switch (CiffComponent::typeId(tag)) {

38
CVE-2019-13113.patch Normal file
View File

@ -0,0 +1,38 @@
Backported of:
From 7798ae25574425271305fffe85de77bec8df03f1 Mon Sep 17 00:00:00 2001
From: Kevin Backhouse <kev@semmle.com>
Date: Wed, 15 May 2019 10:12:02 +0100
Subject: [PATCH] Throw an exception if the data location is invalid. (#842)
diff --git a/src/crwimage.cpp b/src/crwimage.cpp
index 9225ce5..5ccf3b1 100644
--- a/src/crwimage.cpp
+++ b/src/crwimage.cpp
@@ -738,12 +738,11 @@ namespace Exiv2 {
DataLocId CiffComponent::dataLocation(uint16_t tag)
{
- DataLocId di = invalidDataLocId;
switch (tag & 0xc000) {
- case 0x0000: di = valueData; break;
- case 0x4000: di = directoryData; break;
+ case 0x0000: return valueData;
+ case 0x4000: return directoryData;
+ default: throw Error(kerCorruptedMetadata);
}
- return di;
} // CiffComponent::dataLocation
/*!
diff --git a/src/crwimage_int.hpp b/src/crwimage_int.hpp
index 5588ae5..1478c82 100644
--- a/src/crwimage_int.hpp
+++ b/src/crwimage_int.hpp
@@ -78,7 +78,6 @@ namespace Exiv2 {
//! Type to identify where the data is stored in a directory
enum DataLocId {
- invalidDataLocId,
valueData,
directoryData,
lastDataLocId

53
CVE-2019-13114.patch Normal file
View File

@ -0,0 +1,53 @@
Backported of:
From c1bee7319a8b9e0d38f1988d70dc4fa5c52b83d1 Mon Sep 17 00:00:00 2001
From: Kevin Backhouse <kev@semmle.com>
Date: Tue, 30 Apr 2019 11:15:06 +0100
Subject: [PATCH] Avoid null pointer exception due to NULL return value from
strchr.
This fixes #793.
diff --git a/src/http.cpp b/src/http.cpp
index b8a429b..9c76f99 100644
--- a/src/http.cpp
+++ b/src/http.cpp
@@ -339,10 +339,14 @@ int Exiv2::http(dict_t& request,dict_t& response,std::string& errors)
// search for the body
for ( size_t b = 0 ; bSearching && b < lengthof(blankLines) ; b++ ) {
- if ( strstr(buffer,blankLines[b]) ) {
+ const char* blankLinePos = strstr(buffer,blankLines[b]);
+ if ( blankLinePos ) {
bSearching = false ;
- body = (int) ( strstr(buffer,blankLines[b]) - buffer ) + strlen(blankLines[b]) ;
- status = atoi(strchr(buffer,' ')) ;
+ body = blankLinePos - buffer + strlen(blankLines[b]);
+ const char* firstSpace = strchr(buffer,' ');
+ if (firstSpace) {
+ status = atoi(firstSpace);
+ }
}
}
@@ -352,9 +356,19 @@ int Exiv2::http(dict_t& request,dict_t& response,std::string& errors)
char N = '\n';
int i = 0 ; // initial byte in buffer
while(buffer[i] == N ) i++;
- h = strchr(h+i,N)+1;
+ h = strchr(h+i,N);
+ if (!h) {
+ status = 0;
+ break;
+ }
+ h++;
response[""]=std::string(buffer+i).substr(0,h-buffer-2);
- result = atoi(strchr(buffer,' '));
+ const char* firstSpace = strchr(buffer,' ');
+ if ( !firstSpace ) {
+ status = 0;
+ break;
+ }
+ result = atoi(firstSpace);
char* c = strchr(h,C);
char* n = strchr(h,N);
while ( c && n && c < n && h < buffer+body ) {

29
CVE-2019-14982.patch Normal file
View File

@ -0,0 +1,29 @@
From e925bc5addd881543fa503470c8a859e112cca62 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Luis=20D=C3=ADaz=20M=C3=A1s?= <piponazo@gmail.com>
Date: Mon, 15 Jul 2019 20:04:39 +0200
Subject: [PATCH] Fix integer overflow by checking size against header_size
Note that the problem occurs when data_size is less than header_size
what causes a buffer overflow in &data[i]
Co-Authored-By: D4N <dan.cermak@cgc-instruments.com>
---
src/webpimage.cpp | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/src/webpimage.cpp b/src/webpimage.cpp
index 3e4773f0a..8bf98d33e 100644
--- a/src/webpimage.cpp
+++ b/src/webpimage.cpp
@@ -827,8 +827,9 @@ namespace Exiv2 {
}
}
- long WebPImage::getHeaderOffset(byte *data, long data_size,
- byte *header, long header_size) {
+ long WebPImage::getHeaderOffset(byte* data, long data_size, byte* header, long header_size)
+ {
+ if (data_size < header_size) { return -1; }
long pos = -1;
for (long i=0; i < data_size - header_size; i++) {
if (memcmp(header, &data[i], header_size) == 0) {

BIN
exiv2-0.26.tar.gz Normal file

Binary file not shown.

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);
}

107
exiv2-CVE-2017-17723.patch Normal file
View File

@ -0,0 +1,107 @@
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 95589cd..f2e1518 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/error.cpp b/src/error.cpp
index 80378c1..e90a9c0 100644
--- a/src/error.cpp
+++ b/src/error.cpp
@@ -106,6 +106,9 @@ namespace {
{ 52, N_("%1 has invalid XMP value type `%2'") }, // %1=key, %2=value type
{ 53, N_("Not a valid ICC Profile") },
{ 54, N_("Not valid XMP") },
+ { 55, N_("tiff directory length is too large") },
+ { 56, N_("invalid type value detected in Image::printIFDStructure") },
+ { 57, N_("invalid memory allocation request") },
};
}
diff --git a/src/image.cpp b/src/image.cpp
index 0d82804..ec5b873 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
diff --git a/test/bugfixes-test.sh b/test/bugfixes-test.sh
index f91c675..c90ae55 100755
--- a/test/bugfixes-test.sh
+++ b/test/bugfixes-test.sh
@@ -602,6 +602,7 @@ source ./functions.source
runTest exiv2 -pX $filename | xmllint --format -
num=1231
+ printf "$num " >&3
for X in a b; do
filename=exiv2-bug$num$X.jpg
echo '------>' Bug $filename '<-------' >&2
@@ -622,6 +623,7 @@ source ./functions.source
runTest exiv2 -pa $filename
num=1252
+ printf "$num " >&3
for X in a b; do
filename=exiv2-bug$num$X.exv
echo '------>' Bug $filename '<-------' >&2
@@ -629,6 +631,13 @@ source ./functions.source
runTest exiv2 -pa --grep lens/i $filename
done
+ num=g55
+ printf "$num " >&3
+ filename=POC8
+ echo '------>' Bug $filename '<-------' >&2
+ copyTestFile $filename
+ runTest exiv2 $filename 2>/dev/null
+
) 3>&1 > $results 2>&1
printf "\n"

351
exiv2-CVE-2017-17725.patch Normal file
View File

@ -0,0 +1,351 @@
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
diff --git a/src/jp2image.cpp b/src/jp2image.cpp
index 09d023e2..a308bfd9 100644
--- a/src/jp2image.cpp
+++ b/src/jp2image.cpp
@@ -41,6 +41,7 @@ EXIV2_RCSID("@(#) $Id$")
#include "error.hpp"
#include "futils.hpp"
#include "types.hpp"
+#include "safe_op.hpp"
// + standard includes
#include <string>
@@ -269,15 +270,16 @@ namespace Exiv2
std::cout << "Exiv2::Jp2Image::readMetadata: "
<< "Color data found" << std::endl;
#endif
+
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_);
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 00000000..55d690e3
--- /dev/null
+++ b/src/safe_op.hpp
@@ -0,0 +1,308 @@
+// ********************************************************* -*- C++ -*-
+/*
+ * Copyright (C) 2004-2017 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 safe_op.hpp
+ @brief Overflow checks for integers
+ @author Dan Čermák (D4N)
+ <a href="mailto:dan.cermak@cgc-instruments.com">dan.cermak@cgc-instruments.com</a>
+ @date 14-Dec-17, D4N: created
+ */
+
+#ifndef SAFE_OP_HPP_
+#define SAFE_OP_HPP_
+
+#include <limits>
+#include <stdexcept>
+
+#ifdef _MSC_VER
+#include <Intsafe.h>
+#endif
+
+/*!
+ * @brief Arithmetic operations with overflow checks
+ */
+namespace Safe
+{
+ /*!
+ * @brief Helper structs for providing integer overflow checks.
+ *
+ * This namespace contains the internal helper structs fallback_add_overflow
+ * and builtin_add_overflow. Both have a public static member function add
+ * with the following interface:
+ *
+ * bool add(T summand_1, T summand_2, T& result)
+ *
+ * where T is the type over which the struct is templated.
+ *
+ * The function performs a check whether the addition summand_1 + summand_2
+ * can be performed without an overflow. If the operation would overflow,
+ * true is returned and the addition is not performed if it would result in
+ * undefined behavior. If no overflow occurs, the sum is saved in result and
+ * false is returned.
+ *
+ * fallback_add_overflow implements a portable but slower overflow check.
+ * builtin_add_overflow uses compiler builtins (when available) and should
+ * be considerably faster. As builtins are not available for all types,
+ * builtin_add_overflow falls back to fallback_add_overflow when no builtin
+ * is available.
+ */
+ namespace Internal
+ {
+ /*!
+ * @brief Helper struct to determine whether a type is signed or unsigned
+
+ * This struct is a backport of std::is_signed from C++11. It has a public
+ * enum with the property VALUE which is true when the type is signed or
+ * false if it is unsigned.
+ */
+ template <typename T>
+ struct is_signed
+ {
+ enum
+ {
+ VALUE = T(-1) < T(0)
+ };
+ };
+
+ /*!
+ * @brief Helper struct for SFINAE, from C++11
+
+ * This struct has a public typedef called type typedef'd to T if B is
+ * true. Otherwise there is no typedef.
+ */
+ template <bool B, class T = void>
+ struct enable_if
+ {
+ };
+
+ /*!
+ * @brief Specialization of enable_if for the case B == true
+ */
+ template <class T>
+ struct enable_if<true, T>
+ {
+ typedef T type;
+ };
+
+ /*!
+ * @brief Fallback overflow checker, specialized via SFINAE
+ *
+ * This struct implements a 'fallback' addition with an overflow check,
+ * i.e. it does not rely on compiler intrinsics. It is specialized via
+ * SFINAE for signed and unsigned integer types and provides a public
+ * static member function add.
+ */
+ template <typename T, typename = void>
+ struct fallback_add_overflow;
+
+ /*!
+ * @brief Overload of fallback_add_overflow for signed integers
+ */
+ template <typename T>
+ struct fallback_add_overflow<T, typename enable_if<is_signed<T>::VALUE>::type>
+ {
+ /*!
+ * @brief Adds the two summands only if no overflow occurs
+ *
+ * This function performs a check if summand_1 + summand_2 would
+ * overflow and returns true in that case. If no overflow occurs,
+ * the sum is saved in result and false is returned.
+ *
+ * @return true on overflow, false on no overflow
+ *
+ * The check for an overflow is performed before the addition to
+ * ensure that no undefined behavior occurs. The value in result is
+ * only valid when the function returns false.
+ *
+ * Further information:
+ * https://wiki.sei.cmu.edu/confluence/display/c/INT32-C.+Ensure+that+operations+on+signed+integers+do+not+result+in+overflow
+ */
+ static bool add(T summand_1, T summand_2, T& result)
+ {
+ if (((summand_2 >= 0) && (summand_1 > std::numeric_limits<T>::max() - summand_2)) ||
+ ((summand_2 < 0) && (summand_1 < std::numeric_limits<T>::min() - summand_2))) {
+ return true;
+ } else {
+ result = summand_1 + summand_2;
+ return false;
+ }
+ }
+ };
+
+ /*!
+ * @brief Overload of fallback_add_overflow for unsigned integers
+ */
+ template <typename T>
+ struct fallback_add_overflow<T, typename enable_if<!is_signed<T>::VALUE>::type>
+ {
+ /*!
+ * @brief Adds the two summands only if no overflow occurs
+ *
+ * This function performs a check if summand_1 + summand_2 would
+ * overflow and returns true in that case. If no overflow occurs,
+ * the sum is saved in result and false is returned.
+ *
+ * @return true on overflow, false on no overflow
+ *
+ * Further information:
+ * https://wiki.sei.cmu.edu/confluence/display/c/INT30-C.+Ensure+that+unsigned+integer+operations+do+not+wrap
+ */
+ static bool add(T summand_1, T summand_2, T& result)
+ {
+ if (summand_1 > std::numeric_limits<T>::max() - summand_2) {
+ return true;
+ } else {
+ result = summand_1 + summand_2;
+ return false;
+ }
+ }
+ };
+
+ /*!
+ * @brief Overflow checker using compiler intrinsics
+ *
+ * This struct provides an add function with the same interface &
+ * behavior as fallback_add_overload::add but it relies on compiler
+ * intrinsics instead. This version should be considerably faster than
+ * the fallback version as it can fully utilize available CPU
+ * instructions & the compiler's diagnostic.
+ *
+ * However, as some compilers don't provide intrinsics for certain
+ * types, the default implementation of add is the version from falback.
+ *
+ * The struct is explicitly specialized for each type via #ifdefs for
+ * each compiler.
+ */
+ template <typename T>
+ struct builtin_add_overflow
+ {
+ /*!
+ * @brief Add summand_1 and summand_2 and check for overflows.
+ *
+ * This is the default add() function that uses
+ * fallback_add_overflow<T>::add(). All specializations must have
+ * exactly the same interface and behave the same way.
+ */
+ static inline bool add(T summand_1, T summand_2, T& result)
+ {
+ return fallback_add_overflow<T>::add(summand_1, summand_2, result);
+ }
+ };
+
+#if defined(__GNUC__) || defined(__clang__)
+
+/*!
+ * This macro pastes a specialization of builtin_add_overflow using gcc's &
+ * clang's __builtin_(s/u)add(l)(l)_overlow()
+ *
+ * The add function is implemented by forwarding the parameters to the intrinsic
+ * and returning its value.
+ *
+ * The intrinsics are documented here:
+ * https://gcc.gnu.org/onlinedocs/gcc/Integer-Overflow-Builtins.html#Integer-Overflow-Builtins
+ */
+#define SPECIALIZE_builtin_add_overflow(type, builtin_name) \
+ template <> \
+ struct builtin_add_overflow<type> \
+ { \
+ static inline bool add(type summand_1, type summand_2, type& result) \
+ { \
+ return builtin_name(summand_1, summand_2, &result); \
+ } \
+ }
+
+ SPECIALIZE_builtin_add_overflow(int, __builtin_sadd_overflow);
+ SPECIALIZE_builtin_add_overflow(long, __builtin_saddl_overflow);
+ SPECIALIZE_builtin_add_overflow(long long, __builtin_saddll_overflow);
+
+ SPECIALIZE_builtin_add_overflow(unsigned int, __builtin_uadd_overflow);
+ SPECIALIZE_builtin_add_overflow(unsigned long, __builtin_uaddl_overflow);
+ SPECIALIZE_builtin_add_overflow(unsigned long long, __builtin_uaddll_overflow);
+
+#undef SPECIALIZE_builtin_add_overflow
+
+#elif defined(_MSC_VER)
+
+/*!
+ * This macro pastes a specialization of builtin_add_overflow using MSVC's
+ * U(Int/Long/LongLong)Add.
+ *
+ * The add function is implemented by forwarding the parameters to the
+ * intrinsic. As MSVC's intrinsics return S_OK on success, this specialization
+ * returns whether the intrinsics return value does not equal S_OK. This ensures
+ * a uniform interface of the add function (false is returned when no overflow
+ * occurs, true on overflow).
+ *
+ * The intrinsics are documented here:
+ * https://msdn.microsoft.com/en-us/library/windows/desktop/ff516460(v=vs.85).aspx
+ */
+#define SPECIALIZE_builtin_add_overflow_WIN(type, builtin_name) \
+ template <> \
+ struct builtin_add_overflow<type> \
+ { \
+ static inline bool add(type summand_1, type summand_2, type& result) \
+ { \
+ return builtin_name(summand_1, summand_2, &result) != S_OK; \
+ } \
+ }
+
+ SPECIALIZE_builtin_add_overflow_WIN(unsigned int, UIntAdd);
+ SPECIALIZE_builtin_add_overflow_WIN(unsigned long, ULongAdd);
+ SPECIALIZE_builtin_add_overflow_WIN(unsigned long long, ULongLongAdd);
+
+#undef SPECIALIZE_builtin_add_overflow_WIN
+
+#endif
+
+ } // namespace Internal
+
+ /*!
+ * @brief Safe addition, throws an exception on overflow.
+ *
+ * This function returns the result of summand_1 and summand_2 only when the
+ * operation would not overflow, otherwise an exception of type
+ * std::overflow_error is thrown.
+ *
+ * @param[in] summand_1, summand_2 summands to be summed up
+ * @return the sum of summand_1 and summand_2
+ * @throws std::overflow_error if the addition would overflow
+ *
+ * This function utilizes compiler builtins when available and should have a
+ * very small performance hit then. When builtins are unavailable, a more
+ * extensive check is required.
+ *
+ * Builtins are available for the following configurations:
+ * - GCC/Clang for signed and unsigned int, long and long long (not char & short)
+ * - MSVC for unsigned int, long and long long
+ */
+ template <typename T>
+ T add(T summand_1, T summand_2)
+ {
+ T res = 0;
+ if (Internal::builtin_add_overflow<T>::add(summand_1, summand_2, res)) {
+ throw std::overflow_error("Overflow in addition");
+ }
+ return res;
+ }
+
+} // namespace Safe
+
+#endif // SAFE_OP_HPP_

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

76
exiv2-CVE-2018-5772.patch Normal file
View File

@ -0,0 +1,76 @@
diff --git a/src/cr2image.cpp b/src/cr2image.cpp
index 2907426..b6fa315 100644
--- a/src/cr2image.cpp
+++ b/src/cr2image.cpp
@@ -107,8 +107,6 @@ namespace Exiv2 {
throw Error(3, "CR2");
}
clearMetadata();
- std::ofstream devnull;
- printStructure(devnull, kpsRecursive, 0);
ByteOrder bo = Cr2Parser::decode(exifData_,
iptcData_,
xmpData_,
diff --git a/src/crwimage.cpp b/src/crwimage.cpp
index ca79aa7..11cd14c 100644
--- a/src/crwimage.cpp
+++ b/src/crwimage.cpp
@@ -131,15 +131,8 @@ namespace Exiv2 {
throw Error(33);
}
clearMetadata();
- // read all metadata into memory
- // we should put this into clearMetadata(), however it breaks the test suite!
- try {
- std::ofstream devnull;
- printStructure(devnull,kpsRecursive,0);
- } catch (Exiv2::Error& /* e */) {
- DataBuf file(io().size());
- io_->read(file.pData_,file.size_);
- }
+ DataBuf file( (long) io().size());
+ io_->read(file.pData_,file.size_);
CrwParser::decode(this, io_->mmap(), io_->size());
diff --git a/src/orfimage.cpp b/src/orfimage.cpp
index c516591..9a17a50 100644
--- a/src/orfimage.cpp
+++ b/src/orfimage.cpp
@@ -119,8 +119,6 @@ namespace Exiv2 {
throw Error(3, "ORF");
}
clearMetadata();
- std::ofstream devnull;
- printStructure(devnull, kpsRecursive, 0);
ByteOrder bo = OrfParser::decode(exifData_,
iptcData_,
xmpData_,
diff --git a/src/rw2image.cpp b/src/rw2image.cpp
index 95f3b28..764de6f 100644
--- a/src/rw2image.cpp
+++ b/src/rw2image.cpp
@@ -130,8 +130,6 @@ namespace Exiv2 {
throw Error(3, "RW2");
}
clearMetadata();
- std::ofstream devnull;
- printStructure(devnull, kpsRecursive, 0);
ByteOrder bo = Rw2Parser::decode(exifData_,
iptcData_,
xmpData_,
diff --git a/src/tiffimage.cpp b/src/tiffimage.cpp
index f20c69e..9e6eda4 100644
--- a/src/tiffimage.cpp
+++ b/src/tiffimage.cpp
@@ -185,10 +185,6 @@ namespace Exiv2 {
}
clearMetadata();
- // recursively print the structure to /dev/null to ensure all metadata is in memory
- // must be recursive to handle NEFs which stores the raw image in a subIFDs
- std::ofstream devnull;
- printStructure(devnull,kpsRecursive,0);
ByteOrder bo = TiffParser::decode(exifData_,
iptcData_,
xmpData_,

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 {

21
exiv2-doxygen.patch Normal file
View File

@ -0,0 +1,21 @@
diff -up exiv2-trunk/config/Doxyfile.doxygen exiv2-trunk/config/Doxyfile
--- exiv2-trunk/config/Doxyfile.doxygen 2017-05-02 09:17:33.631909015 -0500
+++ exiv2-trunk/config/Doxyfile 2017-05-02 09:18:03.019200824 -0500
@@ -1688,7 +1688,7 @@ HIDE_UNDOC_RELATIONS = YES
# toolkit from AT&T and Lucent Bell Labs. The other options in this section
# have no effect if this option is set to NO (the default)
-HAVE_DOT = YES
+#HAVE_DOT = YES
# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is
# allowed to run in parallel. When set to 0 (the default) doxygen will
@@ -1705,7 +1705,7 @@ DOT_NUM_THREADS = 0
# the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the
# directory containing the font.
-DOT_FONTNAME = Arial
+#DOT_FONTNAME = Arial
# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs.
# The default size is 10pt.

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);
}

115
exiv2.spec Normal file
View File

@ -0,0 +1,115 @@
Name: exiv2
Version: 0.26
Release: 14
Summary: Exif, IPTC and XMP metadata and the ICC Profile
License: GPLv2+
URL: http://www.exiv2.org/
Source0: https://github.com/Exiv2/%{name}/archive/exiv2-%{version}.tar.gz
Patch0: exiv2-simplify-compiler-info-in-cmake.patch
Patch1: exiv2-fix-documentation-build.patch
Patch2: 0006-1296-Fix-submitted.patch
Patch10: exiv2-CVE-2017-17723.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
Patch100: exiv2-doxygen.patch
Patch6000: CVE-2018-19107-CVE-2018-19108-1.patch
Patch6001: CVE-2018-19107-CVE-2018-19108-2.patch
Patch6002: CVE-2018-17229-CVE-2018-17230.patch
Patch6003: CVE-2018-17282.patch
Patch6004: CVE-2017-1000126.patch
Patch6005: CVE-2018-19607.patch
Patch6006: CVE-2018-18915.patch
Patch6007: CVE-2019-13110.patch
Patch6008: CVE-2019-13113.patch
Patch6009: CVE-2019-13114.patch
Patch6010: CVE-2019-14982.patch
Provides: exiv2-libs
Obsoletes: exiv2-libs
BuildRequires: cmake expat-devel gcc-c++ gettext pkgconfig pkgconfig(libcurl) pkgconfig(libssh)
BuildRequires: doxygen graphviz libxslt zlib-devel
%description
Exiv2 is a Cross-platform C++ library and a command line utility to manage image metadata.
It provides fast and easy read and write access to the Exif, IPTC and XMP metadata and the
ICC Profile embedded within digital images in various formats.
%package devel
Summary: This package contains libraries, header and development files for exiv2
Requires: %{name} = %{version}-%{release}
%description devel
Exiv2 is a Cross-platform C++ library and a command line utility to manage image metadata.
This package provides head file,libraries for exiv2.
%package help
Summary: help documentation for exiv2
BuildArch: noarch
%description help
Man pages and other related documents.
%prep
%autosetup -p1
%build
export CPPFLAGS="-DBanAllEntityUsage=1"
%{cmake} -DEXIV2_ENABLE_BUILD_PO:BOOL=ON -DEXIV2_ENABLE_BUILD_SAMPLES:BOOL=OFF -DEXIV2_ENABLE_LIBXMP:BOOL=ON
%make_build
make doc
%install
%make_install
%find_lang exiv2
%check
export PKG_CONFIG_PATH=%{buildroot}%{_libdir}/pkgconfig
test "$(pkg-config --modversion exiv2)" = "%{version}"
test -x %{buildroot}%{_libdir}/libexiv2.so
%files -f exiv2.lang
%defattr(-,root,root)
%doc doc/ChangeLog COPYING
%{_bindir}/exiv2
%{_libdir}/libexiv2.so.26*
%exclude %{_libdir}/pkgconfig/exiv2.lsm
%exclude %{_libdir}/libxmp.a
%files devel
%{_libdir}/pkgconfig/exiv2.pc
%{_libdir}/libexiv2.so
%{_includedir}/exiv2/
%files help
%{_mandir}/man1/exiv2*.1*
%{_datadir}/doc/html/
%changelog
* Wed Sep 25 2019 huzunhao<huzunhao2@huawei.com> - 0.26-12.14
- Type:cves
- ID:CVE-2019-14982
- SUG:NA
- DESC:fix CVE-2019-14982
* Sat Sep 21 2019 Yanjie Guan <guanyanjie@huawei.com> - 0.26-12.13
- Package init for openEuler