Upgrade to 0.27.5

This commit is contained in:
wk333 2021-11-23 11:27:29 +08:00
parent ac4ca436ce
commit 6fdebf1ffa
63 changed files with 20 additions and 4421 deletions

View File

@ -1,37 +0,0 @@
From 03173751b4d7053d6ddf52a15904e8f751f78f56 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Luis=20D=C3=ADaz=20M=C3=A1s?= <piponazo@gmail.com>
Date: Sun, 2 Sep 2018 14:39:52 +0200
Subject: [PATCH] Fix bug in PngChunk::readRawProfile
- Now it takes into account text.size_ when searching for a newline
char.
---
src/pngchunk_int.cpp | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/src/pngchunk.cpp b/src/pngchunk.cpp
index 58281b3ff..755872c94 100644
--- a/src/pngchunk.cpp
+++ b/src/pngchunk.cpp
@@ -629,11 +629,19 @@ namespace Exiv2 {
sp = (char*)text.pData_+1;
+ int pointerPos = 1;
// Look for newline
-
- while (*sp != '\n')
+ while (*sp != '\n' && pointerPos < (text.size_ - 1))
+ {
sp++;
+ pointerPos++;
+ }
+
+ if (pointerPos == (text.size_ - 1))
+ {
+ return DataBuf();
+ }
// Look for length

View File

@ -1,80 +0,0 @@
From b0410707780daff1126a460cb294c144e36e408e Mon Sep 17 00:00:00 2001
From: Kevin Backhouse <kev@semmle.com>
Date: Mon, 13 May 2019 14:57:09 +0100
Subject: [PATCH] Add bounds check on allocation size.
---
src/pngchunk.cpp | 20 +++++++++++++++++---
1 files changed, 17 insertions(+), 3 deletions(-)
diff --git a/src/pngchunk.cpp b/src/pngchunk.cpp
index bf389ee13..64a370e5f 100644
--- a/src/pngchunk.cpp
+++ b/src/pngchunk.cpp
@@ -625,8 +625,12 @@ namespace Exiv2 {
const char *sp = (char*) text.pData_+1; // current byte (space pointer)
const char *eot = (char*) text.pData_+text.size_; // end of text
+ if (sp >= eot) {
+ return DataBuf();
+ }
+
// Look for newline
- while (*sp != '\n' && sp < eot )
+ while (*sp != '\n')
{
sp++;
if ( sp == eot )
@@ -635,9 +639,12 @@ namespace Exiv2 {
}
}
sp++ ; // step over '\n'
+ if (sp == eot) {
+ return DataBuf();
+ }
// Look for length
- while ( (*sp == '\0' || *sp == ' ' || *sp == '\n') && sp < eot )
+ while (*sp == '\0' || *sp == ' ' || *sp == '\n')
{
sp++;
if (sp == eot )
@@ -647,7 +654,7 @@ namespace Exiv2 {
}
const char* startOfLength = sp;
- while ( ('0' <= *sp && *sp <= '9') && sp < eot)
+ while ('0' <= *sp && *sp <= '9')
{
sp++;
if (sp == eot )
@@ -656,8 +663,13 @@ namespace Exiv2 {
}
}
sp++ ; // step over '\n'
+ if (sp == eot) {
+ return DataBuf();
+ }
long length = (long) atol(startOfLength);
+ enforce(length >= 0, Exiv2::kerCorruptedMetadata);
+ enforce(length <= (eot - sp)/2, Exiv2::kerCorruptedMetadata);
// Allocate space
if (length == 0)
@@ -682,6 +694,7 @@ namespace Exiv2 {
for (long i = 0; i < (long) nibbles; i++)
{
+ enforce(sp < eot, Exiv2::kerCorruptedMetadata);
while (*sp < '0' || (*sp > '9' && *sp < 'a') || *sp > 'f')
{
if (*sp == '\0')
@@ -693,6 +706,7 @@ namespace Exiv2 {
}
sp++;
+ enforce(sp < eot, Exiv2::kerCorruptedMetadata);
}
if (i%2 == 0)

View File

@ -1,86 +0,0 @@
From cf3ba049a2792ec2a4a877e343f5dd9654da53dc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Luis=20D=C3=ADaz=20M=C3=A1s?= <piponazo@gmail.com>
Date: Mon, 3 Sep 2018 08:51:08 +0200
Subject: [PATCH] Fix more issues in PngChunk::readRawProfile
---
src/pngchunk.cpp | 36 +++++++++++++-----------
1 files changed, 20 insertions(+), 16 deletions(-)
diff --git a/src/pngchunk.cpp b/src/pngchunk.cpp
index 755872c94..9b3faf1aa 100644
--- a/src/pngchunk.cpp
+++ b/src/pngchunk.cpp
@@ -606,11 +606,6 @@ namespace Exiv2 {
DataBuf PngChunk::readRawProfile(const DataBuf& text,bool iTXt)
{
DataBuf info;
- register long i;
- register unsigned char *dp;
- const char *sp;
- unsigned int nibbles;
- long length;
unsigned char unhex[103]={0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,1, 2,3,4,5,6,7,8,9,0,0,
@@ -627,8 +622,7 @@ namespace Exiv2 {
return info;
}
-
- sp = (char*)text.pData_+1;
+ const char *sp = (char*)text.pData_+1;
int pointerPos = 1;
// Look for newline
@@ -638,20 +632,30 @@ namespace Exiv2 {
pointerPos++;
}
+ // Look for length
+ while ((*sp == '\0' || *sp == ' ' || *sp == '\n') && pointerPos < (text.size_ - 1))
+ {
+ sp++;
+ pointerPos++;
+ }
+
if (pointerPos == (text.size_ - 1))
{
return DataBuf();
}
- // Look for length
+ long length = (long) atol(sp);
- while (*sp == '\0' || *sp == ' ' || *sp == '\n')
+ while (*sp != ' ' && *sp != '\n' && pointerPos < (text.size_ - 1))
+ {
sp++;
+ pointerPos++;
+ }
- length = (long) atol(sp);
-
- while (*sp != ' ' && *sp != '\n')
- sp++;
+ if (pointerPos == (text.size_ - 1))
+ {
+ return DataBuf();
+ }
// Allocate space
@@ -674,10 +678,10 @@ namespace Exiv2 {
// Copy profile, skipping white space and column 1 "=" signs
- dp = (unsigned char*)info.pData_;
- nibbles = length * 2;
+ unsigned char *dp = (unsigned char*)info.pData_;
+ unsigned int nibbles = length * 2;
- for (i = 0; i < (long) nibbles; i++)
+ for (long i = 0; i < (long) nibbles; i++)
{
while (*sp < '0' || (*sp > '9' && *sp < 'a') || *sp > 'f')
{

View File

@ -1,23 +0,0 @@
From bcaca801fb0a3a594b35ab06044d1e8055ec04a7 Mon Sep 17 00:00:00 2001
From: Kevin Backhouse <kev@semmle.com>
Date: Tue, 14 May 2019 09:58:42 +0100
Subject: [PATCH] Merge two enforces into one.
---
src/pngchunk.cpp | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/src/pngchunk.cpp b/src/pngchunk.cpp
index 64a370e5f..714b95b48 100644
--- a/src/pngchunk.cpp
+++ b/src/pngchunk.cpp
@@ -668,8 +668,7 @@ namespace Exiv2 {
}
long length = (long) atol(startOfLength);
- enforce(length >= 0, Exiv2::kerCorruptedMetadata);
- enforce(length <= (eot - sp)/2, Exiv2::kerCorruptedMetadata);
+ enforce(0 <= length && length <= (eot - sp)/2, Exiv2::kerCorruptedMetadata);
// Allocate space
if (length == 0)

View File

@ -1,113 +0,0 @@
From 8b480bc5b2cc2abb8cf6fe4e16c24e58916464d2 Mon Sep 17 00:00:00 2001
From: Robin Mills <robin@clanmills.com>
Date: Mon, 10 Sep 2018 20:54:53 +0200
Subject: [PATCH] Fixes in PngChunk::readRawProfile
---
src/pngchunk.cpp | 55 ++++++++++++++++++++++----------------------
1 file changed, 27 insertions(+), 28 deletions(-)
diff --git a/src/pngchunk.cpp b/src/pngchunk.cpp
index 9b3faf1aa..f81b560aa 100644
--- a/src/pngchunk.cpp
+++ b/src/pngchunk.cpp
@@ -607,11 +607,11 @@ namespace Exiv2 {
{
DataBuf info;
unsigned char unhex[103]={0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,1, 2,3,4,5,6,7,8,9,0,0,
- 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,10,11,12,
- 13,14,15};
+ 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,1, 2,3,4,5,6,7,8,9,0,0,
+ 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,10,11,12,
+ 13,14,15};
if (text.size_ == 0) {
return DataBuf();
}
@@ -622,52 +622,51 @@ namespace Exiv2 {
return info;
}
- const char *sp = (char*)text.pData_+1;
- int pointerPos = 1;
+ const char *sp = (char*) text.pData_+1; // current byte (space pointer)
+ const char *eot = (char*) text.pData_+text.size_; // end of text
// Look for newline
- while (*sp != '\n' && pointerPos < (text.size_ - 1))
+ while (*sp != '\n' && sp < eot )
{
sp++;
- pointerPos++;
+ if ( sp == eot )
+ {
+ return DataBuf();
+ }
}
+ sp++ ; // step over '\n'
// Look for length
- while ((*sp == '\0' || *sp == ' ' || *sp == '\n') && pointerPos < (text.size_ - 1))
+ while ( (*sp == '\0' || *sp == ' ' || *sp == '\n') && sp < eot )
{
sp++;
- pointerPos++;
- }
-
- if (pointerPos == (text.size_ - 1))
- {
- return DataBuf();
+ if (sp == eot )
+ {
+ return DataBuf();
+ }
}
- long length = (long) atol(sp);
-
- while (*sp != ' ' && *sp != '\n' && pointerPos < (text.size_ - 1))
+ const char* startOfLength = sp;
+ while ( ('0' <= *sp && *sp <= '9') && sp < eot)
{
sp++;
- pointerPos++;
+ if (sp == eot )
+ {
+ return DataBuf();
+ }
}
+ sp++ ; // step over '\n'
- if (pointerPos == (text.size_ - 1))
- {
- return DataBuf();
- }
+ long length = (long) atol(startOfLength);
// Allocate space
-
if (length == 0)
{
#ifdef DEBUG
std::cerr << "Exiv2::PngChunk::readRawProfile: Unable To Copy Raw Profile: invalid profile length\n";
#endif
}
-
info.alloc(length);
-
if (info.size_ != length)
{
#ifdef DEBUG
@@ -678,7 +677,7 @@ namespace Exiv2 {
// Copy profile, skipping white space and column 1 "=" signs
- unsigned char *dp = (unsigned char*)info.pData_;
+ unsigned char *dp = (unsigned char*)info.pData_; // decode pointer
unsigned int nibbles = length * 2;
for (long i = 0; i < (long) nibbles; i++)

View File

@ -1,25 +0,0 @@
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

View File

@ -1,42 +0,0 @@
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

@ -1,45 +0,0 @@
From e40c9c148e4d2135d0d732b8dff994a9afde3394 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 Jul 2018 11:51:55 +0200
Subject: [PATCH] Remove buffer overread in tExtToDataBuf
The pointer p is advanced in the while loop to step over three '\n'.
However, its length is never reduced accordingly. => the length check in the
following for loop is invalid, as it permits overreading by the number of
characters that p was advanced by.
---
src/pngimage.cpp | 15 ++++++++++++---
1 file changed, 12 insertions(+), 3 deletions(-)
diff --git a/src/pngimage.cpp b/src/pngimage.cpp
index dc623c4..a99a20b 100644
--- a/src/pngimage.cpp
+++ b/src/pngimage.cpp
@@ -160,12 +160,21 @@ namespace Exiv2 {
}
// calculate length and allocate result;
+ // count: number of \n in the header
long count=0;
+ // p points to the current position in the array bytes
const byte* p = bytes ;
- // header is \nsomething\n number\n hex
- while ( count < 3 )
- if ( *p++ == '\n' )
+
+ // header is '\nsomething\n number\n hex'
+ // => increment p until it points to the byte after the last \n
+ // p must stay within bounds of the bytes array!
+ while ((count < 3) && (p - bytes < length)) {
+ // length is later used for range checks of p => decrement it for each increment of p
+ --length;
+ if ( *p++ == '\n' ) {
count++;
+ }
+ }
for ( long i = 0 ; i < length ; i++ )
if ( value[p[i]] )
++count;
--
1.8.3.1

View File

@ -1,146 +0,0 @@
From 35b3e596edacd2437c2c5d3dd2b5c9502626163d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Dan=20=C4=8Cerm=C3=A1k?= <dan.cermak@cgc-instruments.com>
Date: Fri, 17 Aug 2018 16:41:05 +0200
Subject: [PATCH] Add overflow & overread checks to PngChunk::parseTXTChunk()
This function was creating a lot of new pointers and strings without
properly checking the array bounds. This commit adds several calls
to enforce(), making sure that the pointers stay within bounds.
Strings are now created using the helper function
string_from_unterminated() to prevent overreads in the constructor of
std::string.
This fixes #400
---
src/pngchunk_int.cpp | 63 ++++++++++++++++++++++++++------------------
1 file changed, 37 insertions(+), 26 deletions(-)
diff --git a/src/pngchunk.cpp b/src/pngchunk.cpp
index e087e47cb..f13594bd8 100644
--- a/src/pngchunk.cpp
+++ b/src/pngchunk.cpp
@@ -34,6 +34,7 @@
#include "image.hpp"
#include "error.hpp"
#include "enforce.hpp"
+#include "safe_op.hpp"
// + standard includes
#include <sstream>
@@ -55,6 +54,13 @@ EXIV2_RCSID("@(#) $Id: pngchunk.cpp 3777 2015-05-02 11:55:40Z ahuggel $")
#include <zlib.h> // To uncompress or compress text chunk
+/* Added as support of CVE-2018-16336 */
+std::string string_from_unterminated(const char* data, size_t data_length)
+{
+ const size_t StringLength = strnlen(data, data_length);
+
+ return std::string(data, StringLength);
+}
/*
URLs to find informations about PNG chunks :
@@ -133,6 +135,8 @@ namespace Exiv2 {
if(type == zTXt_Chunk)
{
+ enforce(data.size_ >= Safe::add(keysize, 2), Exiv2::kerCorruptedMetadata);
+
// Extract a deflate compressed Latin-1 text chunk
// we get the compression method after the key
@@ -149,11 +153,13 @@ namespace Exiv2 {
// compressed string after the compression technique spec
const byte* compressedText = data.pData_ + keysize + 2;
unsigned int compressedTextSize = data.size_ - keysize - 2;
+ enforce(compressedTextSize < data.size_, kerCorruptedMetadata);
zlibUncompress(compressedText, compressedTextSize, arr);
}
else if(type == tEXt_Chunk)
{
+ enforce(data.size_ >= Safe::add(keysize, 1), Exiv2::kerCorruptedMetadata);
// Extract a non-compressed Latin-1 text chunk
// the text comes after the key, but isn't null terminated
@@ -164,7 +170,8 @@ namespace Exiv2 {
}
else if(type == iTXt_Chunk)
{
+ enforce(data.size_ >= Safe::add(keysize, 3), Exiv2::kerCorruptedMetadata);
const int nullSeparators = std::count(&data.pData_[keysize+3], &data.pData_[data.size_], '\0');
enforce(nullSeparators >= 2, Exiv2::kerCorruptedMetadata);
@@ -178,40 +185,44 @@ namespace Exiv2 {
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());
+ const size_t languageTextMaxSize = data.size_ - keysize - 3;
+ std::string languageText =
+ string_from_unterminated((const char*)(data.pData_ + Safe::add(keysize, 3)), languageTextMaxSize);
+ const unsigned int languageTextSize = static_cast<unsigned int>(languageText.size());
+
+ enforce(data.size_ >= Safe::add(static_cast<unsigned int>(Safe::add(keysize, 4)), languageTextSize),
+ Exiv2::kerCorruptedMetadata);
// translated keyword string after the language description
- std::string translatedKeyText((const char*)(data.pData_ + keysize + 3 + languageTextSize +1));
- unsigned int translatedKeyTextSize = static_cast<unsigned int>(translatedKeyText.size());
+ std::string translatedKeyText =
+ string_from_unterminated((const char*)(data.pData_ + keysize + 3 + languageTextSize + 1),
+ data.size_ - (keysize + 3 + languageTextSize + 1));
+ const unsigned int translatedKeyTextSize = static_cast<unsigned int>(translatedKeyText.size());
- if ( compressionFlag == 0x00 )
- {
- // then it's an uncompressed iTXt chunk
-#ifdef DEBUG
- std::cout << "Exiv2::PngChunk::parseTXTChunk: We found an uncompressed iTXt field\n";
-#endif
+ if ((compressionFlag == 0x00) || (compressionFlag == 0x01 && compressionMethod == 0x00)) {
+ enforce(Safe::add(static_cast<unsigned int>(keysize + 3 + languageTextSize + 1),
+ Safe::add(translatedKeyTextSize, 1u)) <= data.size_,
+ Exiv2::kerCorruptedMetadata);
- // the text comes after the translated keyword, but isn't null terminated
const byte* text = data.pData_ + keysize + 3 + languageTextSize + 1 + translatedKeyTextSize + 1;
- long textsize = data.size_ - (keysize + 3 + languageTextSize + 1 + translatedKeyTextSize + 1);
+ const long textsize = data.size_ - (keysize + 3 + languageTextSize + 1 + translatedKeyTextSize + 1);
- arr.alloc(textsize);
- arr = DataBuf(text, textsize);
- }
- else if ( compressionFlag == 0x01 && compressionMethod == 0x00 )
- {
- // then it's a zlib compressed iTXt chunk
+ if (compressionFlag == 0x00) {
+ // then it's an uncompressed iTXt chunk
#ifdef DEBUG
- std::cout << "Exiv2::PngChunk::parseTXTChunk: We found a zlib compressed iTXt field\n";
+ std::cout << "Exiv2::PngChunk::parseTXTChunk: We found an uncompressed iTXt field\n";
#endif
- // the compressed text comes after the translated keyword, but isn't null terminated
- const byte* compressedText = data.pData_ + keysize + 3 + languageTextSize + 1 + translatedKeyTextSize + 1;
- long compressedTextSize = data.size_ - (keysize + 3 + languageTextSize + 1 + translatedKeyTextSize + 1);
+ arr.alloc(textsize);
+ arr = DataBuf(text, textsize);
+ } else if (compressionFlag == 0x01 && compressionMethod == 0x00) {
+ // then it's a zlib compressed iTXt chunk
+#ifdef DEBUG
+ std::cout << "Exiv2::PngChunk::parseTXTChunk: We found a zlib compressed iTXt field\n";
+#endif
- zlibUncompress(compressedText, compressedTextSize, arr);
- }
- else
- {
+ // the compressed text comes after the translated keyword, but isn't null terminated
+ zlibUncompress(text, textsize, arr);
+ }
+ } else {
// then it isn't zlib compressed and we are sunk
#ifdef DEBUG
std::cerr << "Exiv2::PngChunk::parseTXTChunk: Non-standard iTXt compression method.\n";

View File

@ -1,22 +0,0 @@
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);
}

View File

@ -1,40 +0,0 @@
--- 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()
{

View File

@ -1,41 +0,0 @@
From b3d077dcaefb6747fff8204490f33eba5a144edb Mon Sep 17 00:00:00 2001
From: Robin Mills <robin@clanmills.com>
Date: Sat, 13 Oct 2018 11:38:56 +0200
Subject: [PATCH] Fix #460 by adding more checks in
CiffDirectory::readDirectory
---
src/crwimage.cpp | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/src/crwimage.cpp b/src/crwimage.cpp
index 0c04761..ebe1da7 100644
--- a/src/crwimage.cpp
+++ b/src/crwimage.cpp
@@ -451,16 +451,21 @@ namespace Exiv2 {
uint32_t size,
ByteOrder byteOrder)
{
+ if (size < 4)
+ throw Error(33);
uint32_t o = getULong(pData + size - 4, byteOrder);
- if (size < 2 || o > size-2) throw Error(33);
+ if ( o+2 > size )
+ throw Error(33);
uint16_t count = getUShort(pData + o, byteOrder);
#ifdef DEBUG
std::cout << "Directory at offset " << std::dec << o
<<", " << count << " entries \n";
#endif
o += 2;
+ if ( (o + (count * 10)) > size )
+ throw Error(33);
+
for (uint16_t i = 0; i < count; ++i) {
- if (size < 10 || o > size-10) throw Error(33);
uint16_t tag = getUShort(pData + o, byteOrder);
CiffComponent::AutoPtr m;
switch (CiffComponent::typeId(tag)) {
--
2.19.1

View File

@ -1,27 +0,0 @@
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

@ -1,31 +0,0 @@
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

@ -1,32 +0,0 @@
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)

View File

@ -1,31 +0,0 @@
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;
}

View File

@ -1,72 +0,0 @@
From fcb42570519f8cf924b0302b09062a60aa565fbe Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Dan=20=C4=8Cerm=C3=A1k?= <dan.cermak@cgc-instruments.com>
Date: Tue, 9 Jan 2018 21:18:36 +0100
Subject: [PATCH 1/2] Add check for DataBuf.size_ in Jp2Image::readMetadata()
When parsing a subBox that is a ColorHeader, a length is extracted
from the input file and fed directly into DataBuf() (which calls
malloc). A crafted input file can provide arbitrarily (up to
max(uint32_t)-8) large values and result in excessive memory
allocation.
This commit adds a check for the new size of DataBuf so that it is not
larger than the remaining size of the file.
This fixes #202 aka CVE-2018-4868
---
src/jp2image.cpp | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/src/jp2image.cpp b/src/jp2image.cpp
index 20727844d..8dd6c9c1b 100644
--- a/src/jp2image.cpp
+++ b/src/jp2image.cpp
@@ -268,7 +268,12 @@ namespace Exiv2
#endif
const long pad = 3 ; // 3 padding bytes 2 0 0
- DataBuf data(Safe::add(subBox.length, static_cast<uint32_t>(8)));
+ const size_t data_length = Safe::add(subBox.length, static_cast<uint32_t>(8));
+ // data_length makes no sense if it is larger than the rest of the file
+ if (data_length > io_->size() - io_->tell()) {
+ throw Error(58);
+ }
+ DataBuf data(data_length);
io_->read(data.pData_,data.size_);
const long iccLength = getULong(data.pData_+pad, bigEndian);
// subtracting pad from data.size_ is safe:
From 72de0f96f35d05ba68b28f4fa82f51a1df2778ca Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Dan=20=C4=8Cerm=C3=A1k?= <dan.cermak@cgc-instruments.com>
Date: Tue, 9 Jan 2018 21:27:20 +0100
Subject: [PATCH 2/2] Added reproducer for CVE-2018-4868 to the test suite
---
tests/bugfixes/github/test_CVE_2018_4868.py | 18 ++++++++++++++++++
1 files changed, 18 insertions(+)
create mode 100644 tests/bugfixes/github/test_CVE_2018_4868.py
diff --git a/tests/bugfixes/github/test_CVE_2018_4868.py b/tests/bugfixes/github/test_CVE_2018_4868.py
new file mode 100644
index 000000000..434eec6b4
--- /dev/null
+++ b/tests/bugfixes/github/test_CVE_2018_4868.py
@@ -0,0 +1,18 @@
+# -*- coding: utf-8 -*-
+
+import system_tests
+
+
+class TestCvePoC(system_tests.Case):
+
+ url = "https://github.com/Exiv2/exiv2/issues/202"
+ cve_url = "http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-4868"
+ found_by = ["afl", "topsecLab", "xcainiao"]
+
+ filename = "{data_path}/exiv2-memorymmap-error"
+ commands = ["{exiv2} " + filename]
+ stdout = [""]
+ stderr = ["""{exiv2_exception_msg} """ + filename + """:
+{error_58_message}
+"""]
+ retval = [1]

View File

@ -1,27 +0,0 @@
From c03f73268f65c73f9d3d7b670f13e48e92692750 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Roberto=20C=2E=20S=C3=A1nchez?= <roberto@connexer.com>
Date: Fri, 18 Sep 2020 14:40:36 +0800
Subject: [PATCH] Prevent SIGABRT on excessive subBox length in jp2image.cpp
This fixes CVE-2018-9145
---
src/jp2image.cpp | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/src/jp2image.cpp b/src/jp2image.cpp
index 3cebc2a..6a662fa 100644
--- a/src/jp2image.cpp
+++ b/src/jp2image.cpp
@@ -505,6 +505,10 @@ namespace Exiv2
subBox.length = getLong((byte*)&subBox.length, bigEndian);
subBox.type = getLong((byte*)&subBox.type, bigEndian);
+ // subBox.length makes no sense if it is larger than the rest of the file
+ if (subBox.length > io_->size() - io_->tell()) {
+ throw Error(kerCorruptedMetadata);
+ }
DataBuf data(subBox.length-sizeof(box));
io_->read(data.pData_,data.size_);
if ( bPrint ) {
--
2.27.0

View File

@ -1,61 +0,0 @@
From c0ecc2ae36f34462be98623deb85ba1747ae2175 Mon Sep 17 00:00:00 2001
From: Kevin Backhouse <kev@semmle.com>
Date: Mon, 13 May 2019 16:56:29 +0100
Subject: [PATCH] Avoid integer overflow.
---
src/crwimage.cpp | 4 ++--
tests/bugfixes/github/test_issue_843.py | 22 ++++++++++++++++++++++
2 files changed, 24 insertions(+), 2 deletions(-)
create mode 100644 tests/bugfixes/github/test_issue_843.py
diff --git a/src/crwimage.cpp b/src/crwimage.cpp
index c2fd5f3a5..4080c0787 100644
--- a/src/crwimage.cpp
+++ b/src/crwimage.cpp
@@ -281,7 +281,7 @@ namespace Exiv2 {
if (size < 4)
throw Error(33);
uint32_t o = getULong(pData + size - 4, byteOrder);
- if ( o+2 > size )
+ if ( o > size-2 )
throw Error(33);
uint16_t count = getUShort(pData + o, byteOrder);
#ifdef DEBUG
@@ -289,7 +289,7 @@ namespace Exiv2 {
<<", " << count << " entries \n";
#endif
o += 2;
- if ( (o + (count * 10)) > size )
+ if ( static_cast<uint32_t>(count) * 10 > size-o )
throw Error(33);
for (uint16_t i = 0; i < count; ++i) {
diff --git a/tests/bugfixes/github/test_issue_843.py b/tests/bugfixes/github/test_issue_843.py
new file mode 100644
index 000000000..2df9c1cf8
--- /dev/null
+++ b/tests/bugfixes/github/test_issue_843.py
@@ -0,0 +1,22 @@
+# -*- coding: utf-8 -*-
+
+from system_tests import CaseMeta, path
+
+
+class IntegerOverflowInCiffDirectoryReadDirectory(metaclass=CaseMeta):
+ """
+ Regression test for the bug described in:
+ https://github.com/Exiv2/exiv2/issues/843
+
+ An integer overflow causes an out-of-bounds read.
+ """
+ url = "https://github.com/Exiv2/exiv2/issues/843"
+
+ filename = path("$data_path/issue_843_poc.crw")
+ commands = ["$exiv2 $filename"]
+ stdout = [""]
+ stderr = [
+ """$exiv2_exception_message $filename:
+$kerCorruptedMetadata
+"""]
+ retval = [1]

View File

@ -1,11 +0,0 @@
--- 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)) {

View File

@ -1,38 +0,0 @@
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

View File

@ -1,53 +0,0 @@
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 ) {

View File

@ -1,29 +0,0 @@
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) {

View File

@ -1,57 +0,0 @@
From 22ea582c6b74ada30bec3a6b15de3c3e52f2b4da Mon Sep 17 00:00:00 2001
From: Robin Mills <robin@clanmills.com>
Date: Mon, 5 Apr 2021 20:33:25 +0100
Subject: [PATCH] fix_1522_jp2image_exif_asan
---
src/jp2image.cpp | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/src/jp2image.cpp b/src/jp2image.cpp
index a81e68f..8e36276 100644
--- a/src/jp2image.cpp
+++ b/src/jp2image.cpp
@@ -38,6 +38,7 @@ EXIV2_RCSID("@(#) $Id$")
#include "image.hpp"
#include "image_int.hpp"
#include "basicio.hpp"
+#include "enforce.hpp"
#include "error.hpp"
#include "futils.hpp"
#include "types.hpp"
@@ -345,7 +346,7 @@ namespace Exiv2
if (io_->error()) throw Error(14);
if (bufRead != rawData.size_) throw Error(20);
- if (rawData.size_ > 0)
+ if (rawData.size_ > 8) // "II*\0long"
{
// Find the position of Exif header in bytes array.
long pos = ( (rawData.pData_[0] == rawData.pData_[1])
@@ -484,6 +485,7 @@ namespace Exiv2
position = io_->tell();
box.length = getLong((byte*)&box.length, bigEndian);
box.type = getLong((byte*)&box.type, bigEndian);
+ enforce(box.length <= io_->size()-io_->tell() , Exiv2::kerCorruptedMetadata);
if ( bPrint ) {
out << Internal::stringFormat("%8ld | %8ld | ",position-sizeof(box),box.length) << toAscii(box.type) << " | " ;
@@ -560,12 +562,13 @@ namespace Exiv2
if (bufRead != rawData.size_) throw Error(20);
if ( bPrint ){
- out << Internal::binaryToString(rawData,40,0);
+ out << Internal::binaryToString(
+ rawData, rawData.size_>40?40:rawData.size_, 0);
out.flush();
}
lf(out,bLF);
- if(bIsExif && bRecursive && rawData.size_ > 0)
+ if(bIsExif && bRecursive && rawData.size_ > 8) // "II*\0long"
{
if ( (rawData.pData_[0] == rawData.pData_[1])
&& (rawData.pData_[0]=='I' || rawData.pData_[0]=='M' )
--
2.23.0

View File

@ -1,26 +0,0 @@
From caa4e6745a76a23bb80127cf54c0d65096ae684c Mon Sep 17 00:00:00 2001
From: Kevin Backhouse <kev@semmle.com>
Date: Tue, 30 Apr 2019 09:26:18 +0100
Subject: [PATCH] Avoid negative integer overflow when `filesize <
io_->tell()`.
This fixes #791.
---
src/webpimage.cpp | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/webpimage.cpp b/src/webpimage.cpp
index 9d7272c..6fe2ddb 100644
--- a/src/webpimage.cpp
+++ b/src/webpimage.cpp
@@ -45,6 +45,7 @@
#include "tiffimage_int.hpp"
#include "convert.hpp"
#include "enforce.hpp"
+#include "safe_op.hpp"
#include <cmath>
#include <iomanip>
--
2.23.0

View File

@ -1,116 +0,0 @@
From caa4e6745a76a23bb80127cf54c0d65096ae684c Mon Sep 17 00:00:00 2001
From: Kevin Backhouse <kev@semmle.com>
Date: Tue, 30 Apr 2019 09:26:18 +0100
Subject: [PATCH] Avoid negative integer overflow when `filesize <
io_->tell()`.
This fixes #791.
---
src/webpimage.cpp | 33 +++++++++++++++++++++------------
1 file changed, 21 insertions(+), 12 deletions(-)
diff --git a/src/webpimage.cpp b/src/webpimage.cpp
index 51a200b..9d7272c 100644
--- a/src/webpimage.cpp
+++ b/src/webpimage.cpp
@@ -67,6 +67,15 @@ namespace Exiv2 {
namespace Exiv2 {
using namespace Exiv2::Internal;
+ // This static function is a temporary fix in v0.27. In the next version,
+ // it will be added as a method of BasicIo.
+ static void readOrThrow(BasicIo& iIo, byte* buf, long rcount, ErrorCode err) {
+ const long nread = iIo.read(buf, rcount);
+ enforce(nread == rcount, err);
+ enforce(!iIo.error(), err);
+ }
+
+
WebPImage::WebPImage(BasicIo::AutoPtr io)
: Image(ImageType::webp, mdNone, io)
{
@@ -512,7 +521,7 @@ namespace Exiv2 {
DataBuf chunkId(5);
chunkId.pData_[4] = '\0' ;
- io_->readOrThrow(data, WEBP_TAG_SIZE * 3, Exiv2::kerCorruptedMetadata);
+ readOrThrow(*io_, data, WEBP_TAG_SIZE * 3, Exiv2::kerCorruptedMetadata);
const uint32_t filesize = Exiv2::getULong(data + WEBP_TAG_SIZE, littleEndian) + 8;
enforce(filesize <= io_->size(), Exiv2::kerCorruptedMetadata);
@@ -532,8 +541,8 @@ namespace Exiv2 {
chunkId.pData_[4] = '\0' ;
while ( !io_->eof() && (uint64_t) io_->tell() < filesize) {
- io_->readOrThrow(chunkId.pData_, WEBP_TAG_SIZE, Exiv2::kerCorruptedMetadata);
- io_->readOrThrow(size_buff, WEBP_TAG_SIZE, Exiv2::kerCorruptedMetadata);
+ readOrThrow(*io_, chunkId.pData_, WEBP_TAG_SIZE, Exiv2::kerCorruptedMetadata);
+ readOrThrow(*io_, size_buff, WEBP_TAG_SIZE, Exiv2::kerCorruptedMetadata);
const uint32_t size = Exiv2::getULong(size_buff, littleEndian);
enforce(io_->tell() <= filesize, Exiv2::kerCorruptedMetadata);
enforce(size <= (filesize - io_->tell()), Exiv2::kerCorruptedMetadata);
@@ -545,8 +554,8 @@ namespace Exiv2 {
has_canvas_data = true;
byte size_buf[WEBP_TAG_SIZE];
-
- io_->readOrThrow(payload.pData_, payload.size_, Exiv2::kerCorruptedMetadata);
+
+ readOrThrow(*io_, payload.pData_, payload.size_, Exiv2::kerCorruptedMetadata);
// Fetch width
memcpy(&size_buf, &payload.pData_[4], 3);
@@ -561,7 +570,7 @@ namespace Exiv2 {
enforce(size >= 10, Exiv2::kerCorruptedMetadata);
has_canvas_data = true;
- io_->readOrThrow(payload.pData_, payload.size_, Exiv2::kerCorruptedMetadata);
+ readOrThrow(*io_, payload.pData_, payload.size_, Exiv2::kerCorruptedMetadata);
byte size_buf[WEBP_TAG_SIZE];
// Fetch width""
@@ -582,7 +591,7 @@ namespace Exiv2 {
byte size_buf_w[2];
byte size_buf_h[3];
- io_->readOrThrow(payload.pData_, payload.size_, Exiv2::kerCorruptedMetadata);
+ readOrThrow(*io_, payload.pData_, payload.size_, Exiv2::kerCorruptedMetadata);
// Fetch width
memcpy(&size_buf_w, &payload.pData_[1], 2);
@@ -599,8 +608,8 @@ namespace Exiv2 {
has_canvas_data = true;
byte size_buf[WEBP_TAG_SIZE];
-
- io_->readOrThrow(payload.pData_, payload.size_, Exiv2::kerCorruptedMetadata);
+
+ readOrThrow(*io_, payload.pData_, payload.size_, Exiv2::kerCorruptedMetadata);
// Fetch width
memcpy(&size_buf, &payload.pData_[6], 3);
@@ -612,10 +621,10 @@ namespace Exiv2 {
size_buf[3] = 0;
pixelHeight_ = Exiv2::getULong(size_buf, littleEndian) + 1;
} else if (equalsWebPTag(chunkId, WEBP_CHUNK_HEADER_ICCP)) {
- io_->readOrThrow(payload.pData_, payload.size_, Exiv2::kerCorruptedMetadata);
+ readOrThrow(*io_, payload.pData_, payload.size_, Exiv2::kerCorruptedMetadata);
this->setIccProfile(payload);
} else if (equalsWebPTag(chunkId, WEBP_CHUNK_HEADER_EXIF)) {
- io_->readOrThrow(payload.pData_, payload.size_, Exiv2::kerCorruptedMetadata);
+ readOrThrow(*io_, payload.pData_, payload.size_, Exiv2::kerCorruptedMetadata);
byte size_buff[2];
byte exifLongHeader[] = { 0xFF, 0x01, 0xFF, 0xE1 };
@@ -696,7 +705,7 @@ namespace Exiv2 {
if (rawExifData) free(rawExifData);
} else if (equalsWebPTag(chunkId, WEBP_CHUNK_HEADER_XMP)) {
- io_->readOrThrow(payload.pData_, payload.size_, Exiv2::kerCorruptedMetadata);
+ readOrThrow(*io_, payload.pData_, payload.size_, Exiv2::kerCorruptedMetadata);
xmpPacket_.assign(reinterpret_cast<char*>(payload.pData_), payload.size_);
if (xmpPacket_.size() > 0 && XmpParser::decode(xmpData_, xmpPacket_)) {
#ifndef SUPPRESS_WARNINGS
--
2.23.0

View File

@ -1,59 +0,0 @@
From b5d2e4feea9c942bf4951f573410845dc5d81747 Mon Sep 17 00:00:00 2001
From: Kevin Backhouse <kev@semmle.com>
Date: Wed, 19 Feb 2020 15:55:54 +0800
Subject: [PATCH] Add better bounds checking in PngImage::printStructure().
---
src/pngimage.cpp | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)
diff --git a/src/pngimage.cpp b/src/pngimage.cpp
index 991da6c..516dcc2 100644
--- a/src/pngimage.cpp
+++ b/src/pngimage.cpp
@@ -241,7 +241,7 @@ namespace Exiv2 {
if (bufRead != cheaderBuf.size_) throw Error(20);
// Decode chunk data length.
- uint32_t dataOffset = Exiv2::getULong(cheaderBuf.pData_, Exiv2::bigEndian);
+ const uint32_t dataOffset = Exiv2::getULong(cheaderBuf.pData_, Exiv2::bigEndian);
for (int i = 4; i < 8; i++) {
chType[i-4]=cheaderBuf.pData_[i];
}
@@ -256,7 +256,8 @@ namespace Exiv2 {
}
DataBuf buff(dataOffset);
- io_->read(buff.pData_,dataOffset);
+ bufRead = io_->read(buff.pData_,dataOffset);
+ if (bufRead != static_cast<long>(dataOffset)) throw Exiv2::Error(14);
io_->seek(restore, BasicIo::beg);
// format output
@@ -269,7 +270,8 @@ namespace Exiv2 {
if ( bPrint ) {
io_->seek(dataOffset, BasicIo::cur);// jump to checksum
byte checksum[4];
- io_->read(checksum,4);
+ bufRead = io_->read(checksum,4);
+ if (bufRead != 4) throw Exiv2::Error(14);
io_->seek(restore, BasicIo::beg) ;// restore file pointer
out << Internal::stringFormat("%8d | %-5s |%8d | "
@@ -300,9 +302,12 @@ namespace Exiv2 {
DataBuf dataBuf;
byte* data = new byte[dataOffset+1];
data[dataOffset] = 0;
- io_->read(data,dataOffset);
+ bufRead = io_->read(data,dataOffset);
+ if (bufRead != static_cast<long>(dataOffset)) throw Exiv2::Error(14);
io_->seek(restore, BasicIo::beg);
uint32_t name_l = (uint32_t) std::strlen((const char*)data)+1; // leading string length
+ if (name_l > dataOffset) throw Exiv2::Error(58);
+
uint32_t start = name_l;
bool bLF = false;
--
2.19.1

View File

@ -1,36 +0,0 @@
From 1fc5ef40b15735e1b02ec752ec535c19831aafa6 Mon Sep 17 00:00:00 2001
From: Kevin Backhouse <kev@semmle.com>
Date: Thu, 25 Apr 2019 21:31:50 +0100
Subject: [PATCH] Avoid negative integer overflow when `iccOffset >
chunkLength`.
This fixes #790.
(cherry picked from commit 6fa2e31206127bd8bcac0269311f3775a8d6ea21)
---
src/pngimage.cpp | 2 ++
1 file changed, 2 insertions(+)
diff --git a/src/pngimage.cpp b/src/pngimage.cpp
index 49c8336..435dd3b 100644
--- a/src/pngimage.cpp
+++ b/src/pngimage.cpp
@@ -40,6 +40,7 @@ EXIV2_RCSID("@(#) $Id$")
#include "image_int.hpp"
#include "basicio.hpp"
#include "error.hpp"
+#include "enforce.hpp"
#include "futils.hpp"
#include "types.hpp"
@@ -480,6 +481,7 @@ namespace Exiv2 {
}
++iccOffset; // +1 = 'compressed' flag
+ enforce(iccOffset <= dataOffset, Exiv2::kerCorruptedMetadata);
zlibToDataBuf(cdataBuf.pData_ +iccOffset,dataOffset-iccOffset,iccProfile_);
#ifdef DEBUG
--
1.8.3.1

View File

@ -1,29 +0,0 @@
From 13e5a3e02339b746abcaee6408893ca2fd8e289d Mon Sep 17 00:00:00 2001
From: Pydera <pydera@mailbox.org>
Date: Thu, 8 Apr 2021 17:36:16 +0200
Subject: [PATCH] Fix out of buffer access in #1529
---
src/jp2image.cpp | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/src/jp2image.cpp b/src/jp2image.cpp
index b21f7f1..917d115 100644
--- a/src/jp2image.cpp
+++ b/src/jp2image.cpp
@@ -756,9 +756,10 @@ namespace Exiv2
#endif
box.length = io_->size() - io_->tell() + 8;
}
- if (box.length == 1)
+ if (box.length < 8)
{
- // FIXME. Special case. the real box size is given in another place.
+ // box is broken, so there is nothing we can do here
+ throw Error(kerCorruptedMetadata);
}
// Read whole box : Box header + Box data (not fixed size - can be null).
--
2.23.0

View File

@ -1,29 +0,0 @@
From c98d372b48adc6de859dc04e2e0c33441cfe136c Mon Sep 17 00:00:00 2001
From: Pydera <pydera@mailbox.org>
Date: Thu, 8 Apr 2021 17:11:38 +0200
Subject: [PATCH] Fix out of buffer access in #1530
---
src/crwimage_int.cpp | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/src/crwimage.cpp b/src/crwimage.cpp
index a44a67e2c..9155e0042 100644
--- a/src/crwimage.cpp
+++ b/src/crwimage.cpp
@@ -1186,11 +1186,13 @@ namespace Exiv2 {
CiffComponent* cc = pHead->findComponent(pCrwMapping->crwTagId_,
pCrwMapping->crwDir_);
if (edX != edEnd || edY != edEnd || edO != edEnd) {
- uint32_t size = 28;
+ size_t size = 28;
if (cc && cc->size() > size) size = cc->size();
DataBuf buf(size);
std::memset(buf.pData_, 0x0, buf.size_);
- if (cc) std::memcpy(buf.pData_ + 8, cc->pData() + 8, cc->size() - 8);
+ if (cc && cc->size() > 8) {
+ std::memcpy(buf.pData_ + 8, cc->pData() + 8, cc->size() - 8);
+ }
if (edX != edEnd && edX->size() == 4) {
edX->copy(buf.pData_, pHead->byteOrder());
}

View File

@ -1,123 +0,0 @@
From 783b3a6ff15ed6f82a8f8e6c8a6f3b84a9b04d4b Mon Sep 17 00:00:00 2001
From: Kevin Backhouse <kevinbackhouse@github.com>
Date: Mon, 19 Apr 2021 18:06:00 +0100
Subject: [PATCH] Improve bound checking in WebPImage::doWriteMetadata()
---
src/webpimage.cpp | 41 ++++++++++++++++++++++++++++++-----------
1 file changed, 30 insertions(+), 11 deletions(-)
diff --git a/src/webpimage.cpp b/src/webpimage.cpp
index c12e8fb..51a200b 100644
--- a/src/webpimage.cpp
+++ b/src/webpimage.cpp
@@ -144,7 +144,7 @@ namespace Exiv2 {
DataBuf chunkId(WEBP_TAG_SIZE+1);
chunkId.pData_ [WEBP_TAG_SIZE] = '\0';
- io_->read(data, WEBP_TAG_SIZE * 3);
+ readOrThrow(*io_, data, WEBP_TAG_SIZE * 3, Exiv2::kerCorruptedMetadata);
uint64_t filesize = Exiv2::getULong(data + WEBP_TAG_SIZE, littleEndian);
/* Set up header */
@@ -183,13 +183,20 @@ namespace Exiv2 {
case we have any exif or xmp data, also check
for any chunks with alpha frame/layer set */
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);
+ readOrThrow(*io_, chunkId.pData_, WEBP_TAG_SIZE, Exiv2::kerCorruptedMetadata);
+ readOrThrow(*io_, size_buff, WEBP_TAG_SIZE, Exiv2::kerCorruptedMetadata);
+ const uint32_t size_u32 = Exiv2::getULong(size_buff, littleEndian);
+
+ // Check that `size_u32` is safe to cast to `long`.
+ enforce(size_u32 <= static_cast<size_t>(std::numeric_limits<unsigned int>::max()),
+ Exiv2::kerCorruptedMetadata);
+ const long size = static_cast<long>(size_u32);
DataBuf payload(size);
- io_->read(payload.pData_, payload.size_);
- byte c;
- if ( payload.size_ % 2 ) io_->read(&c,1);
+ readOrThrow(*io_, payload.pData_, payload.size_, Exiv2::kerCorruptedMetadata);
+ if ( payload.size_ % 2 ) {
+ byte c;
+ readOrThrow(*io_, &c, 1, Exiv2::kerCorruptedMetadata);
+ }
/* Chunk with information about features
used in the file. */
@@ -197,6 +204,7 @@ namespace Exiv2 {
has_vp8x = true;
}
if (equalsWebPTag(chunkId, WEBP_CHUNK_HEADER_VP8X) && !has_size) {
+ enforce(size >= 10, Exiv2::kerCorruptedMetadata);
has_size = true;
byte size_buf[WEBP_TAG_SIZE];
@@ -225,6 +233,7 @@ namespace Exiv2 {
}
#endif
if (equalsWebPTag(chunkId, WEBP_CHUNK_HEADER_VP8) && !has_size) {
+ enforce(size >= 10, Exiv2::kerCorruptedMetadata);
has_size = true;
byte size_buf[2];
@@ -242,11 +251,13 @@ namespace Exiv2 {
/* Chunk with with lossless image data. */
if (equalsWebPTag(chunkId, WEBP_CHUNK_HEADER_VP8L) && !has_alpha) {
+ enforce(size >= 5, Exiv2::kerCorruptedMetadata);
if ((payload.pData_[5] & WEBP_VP8X_ALPHA_BIT) == WEBP_VP8X_ALPHA_BIT) {
has_alpha = true;
}
}
if (equalsWebPTag(chunkId, WEBP_CHUNK_HEADER_VP8L) && !has_size) {
+ enforce(size >= 5, Exiv2::kerCorruptedMetadata);
has_size = true;
byte size_buf_w[2];
byte size_buf_h[3];
@@ -274,11 +285,13 @@ namespace Exiv2 {
/* Chunk with animation frame. */
if (equalsWebPTag(chunkId, WEBP_CHUNK_HEADER_ANMF) && !has_alpha) {
+ enforce(size >= 6, Exiv2::kerCorruptedMetadata);
if ((payload.pData_[5] & 0x2) == 0x2) {
has_alpha = true;
}
}
if (equalsWebPTag(chunkId, WEBP_CHUNK_HEADER_ANMF) && !has_size) {
+ enforce(size >= 12, Exiv2::kerCorruptedMetadata);
has_size = true;
byte size_buf[WEBP_TAG_SIZE];
@@ -307,16 +320,22 @@ namespace Exiv2 {
io_->seek(12, BasicIo::beg);
while ( !io_->eof() && (uint64_t) io_->tell() < filesize) {
- io_->read(chunkId.pData_, 4);
- io_->read(size_buff, 4);
+ readOrThrow(*io_, chunkId.pData_, 4, Exiv2::kerCorruptedMetadata);
+ readOrThrow(*io_, size_buff, 4, Exiv2::kerCorruptedMetadata);
+
+ const uint32_t size_u32 = Exiv2::getULong(size_buff, littleEndian);
- long size = Exiv2::getULong(size_buff, littleEndian);
+ // Check that `size_u32` is safe to cast to `long`.
+ enforce(size_u32 <= static_cast<size_t>(std::numeric_limits<unsigned int>::max()),
+ Exiv2::kerCorruptedMetadata);
+ const long size = static_cast<long>(size_u32);
DataBuf payload(size);
- io_->read(payload.pData_, size);
+ readOrThrow(*io_, payload.pData_, size, Exiv2::kerCorruptedMetadata);
if ( io_->tell() % 2 ) io_->seek(+1,BasicIo::cur); // skip pad
if (equalsWebPTag(chunkId, WEBP_CHUNK_HEADER_VP8X)) {
+ enforce(size >= 1, Exiv2::kerCorruptedMetadata);
if (has_icc){
payload.pData_[0] |= WEBP_VP8X_ICC_BIT;
} else {
--
2.23.0

View File

@ -1,55 +0,0 @@
From f9308839198aca5e68a65194f151a1de92398f54 Mon Sep 17 00:00:00 2001
From: Kevin Backhouse <kevinbackhouse@github.com>
Date: Tue, 20 Apr 2021 12:04:13 +0100
Subject: [PATCH] Better bounds checking in Jp2Image::encodeJp2Header()
---
src/jp2image.cpp | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/src/jp2image.cpp b/src/jp2image.cpp
index 0825d99..f9be021 100644
--- a/src/jp2image.cpp
+++ b/src/jp2image.cpp
@@ -650,6 +650,7 @@ namespace Exiv2
#ifdef DEBUG
std::cout << "Jp2Image::encodeJp2Header subbox: "<< toAscii(subBox.type) << " length = " << subBox.length << std::endl;
#endif
+ enforce(subBox.length <= length - count, Exiv2::kerCorruptedMetadata);
count += subBox.length;
newBox.type = subBox.type;
} else {
@@ -658,12 +659,13 @@ namespace Exiv2
count = length;
}
- int32_t newlen = subBox.length;
+ uint32_t newlen = subBox.length;
if ( newBox.type == kJp2BoxTypeColorHeader ) {
bWroteColor = true ;
if ( ! iccProfileDefined() ) {
const char* pad = "\x01\x00\x00\x00\x00\x00\x10\x00\x00\x05\x1cuuid";
uint32_t psize = 15;
+ enforce(newlen <= output.size_ - outlen, Exiv2::kerCorruptedMetadata);
ul2Data((byte*)&newBox.length,psize ,bigEndian);
ul2Data((byte*)&newBox.type ,newBox.type,bigEndian);
::memcpy(output.pData_+outlen ,&newBox ,sizeof(newBox));
@@ -672,6 +674,7 @@ namespace Exiv2
} else {
const char* pad = "\0x02\x00\x00";
uint32_t psize = 3;
+ enforce(newlen <= output.size_ - outlen, Exiv2::kerCorruptedMetadata);
ul2Data((byte*)&newBox.length,psize+iccProfile_.size_,bigEndian);
ul2Data((byte*)&newBox.type,newBox.type,bigEndian);
::memcpy(output.pData_+outlen ,&newBox ,sizeof(newBox) );
@@ -680,6 +683,7 @@ namespace Exiv2
newlen = psize + iccProfile_.size_;
}
} else {
+ enforce(newlen <= output.size_ - outlen, Exiv2::kerCorruptedMetadata);
::memcpy(output.pData_+outlen,boxBuf.pData_+inlen,subBox.length);
}
--
2.23.0

View File

@ -1,39 +0,0 @@
From 6628a69c036df2aa036290e6cd71767c159c79ed Mon Sep 17 00:00:00 2001
From: Kevin Backhouse <kevinbackhouse@github.com>
Date: Wed, 21 Apr 2021 12:06:04 +0100
Subject: [PATCH] Add more bounds checks in Jp2Image::encodeJp2Header
---
src/jp2image.cpp | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/src/jp2image.cpp b/src/jp2image.cpp
index 917d115..0825d99 100644
--- a/src/jp2image.cpp
+++ b/src/jp2image.cpp
@@ -626,15 +626,18 @@ namespace Exiv2
void Jp2Image::encodeJp2Header(const DataBuf& boxBuf,DataBuf& outBuf)
{
DataBuf output(boxBuf.size_ + iccProfile_.size_ + 100); // allocate sufficient space
- int outlen = sizeof(Jp2BoxHeader) ; // now many bytes have we written to output?
- int inlen = sizeof(Jp2BoxHeader) ; // how many bytes have we read from boxBuf?
+ long outlen = sizeof(Jp2BoxHeader) ; // now many bytes have we written to output?
+ long inlen = sizeof(Jp2BoxHeader) ; // how many bytes have we read from boxBuf?
+ enforce(sizeof(Jp2BoxHeader) <= static_cast<size_t>(output.size_), Exiv2::kerCorruptedMetadata);
Jp2BoxHeader* pBox = (Jp2BoxHeader*) boxBuf.pData_;
- int32_t length = getLong((byte*)&pBox->length, bigEndian);
- int32_t count = sizeof (Jp2BoxHeader);
+ uint32_t length = getLong((byte*)&pBox->length, bigEndian);
+ enforce(length <= static_cast<size_t>(output.size_), Exiv2::kerCorruptedMetadata);
+ uint32_t count = sizeof (Jp2BoxHeader);
char* p = (char*) boxBuf.pData_;
bool bWroteColor = false ;
while ( count < length || !bWroteColor ) {
+ enforce(sizeof(Jp2BoxHeader) <= length - count, Exiv2::kerCorruptedMetadata);
Jp2BoxHeader* pSubBox = (Jp2BoxHeader*) (p+count) ;
// copy data. pointer could be into a memory mapped file which we will decode!
--
2.23.0

View File

@ -1,24 +0,0 @@
From e6a0982f7cd9282052b6e3485a458d60629ffa0b Mon Sep 17 00:00:00 2001
From: Kevin Backhouse <kevinbackhouse@github.com>
Date: Fri, 23 Apr 2021 11:44:44 +0100
Subject: [PATCH] Add bounds check in Jp2Image::doWriteMetadata().
---
src/jp2image.cpp | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/jp2image.cpp b/src/jp2image.cpp
index f9be021..40eca0d 100644
--- a/src/jp2image.cpp
+++ b/src/jp2image.cpp
@@ -888,6 +888,7 @@ namespace Exiv2
case kJp2BoxTypeUuid:
{
+ enforce(boxBuf.size_ >= 24, Exiv2::kerCorruptedMetadata);
if(memcmp(boxBuf.pData_ + 8, kJp2UuidExif, 16) == 0)
{
#ifdef DEBUG
--
2.23.0

View File

@ -1,26 +0,0 @@
From 82e46b5524fb904e6660dadd2c6d8e5e47375a1a Mon Sep 17 00:00:00 2001
From: Kevin Backhouse <kevinbackhouse@github.com>
Date: Tue, 11 May 2021 12:14:33 +0100
Subject: [PATCH] Use readOrThrow to check error conditions of iIo.read().
---
src/webpimage.cpp | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/webpimage.cpp b/src/webpimage.cpp
index 7c64ff3d7..ca26e514a 100644
--- a/src/webpimage.cpp
+++ b/src/webpimage.cpp
@@ -754,9 +754,9 @@ namespace Exiv2 {
byte webp[len];
byte data[len];
byte riff[len];
- iIo.read(riff, len);
- iIo.read(data, len);
- iIo.read(webp, len);
+ readOrThrow(iIo, riff, len, Exiv2::kerCorruptedMetadata);
+ readOrThrow(iIo, data, len, Exiv2::kerCorruptedMetadata);
+ readOrThrow(iIo, webp, len, Exiv2::kerCorruptedMetadata);
bool matched_riff = (memcmp(riff, RiffImageId, len) == 0);
bool matched_webp = (memcmp(webp, WebPImageId, len) == 0);
iIo.seek(-12, BasicIo::cur);

View File

@ -1,126 +0,0 @@
From c261fbaa2567687eec6a595d3016212fd6ae648d Mon Sep 17 00:00:00 2001
From: Kevin Backhouse <kevinbackhouse@github.com>
Date: Sun, 16 May 2021 15:05:08 +0100
Subject: [PATCH] Fix quadratic complexity performance bug.
---
xmpsdk/src/XMPMeta-Parse.cpp | 57 +++++++++++++++++++++++-------------
1 file changed, 36 insertions(+), 21 deletions(-)
diff --git a/xmpsdk/src/XMPMeta-Parse.cpp b/xmpsdk/src/XMPMeta-Parse.cpp
index 9f66fe8e1d..69596934ea 100644
--- a/xmpsdk/src/XMPMeta-Parse.cpp
+++ b/xmpsdk/src/XMPMeta-Parse.cpp
@@ -976,12 +976,26 @@ ProcessUTF8Portion ( XMLParserAdapter * xmlParser,
{
const XMP_Uns8 * bufEnd = buffer + length;
- const XMP_Uns8 * spanStart = buffer;
const XMP_Uns8 * spanEnd;
+
+ // `buffer` is copied into this std::string. If `buffer` only
+ // contains valid UTF-8 and no escape characters, then the copy
+ // will be identical to the original, but invalid characters are
+ // replaced - usually with a space character. This std::string was
+ // added as a performance fix for:
+ // https://github.com/Exiv2/exiv2/security/advisories/GHSA-w8mv-g8qq-36mj
+ // Previously, the code was repeatedly calling
+ // `xmlParser->ParseBuffer()`, which turned out to have quadratic
+ // complexity, because expat kept reparsing the entire string from
+ // the beginning.
+ std::string copy;
- for ( spanEnd = spanStart; spanEnd < bufEnd; ++spanEnd ) {
+ for ( spanEnd = buffer; spanEnd < bufEnd; ++spanEnd ) {
- if ( (0x20 <= *spanEnd) && (*spanEnd <= 0x7E) && (*spanEnd != '&') ) continue; // A regular ASCII character.
+ if ( (0x20 <= *spanEnd) && (*spanEnd <= 0x7E) && (*spanEnd != '&') ) {
+ copy.push_back(*spanEnd);
+ continue; // A regular ASCII character.
+ }
if ( *spanEnd >= 0x80 ) {
@@ -992,21 +1006,20 @@ ProcessUTF8Portion ( XMLParserAdapter * xmlParser,
if ( uniLen > 0 ) {
// A valid UTF-8 character, keep it as-is.
+ copy.append((const char*)spanEnd, uniLen);
spanEnd += uniLen - 1; // ! The loop increment will put back the +1.
} else if ( (uniLen < 0) && (! last) ) {
// Have a partial UTF-8 character at the end of the buffer and more input coming.
- xmlParser->ParseBuffer ( spanStart, (spanEnd - spanStart), false );
+ xmlParser->ParseBuffer ( copy.c_str(), copy.size(), false );
return (spanEnd - buffer);
} else {
// Not a valid UTF-8 sequence. Replace the first byte with the Latin-1 equivalent.
- xmlParser->ParseBuffer ( spanStart, (spanEnd - spanStart), false );
const char * replacement = kReplaceLatin1 [ *spanEnd - 0x80 ];
- xmlParser->ParseBuffer ( replacement, strlen ( replacement ), false );
- spanStart = spanEnd + 1; // ! The loop increment will do "spanEnd = spanStart".
+ copy.append ( replacement );
}
@@ -1014,11 +1027,12 @@ ProcessUTF8Portion ( XMLParserAdapter * xmlParser,
// Replace ASCII controls other than tab, LF, and CR with a space.
- if ( (*spanEnd == kTab) || (*spanEnd == kLF) || (*spanEnd == kCR) ) continue;
+ if ( (*spanEnd == kTab) || (*spanEnd == kLF) || (*spanEnd == kCR) ) {
+ copy.push_back(*spanEnd);
+ continue;
+ }
- xmlParser->ParseBuffer ( spanStart, (spanEnd - spanStart), false );
- xmlParser->ParseBuffer ( " ", 1, false );
- spanStart = spanEnd + 1; // ! The loop increment will do "spanEnd = spanStart".
+ copy.push_back(' ');
} else {
@@ -1030,18 +1044,21 @@ ProcessUTF8Portion ( XMLParserAdapter * xmlParser,
if ( escLen < 0 ) {
// Have a partial numeric escape in this buffer, wait for more input.
- if ( last ) continue; // No more buffers, not an escape, absorb as normal input.
- xmlParser->ParseBuffer ( spanStart, (spanEnd - spanStart), false );
+ if ( last ) {
+ copy.push_back('&');
+ continue; // No more buffers, not an escape, absorb as normal input.
+ }
+ xmlParser->ParseBuffer ( copy.c_str(), copy.size(), false );
return (spanEnd - buffer);
} else if ( escLen > 0 ) {
// Have a complete numeric escape to replace.
- xmlParser->ParseBuffer ( spanStart, (spanEnd - spanStart), false );
- xmlParser->ParseBuffer ( " ", 1, false );
- spanStart = spanEnd + escLen;
- spanEnd = spanStart - 1; // ! The loop continuation will increment spanEnd!
+ copy.push_back(' ');
+ spanEnd = spanEnd + escLen - 1; // ! The loop continuation will increment spanEnd!
+ } else {
+ copy.push_back('&');
}
}
@@ -1049,10 +1066,8 @@ ProcessUTF8Portion ( XMLParserAdapter * xmlParser,
}
XMP_Assert ( spanEnd == bufEnd );
-
- if ( spanStart < bufEnd ) xmlParser->ParseBuffer ( spanStart, (spanEnd - spanStart), false );
- if ( last ) xmlParser->ParseBuffer ( " ", 1, true );
-
+ copy.push_back(' ');
+ xmlParser->ParseBuffer ( copy.c_str(), copy.size(), true );
return length;
} // ProcessUTF8Portion

View File

@ -1,47 +0,0 @@
From 466acf56a13a1afa88cefbb249b535088d077c20 Mon Sep 17 00:00:00 2001
From: Luis Diaz Mas <piponazo@gmail.com>
Date: Tue, 25 Dec 2018 16:54:26 +0100
Subject: [PATCH] Fix ICC profile in PNG images
(cherry picked from commit 9a38066b8eddf3948696a3362aac29e012ebe690)
---
src/pngimage.cpp | 16 +++++++++++++++-
1 file changed, 15 insertions(+), 1 deletion(-)
diff --git a/src/pngimage.cpp b/src/pngimage.cpp
index ed7399a..49c8336 100644
--- a/src/pngimage.cpp
+++ b/src/pngimage.cpp
@@ -468,7 +468,20 @@ namespace Exiv2 {
}
else if (!memcmp(cheaderBuf.pData_ + 4, "iCCP", 4))
{
- zlibToDataBuf(cdataBuf.pData_ +12+1,dataOffset-13,iccProfile_); // +1 = 'compressed' flag
+ // The ICC profile name can vary from 1-79 characters.
+ uint32_t iccOffset = 0;
+ while (iccOffset < 80 && iccOffset < dataOffset) {
+
+ const byte* profileName = cdataBuf.pData_ + iccOffset;
+ ++iccOffset;
+
+ if (*profileName == 0x00)
+ break;
+ }
+
+ ++iccOffset; // +1 = 'compressed' flag
+
+ zlibToDataBuf(cdataBuf.pData_ +iccOffset,dataOffset-iccOffset,iccProfile_);
#ifdef DEBUG
std::cout << "Exiv2::PngImage::readMetadata: Found iCCP chunk length: " << dataOffset << std::endl;
std::cout << "Exiv2::PngImage::readMetadata: iccProfile.size_ : " << iccProfile_.size_ << std::endl;
@@ -627,6 +640,7 @@ namespace Exiv2 {
// calculate CRC
uLong tmp = crc32(0L, Z_NULL, 0);
+ tmp = crc32(tmp, (const Bytef*)type ,typeLen);
tmp = crc32(tmp, (const Bytef*)header ,headerLen);
tmp = crc32(tmp, (const Bytef*)compressed.pData_,compressed.size_);
byte crc[4];
--
1.8.3.1

36
exiv2
View File

@ -1,36 +0,0 @@
From 1fc5ef40b15735e1b02ec752ec535c19831aafa6 Mon Sep 17 00:00:00 2001
From: Kevin Backhouse <kev@semmle.com>
Date: Thu, 25 Apr 2019 21:31:50 +0100
Subject: [PATCH] Avoid negative integer overflow when `iccOffset >
chunkLength`.
This fixes #790.
(cherry picked from commit 6fa2e31206127bd8bcac0269311f3775a8d6ea21)
---
src/pngimage.cpp | 2 ++
1 file changed, 2 insertions(+)
diff --git a/src/pngimage.cpp b/src/pngimage.cpp
index 49c8336..435dd3b 100644
--- a/src/pngimage.cpp
+++ b/src/pngimage.cpp
@@ -40,6 +40,7 @@ EXIV2_RCSID("@(#) $Id$")
#include "image_int.hpp"
#include "basicio.hpp"
#include "error.hpp"
+#include "enforce.hpp"
#include "futils.hpp"
#include "types.hpp"
@@ -480,6 +481,7 @@ namespace Exiv2 {
}
++iccOffset; // +1 = 'compressed' flag
+ enforce(iccOffset <= dataOffset, Exiv2::kerCorruptedMetadata);
zlibToDataBuf(cdataBuf.pData_ +iccOffset,dataOffset-iccOffset,iccProfile_);
#ifdef DEBUG
--
1.8.3.1

View File

@ -1,41 +0,0 @@
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

@ -1,36 +0,0 @@
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

@ -1,53 +0,0 @@
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

@ -1,61 +0,0 @@
From d3c2b9938583440f87ce9115de5a7e8cd8f8db57 Mon Sep 17 00:00:00 2001
From: clanmills <robin@clanmills.com>
Date: Sun, 11 Jun 2017 11:56:20 +0100
Subject: [PATCH] #1297 Fix submitted.
---
src/error.cpp | 2 ++
src/image.cpp | 11 ++++++-----
2 files changed, 8 insertions(+), 5 deletions(-)
diff --git a/src/image.cpp b/src/image.cpp
index 0d8280455..0db66eb04 100644
--- a/src/image.cpp
+++ b/src/image.cpp
@@ -332,7 +332,7 @@ namespace Exiv2 {
static bool typeValid(uint16_t type)
{
- return type >= 1 && type <= 13 ;
+ return type >= 1 && type <= 13 ;
}
void Image::printIFDStructure(BasicIo& io, std::ostream& out, Exiv2::PrintStructureOption option,uint32_t start,bool bSwap,char c,int depth)
@@ -352,12 +352,12 @@ namespace Exiv2 {
uint16_t dirLength = byteSwap2(dir,0,bSwap);
bool tooBig = dirLength > 500;
+ if ( tooBig ) throw Error(55);
if ( bFirst && bPrint ) {
out << Internal::indent(depth) << Internal::stringFormat("STRUCTURE OF TIFF FILE (%c%c): ",c,c) << io.path() << std::endl;
if ( tooBig ) out << Internal::indent(depth) << "dirLength = " << dirLength << std::endl;
}
- if (tooBig) break;
// Read the dictionary
for ( int i = 0 ; i < dirLength ; i ++ ) {
@@ -374,10 +374,11 @@ namespace Exiv2 {
uint32_t count = byteSwap4(dir,4,bSwap);
uint32_t offset = byteSwap4(dir,8,bSwap);
- // Break for unknown tag types else we may get segfault.
+ // Break for unknown tag types else we may segfault.
if ( !typeValid(type) ) {
std::cerr << "invalid type value detected in Image::printIFDStructure: " << type << std::endl;
start = 0; // break from do loop
+ throw Error(56);
break; // break from for loop
}
@@ -411,8 +412,8 @@ namespace Exiv2 {
if ( bPrint ) {
uint32_t address = start + 2 + i*12 ;
out << Internal::indent(depth)
- << Internal::stringFormat("%8u | %#06x %-25s |%10s |%9u |%10u | "
- ,address,tag,tagName(tag,25),typeName(type),count,offset);
+ << Internal::stringFormat("%8u | %#06x %-25s |%10s |%9u |%10u | "
+ ,address,tag,tagName(tag,25),typeName(type),count,offset);
if ( isShortType(type) ){
for ( size_t k = 0 ; k < kount ; k++ ) {
out << sp << byteSwap2(buf,k*size,bSwap);

View File

@ -1,37 +0,0 @@
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,107 +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 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"

View File

@ -1,351 +0,0 @@
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_

View File

@ -1,25 +0,0 @@
From 1c76ecbd66263b2ed14c82e41917ab3d7e8b0ef9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Luis=20D=C3=ADaz=20M=C3=A1s?= <piponazo@gmail.com>
Date: Tue, 19 Dec 2017 19:52:41 +0100
Subject: [PATCH] Only print items (Params::prValue) when size > 0
---
src/actions.cpp | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/src/actions.cpp b/src/actions.cpp
index e5baa75fc..3125cf54f 100644
--- a/src/actions.cpp
+++ b/src/actions.cpp
@@ -704,8 +704,9 @@ namespace Action {
<< std::setfill(' ') << std::right
<< md.size();
}
- if (Params::instance().printItems_ & Params::prValue) {
- if (!first) std::cout << " ";
+ if (Params::instance().printItems_ & Params::prValue && md.size() > 0) {
+ if (!first)
+ std::cout << " ";
first = false;
if ( Params::instance().binary_
&& ( md.typeId() == Exiv2::undefined

View File

@ -1,27 +0,0 @@
From 85e8a48bc2da364869ffd1aaeabc09edcfa03067 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Luis=20D=C3=ADaz=20M=C3=A1s?= <piponazo@gmail.com>
Date: Tue, 19 Dec 2017 19:54:17 +0100
Subject: [PATCH] Move condition in if statement to discard work earlier
---
src/actions.cpp | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/src/actions.cpp b/src/actions.cpp
index 3125cf54f..fea22d373 100644
--- a/src/actions.cpp
+++ b/src/actions.cpp
@@ -708,10 +708,9 @@ namespace Action {
if (!first) std::cout << " ";
first = false;
- if ( Params::instance().binary_
- && ( md.typeId() == Exiv2::undefined
+ if (md.size() > 128 && Params::instance().binary_ && (
+ md.typeId() == Exiv2::undefined
|| md.typeId() == Exiv2::unsignedByte
- || md.typeId() == Exiv2::signedByte)
- && md.size() > 128) {
+ || md.typeId() == Exiv2::signedByte)) {
std::cout << _("(Binary value suppressed)") << std::endl;
return true;
}

View File

@ -1,344 +0,0 @@
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

@ -1,61 +0,0 @@
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

@ -1,31 +0,0 @@
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

@ -1,60 +0,0 @@
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

@ -1,49 +0,0 @@
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,76 +0,0 @@
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_,

View File

@ -1,466 +0,0 @@
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()
{

View File

@ -1,21 +0,0 @@
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

@ -1,197 +0,0 @@
From c73d1e27198a389ce7caf52ac30f8e2120acdafd Mon Sep 17 00:00:00 2001
From: Kevin Backhouse <kev@semmle.com>
Date: Fri, 26 Apr 2019 10:21:46 +0100
Subject: [PATCH 1/1] Avoid negative integer overflow when `filesize <
io_->tell()`.
This fixes #791.
---
include/exiv2/basicio.hpp | 21 +++++++++++++++++++++
include/exiv2/webpimage.hpp | 2 +-
src/basicio.cpp | 14 ++++++++++++++
src/webpimage.cpp | 26 +++++++++++++++-----------
diff -Naur a/include/exiv2/basicio.hpp b/include/exiv2/basicio.hpp
--- a/include/exiv2/basicio.hpp 2020-05-21 17:33:11.452872734 +0800
+++ b/include/exiv2/basicio.hpp 2020-05-21 18:25:25.577619496 +0800
@@ -28,6 +28,7 @@
// *****************************************************************************
// included header files
#include "types.hpp"
+#include "error.hpp"
#include "futils.hpp"
// + standard includes
@@ -155,6 +156,26 @@
*/
virtual long read(byte* buf, long rcount) = 0;
/*!
+ @brief Read data from the IO source. Reading starts at the current
+ IO position and the position is advanced by the number of bytes
+ read. Throw an exception if not enough bytes are available.
+ @param rcount Number of bytes to read.
+ @param err ErrorCode to throw if not enough bytes are available.
+ @return DataBuf instance containing the bytes read.
+ */
+ DataBuf readOrThrow(long rcount, ErrorCode err);
+ /*!
+ @brief Read data from the IO source. Reading starts at the current
+ IO position and the position is advanced by the number of bytes
+ read. Throw an exception if not enough bytes are available.
+ @param buf Pointer to a block of memory into which the read data
+ is stored. The memory block must be at least \em rcount bytes
+ long.
+ @param err ErrorCode to throw if not enough bytes are available.
+ @param rcount Number of bytes to read.
+ */
+ void readOrThrow(byte* buf, long rcount, ErrorCode err);
+ /*!
@brief Read one byte from the IO source. Current IO position is
advanced by one byte.
@return The byte read from the IO source if successful;<BR>
diff -Naur a/include/exiv2/webpimage.hpp b/include/exiv2/webpimage.hpp
--- a/include/exiv2/webpimage.hpp 2020-05-21 17:33:11.452872734 +0800
+++ b/include/exiv2/webpimage.hpp 2020-05-21 18:27:02.307763543 +0800
@@ -95,7 +95,7 @@
byte *header, long header_size);
bool equalsWebPTag(Exiv2::DataBuf& buf ,const char* str);
void debugPrintHex(byte *data, long size);
- void decodeChunks(uint64_t filesize);
+ void decodeChunks(uint32_t filesize);
void inject_VP8X(BasicIo& iIo, bool has_xmp, bool has_exif,
bool has_alpha, bool has_icc, int width,
int height);
diff -Naur a/src/basicio.cpp b/src/basicio.cpp
--- a/src/basicio.cpp 2020-05-21 17:33:11.472872765 +0800
+++ b/src/basicio.cpp 2020-05-21 18:29:18.497966466 +0800
@@ -33,6 +33,7 @@
#include "futils.hpp"
#include "types.hpp"
#include "error.hpp"
+#include "enforce.hpp"
#include "http.hpp"
#include "properties.hpp"
@@ -83,6 +84,18 @@
BasicIo::~BasicIo()
{
}
+ DataBuf BasicIo::readOrThrow(long rcount, ErrorCode err) {
+ DataBuf result = read(rcount);
+ enforce(result.size_ == rcount, err);
+ enforce(!error(), err);
+ return result;
+ }
+
+ void BasicIo::readOrThrow(byte* buf, long rcount, ErrorCode err) {
+ const long nread = read(buf, rcount);
+ enforce(nread == rcount, err);
+ enforce(!error(), err);
+ }
//! Internal Pimpl structure of class FileIo.
class FileIo::Impl {
diff -Naur a/src/webpimage.cpp b/src/webpimage.cpp
--- a/src/webpimage.cpp 2020-05-21 17:33:11.472872765 +0800
+++ b/src/webpimage.cpp 2020-05-21 19:05:02.951135410 +0800
@@ -493,7 +493,7 @@
DataBuf chunkId(5);
chunkId.pData_[4] = '\0' ;
- io_->read(data, WEBP_TAG_SIZE * 3);
+ io_->readOrThrow(data, WEBP_TAG_SIZE * 3, Exiv2::kerCorruptedMetadata);
const uint32_t filesize = Exiv2::getULong(data + WEBP_TAG_SIZE, littleEndian) + 8;
enforce(filesize <= io_->size(), Exiv2::kerCorruptedMetadata);
@@ -501,7 +501,7 @@
} // WebPImage::readMetadata
- void WebPImage::decodeChunks(uint64_t filesize)
+ void WebPImage::decodeChunks(uint32_t filesize)
{
DataBuf chunkId(5);
byte size_buff[WEBP_TAG_SIZE];
@@ -513,9 +513,10 @@
chunkId.pData_[4] = '\0' ;
while ( !io_->eof() && (uint64_t) io_->tell() < filesize) {
- io_->read(chunkId.pData_, WEBP_TAG_SIZE);
- io_->read(size_buff, WEBP_TAG_SIZE);
+ io_->readOrThrow(chunkId.pData_, WEBP_TAG_SIZE, Exiv2::kerCorruptedMetadata);
+ io_->readOrThrow(size_buff, WEBP_TAG_SIZE, Exiv2::kerCorruptedMetadata);
const uint32_t size = Exiv2::getULong(size_buff, littleEndian);
+ enforce(io_->tell() <= filesize, Exiv2::kerCorruptedMetadata);
enforce(size <= (filesize - io_->tell()), Exiv2::kerCorruptedMetadata);
DataBuf payload(size);
@@ -526,7 +527,7 @@
has_canvas_data = true;
byte size_buf[WEBP_TAG_SIZE];
- io_->read(payload.pData_, payload.size_);
+ io_->readOrThrow(payload.pData_, payload.size_, Exiv2::kerCorruptedMetadata);
// Fetch width
memcpy(&size_buf, &payload.pData_[4], 3);
@@ -541,7 +542,7 @@
enforce(size >= 10, Exiv2::kerCorruptedMetadata);
has_canvas_data = true;
- io_->read(payload.pData_, payload.size_);
+ io_->readOrThrow(payload.pData_, payload.size_, Exiv2::kerCorruptedMetadata);
byte size_buf[WEBP_TAG_SIZE];
// Fetch width""
@@ -562,7 +563,7 @@
byte size_buf_w[2];
byte size_buf_h[3];
- io_->read(payload.pData_, payload.size_);
+ io_->readOrThrow(payload.pData_, payload.size_, Exiv2::kerCorruptedMetadata);
// Fetch width
memcpy(&size_buf_w, &payload.pData_[1], 2);
@@ -580,7 +581,7 @@
has_canvas_data = true;
byte size_buf[WEBP_TAG_SIZE];
- io_->read(payload.pData_, payload.size_);
+ io_->readOrThrow(payload.pData_, payload.size_, Exiv2::kerCorruptedMetadata);
// Fetch width
memcpy(&size_buf, &payload.pData_[6], 3);
@@ -592,10 +593,10 @@
size_buf[3] = 0;
pixelHeight_ = Exiv2::getULong(size_buf, littleEndian) + 1;
} else if (equalsWebPTag(chunkId, WEBP_CHUNK_HEADER_ICCP)) {
- io_->read(payload.pData_, payload.size_);
+ io_->readOrThrow(payload.pData_, payload.size_, Exiv2::kerCorruptedMetadata);
this->setIccProfile(payload);
} else if (equalsWebPTag(chunkId, WEBP_CHUNK_HEADER_EXIF)) {
- io_->read(payload.pData_, payload.size_);
+ io_->readOrThrow(payload.pData_, payload.size_, Exiv2::kerCorruptedMetadata);
byte size_buff[2];
byte exifLongHeader[] = { 0xFF, 0x01, 0xFF, 0xE1 };
@@ -676,7 +677,7 @@
if (rawExifData) free(rawExifData);
} else if (equalsWebPTag(chunkId, WEBP_CHUNK_HEADER_XMP)) {
- io_->read(payload.pData_, payload.size_);
+ io_->readOrThrow(payload.pData_, payload.size_, Exiv2::kerCorruptedMetadata);
xmpPacket_.assign(reinterpret_cast<char*>(payload.pData_), payload.size_);
if (xmpPacket_.size() > 0 && XmpParser::decode(xmpData_, xmpPacket_)) {
#ifndef SUPPRESS_WARNINGS
@@ -708,7 +709,10 @@
}
bool isWebPType(BasicIo& iIo, bool /*advance*/)
- {
+ {
+ if (iIo.size() < 12) {
+ return false;
+ }
const int32_t len = 4;
const unsigned char RiffImageId[4] = { 'R', 'I', 'F' ,'F'};
const unsigned char WebPImageId[4] = { 'W', 'E', 'B' ,'P'};

View File

@ -1,176 +0,0 @@
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

@ -1,21 +0,0 @@
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

@ -1,84 +0,0 @@
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

@ -1,43 +0,0 @@
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

@ -1,39 +0,0 @@
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

@ -1,79 +1,15 @@
Name: exiv2
Version: 0.26
Release: 27
Version: 0.27.5
Release: 1
Summary: Exif, IPTC and XMP metadata and the ICC Profile
License: GPLv2+
URL: http://www.exiv2.org/
Source0: https://github.com/Exiv2/exiv2/archive/v%{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
Patch6011: exiv2-CVE-2017-14865.patch
Patch6012: exiv2-CVE-2017-18005_1.patch
Patch6013: exiv2-CVE-2017-18005_2.patch
Patch6014: 0001-CVE-2018-19535.patch
Patch6015: 0002-CVE-2018-19535.patch
Patch6016: 0003-CVE-2018-19535.patch
Patch6017: 0001-CVE-2019-13112.patch
Patch6018: 0002-CVE-2019-13112.patch
Patch6019: CVE-2018-16336.patch
Patch6020: CVE-2018-17581.patch
Patch6021: CVE-2019-13110-Avoid-integer-overflow.patch
Patch6022: CVE-2018-4868.patch
Patch6023: backport-CVE-2018-10772.patch
Patch6024: CVE-2018-11037.patch
Patch6025: backport-Fix-ICC-profile-in-PNG-images.patch
Patch6026: backport-CVE-2019-13109.patch
Patch6027: exiv2-CVE-2019-13111.patch
Patch6028: CVE-2018-9145.patch
Patch6029: CVE-2021-3482.patch
Patch6030: backport-CVE-2021-29457.patch
Patch6031: backport-CVE-2021-29458.patch
Patch6032: backport-CVE-2021-29470.patch
Patch6033: backport-0001-CVE-2021-29463.patch
Patch6034: backport-0002-CVE-2021-29463.patch
Patch6035: backport-CVE-2021-29464.patch
Patch6036: backport-CVE-2021-29463.patch
Patch6037: backport-CVE-2021-29473.patch
Patch6038: backport-CVE-2021-29623.patch
Patch6039: backport-CVE-2021-32617.patch
Source0: https://github.com/Exiv2/exiv2/archive/refs/tags/v%{version}.tar.gz
Provides: exiv2-libs
Obsoletes: exiv2-libs
BuildRequires: cmake expat-devel gcc-c++ gettext pkgconfig pkgconfig(libcurl) pkgconfig(libssh)
BuildRequires: cmake expat-devel gcc-c++ gettext pkgconfig
BuildRequires: doxygen graphviz libxslt zlib-devel
%description
@ -95,20 +31,23 @@ This package provides head file,libraries for exiv2.
%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
%{cmake} \
-DCMAKE_INSTALL_DOCDIR="%{_pkgdocdir}" \
-DEXIV2_BUILD_DOC:BOOL=ON \
-DEXIV2_ENABLE_NLS:BOOL=ON \
-DEXIV2_BUILD_SAMPLES:BOOL=OFF
%make_build
make doc
%install
%make_install
%find_lang exiv2
%find_lang exiv2 --with-man
%check
export PKG_CONFIG_PATH=%{buildroot}%{_libdir}/pkgconfig
export PKG_CONFIG_PATH="%{buildroot}%{_libdir}/pkgconfig${PKG_CONFIG_PATH:+:}${PKG_CONFIG_PATH}"
test "$(pkg-config --modversion exiv2)" = "%{version}"
test "$(pkg-config --variable=libdir exiv2)" = "%{_libdir}"
test -x %{buildroot}%{_libdir}/libexiv2.so
%files -f exiv2.lang
@ -116,7 +55,8 @@ test -x %{buildroot}%{_libdir}/libexiv2.so
%doc doc/ChangeLog
%license COPYING
%{_bindir}/exiv2
%{_libdir}/libexiv2.so.26*
%{_libdir}/libexiv2.so.27*
%{_libdir}/libexiv2.so.%{version}
%exclude %{_libdir}/pkgconfig/exiv2.lsm
%exclude %{_libdir}/libxmp.a
@ -125,13 +65,18 @@ test -x %{buildroot}%{_libdir}/libexiv2.so
%{_libdir}/pkgconfig/exiv2.pc
%{_libdir}/libexiv2.so
%{_includedir}/exiv2/
%{_libdir}/cmake/exiv2/
%{_libdir}/libexiv2-xmp.a
%files help
%defattr(-,root,root)
%{_mandir}/man1/exiv2*.1*
%{_datadir}/doc/html/
%{_pkgdocdir}/
%changelog
* Tue Nov 23 2021 wangkai <wangkai385@huawei.com> - 0.27.5-1
- Upgrade to 0.27.5
* Thu May 27 2021 liuyumeng <liuyumeng5@huawei.com> - 0.26-27
- Type:cves
- ID:CVE-2021-29623 CVE-2021-32617

Binary file not shown.