!47 Upgrade to 0.27.5
From: @wk333 Reviewed-by: @small_leek Signed-off-by: @small_leek
This commit is contained in:
commit
869435fa98
@ -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
|
||||
|
||||
@ -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)
|
||||
@ -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')
|
||||
{
|
||||
@ -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)
|
||||
@ -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++)
|
||||
@ -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
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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";
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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()
|
||||
{
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
@ -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
|
||||
@ -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)
|
||||
@ -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;
|
||||
}
|
||||
@ -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]
|
||||
@ -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
|
||||
@ -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]
|
||||
@ -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)) {
|
||||
@ -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
|
||||
@ -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 ) {
|
||||
@ -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) {
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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());
|
||||
}
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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);
|
||||
@ -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
|
||||
@ -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
36
exiv2
@ -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
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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
|
||||
@ -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 "
|
||||
@ -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);
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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"
|
||||
@ -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_
|
||||
@ -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
|
||||
@ -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;
|
||||
}
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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_);
|
||||
}
|
||||
@ -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;
|
||||
@ -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];
|
||||
|
||||
@ -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_,
|
||||
@ -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()
|
||||
{
|
||||
@ -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" ;
|
||||
}
|
||||
@ -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'};
|
||||
@ -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 {
|
||||
@ -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.
|
||||
@ -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()
|
||||
+
|
||||
@ -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 )
|
||||
@ -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);
|
||||
}
|
||||
95
exiv2.spec
95
exiv2.spec
@ -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.
Loading…
x
Reference in New Issue
Block a user