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

