File CVE-2019-13111.patch of Package exiv2-0_26.26888

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.
---
 include/exiv2/webpimage.hpp             |   2 +-
 src/webpimage.cpp                       |  35 ++++++++++++++++--------
 test/data/issue_791_poc1.webp           | Bin 0 -> 28 bytes
 tests/bugfixes/github/test_issue_791.py |  27 ++++++++++++++++++
 4 files changed, 52 insertions(+), 12 deletions(-)
 create mode 100644 test/data/issue_791_poc1.webp
 create mode 100644 tests/bugfixes/github/test_issue_791.py

Index: exiv2-0.26/include/exiv2/webpimage.hpp
===================================================================
--- exiv2-0.26.orig/include/exiv2/webpimage.hpp
+++ exiv2-0.26/include/exiv2/webpimage.hpp
@@ -95,7 +95,7 @@ namespace Exiv2 {
                              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);
Index: exiv2-0.26/src/webpimage.cpp
===================================================================
--- exiv2-0.26.orig/src/webpimage.cpp
+++ exiv2-0.26/src/webpimage.cpp
@@ -66,6 +66,14 @@ 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)
     {
@@ -477,6 +485,7 @@ namespace Exiv2 {
 
     /* =========================================== */
 
+
     void WebPImage::readMetadata()
     {
         if (io_->open() != 0) throw Error(9, io_->path(), strError());
@@ -492,7 +501,7 @@ namespace Exiv2 {
         DataBuf chunkId(5);
         chunkId.pData_[4] = '\0' ;
 
-        io_->read(data, WEBP_TAG_SIZE * 3);
+        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);
@@ -500,7 +509,7 @@ namespace Exiv2 {
 
     } // WebPImage::readMetadata
 
-    void WebPImage::decodeChunks(uint64_t filesize)
+    void WebPImage::decodeChunks(uint32_t filesize)
     {
         DataBuf   chunkId(5);
         byte      size_buff[WEBP_TAG_SIZE];
@@ -512,9 +521,10 @@ namespace Exiv2 {
 
         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);
+            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);
 
             DataBuf payload(size);
@@ -523,7 +533,7 @@ namespace Exiv2 {
                 has_canvas_data = true;
                 byte size_buf[WEBP_TAG_SIZE];
 
-                io_->read(payload.pData_, payload.size_);
+                readOrThrow(*io_, payload.pData_, payload.size_, Exiv2::kerCorruptedMetadata);
 
                 // Fetch width
                 memcpy(&size_buf, &payload.pData_[4], 3);
@@ -536,7 +546,7 @@ namespace Exiv2 {
                 pixelHeight_ = Exiv2::getULong(size_buf, littleEndian) + 1;
             } else if (equalsWebPTag(chunkId, WEBP_CHUNK_HEADER_VP8) && !has_canvas_data) {
                 has_canvas_data = true;
-                io_->read(payload.pData_, payload.size_);
+                readOrThrow(*io_, payload.pData_, payload.size_, Exiv2::kerCorruptedMetadata);
                 byte size_buf[WEBP_TAG_SIZE];
 
                 // Fetch width""
@@ -555,7 +565,7 @@ namespace Exiv2 {
                 byte size_buf_w[2];
                 byte size_buf_h[3];
 
-                io_->read(payload.pData_, payload.size_);
+                readOrThrow(*io_, payload.pData_, payload.size_, Exiv2::kerCorruptedMetadata);
 
                 // Fetch width
                 memcpy(&size_buf_w, &payload.pData_[1], 2);
@@ -571,7 +581,7 @@ namespace Exiv2 {
                 has_canvas_data = true;
                 byte size_buf[WEBP_TAG_SIZE];
 
-                io_->read(payload.pData_, payload.size_);
+                readOrThrow(*io_, payload.pData_, payload.size_, Exiv2::kerCorruptedMetadata);
 
                 // Fetch width
                 memcpy(&size_buf, &payload.pData_[6], 3);
@@ -583,10 +593,10 @@ namespace Exiv2 {
                 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_);
+                readOrThrow(*io_, payload.pData_, payload.size_, Exiv2::kerCorruptedMetadata);
                 this->setIccProfile(payload);
             } else if (equalsWebPTag(chunkId, WEBP_CHUNK_HEADER_EXIF)) {
-                io_->read(payload.pData_, payload.size_);
+                readOrThrow(*io_, payload.pData_, payload.size_, Exiv2::kerCorruptedMetadata);
 
                 byte  size_buff[2];
                 byte  exifLongHeader[]   = { 0xFF, 0x01, 0xFF, 0xE1 };
@@ -667,7 +677,7 @@ namespace Exiv2 {
 
                 if (rawExifData) free(rawExifData);
             } else if (equalsWebPTag(chunkId, WEBP_CHUNK_HEADER_XMP)) {
-                io_->read(payload.pData_, payload.size_);
+                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
@@ -700,6 +710,9 @@ namespace Exiv2 {
 
     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'};
Index: exiv2-0.26/tests/bugfixes/github/test_issue_791.py
===================================================================
--- /dev/null
+++ exiv2-0.26/tests/bugfixes/github/test_issue_791.py
@@ -0,0 +1,27 @@
+import system_tests
+
+
+class IntegerOverflowInWebpImageReadMetadata(
+        metaclass=system_tests.CaseMeta):
+    """
+    Regression test for the bug described in:
+    https://github.com/Exiv2/exiv2/issues/791
+
+    Due to an integer overflow bug (#791), this test triggers a 4GB
+    memory allocation. So the test will fail with a std::bad_alloc
+    exception if less than 4GB is available.  On Linux, you can use
+    `ulimit -v 4000000` to reduce the available memory to slightly
+    less than 4GB.
+    """
+    url = "https://github.com/Exiv2/exiv2/issues/791"
+
+    filename = system_tests.path(
+        "$data_path/issue_791_poc1.webp"
+    )
+    commands = ["$exiv2 $filename"]
+    stdout = [""]
+    stderr = ["""Exiv2 exception in print action for file $filename:
+corrupted image metadata
+"""
+]
+    retval = [1]
openSUSE Build Service is sponsored by