b326000
From d4e4288d839d0d9546a05986771f8738c382060c Mon Sep 17 00:00:00 2001
b326000
From: =?UTF-8?q?Dan=20=C4=8Cerm=C3=A1k?= <dan.cermak@cgc-instruments.com>
b326000
Date: Sat, 7 Oct 2017 23:08:36 +0200
b326000
Subject: Fix for CVE-2017-14864, CVE-2017-14862 and CVE-2017-14859
b326000
b326000
The invalid memory dereference in
b326000
Exiv2::getULong()/Exiv2::StringValueBase::read()/Exiv2::DataValue::read()
b326000
is caused further up the call-stack, by
b326000
v->read(pData, size, byteOrder) in TiffReader::readTiffEntry()
b326000
passing an invalid pData pointer (pData points outside of the Tiff
b326000
file). pData can be set out of bounds in the (size > 4) branch where
b326000
baseOffset() and offset are added to pData_ without checking whether
b326000
the result is still in the file. As offset comes from an untrusted
b326000
source, an attacker can craft an arbitrarily large offset into the
b326000
file.
b326000
b326000
This commit adds a check into the problematic branch, whether the
b326000
result of the addition would be out of bounds of the Tiff
b326000
file. Furthermore the whole operation is checked for possible
b326000
overflows.
b326000
b326000
diff --git a/src/tiffvisitor.cpp b/src/tiffvisitor.cpp
b326000
index 4ab733d4..ef13542e 100644
b326000
--- a/src/tiffvisitor.cpp
b326000
+++ b/src/tiffvisitor.cpp
b326000
@@ -47,6 +47,7 @@ EXIV2_RCSID("@(#) $Id$")
b326000
 #include <iostream>
b326000
 #include <iomanip>
b326000
 #include <cassert>
b326000
+#include <limits>
b326000
 
b326000
 // *****************************************************************************
b326000
 namespace {
b326000
@@ -1517,7 +1518,19 @@ namespace Exiv2 {
b326000
                 size = 0;
b326000
         }
b326000
         if (size > 4) {
b326000
+            // setting pData to pData_ + baseOffset() + offset can result in pData pointing to invalid memory,
b326000
+            // as offset can be arbitrarily large
b326000
+            if ((static_cast<uintptr_t>(baseOffset()) > std::numeric_limits<uintptr_t>::max() - static_cast<uintptr_t>(offset))
b326000
+             || (static_cast<uintptr_t>(baseOffset() + offset) > std::numeric_limits<uintptr_t>::max() - reinterpret_cast<uintptr_t>(pData_)))
b326000
+            {
b326000
+                throw Error(59);
b326000
+            }
b326000
+            if (pData_ + static_cast<uintptr_t>(baseOffset()) + static_cast<uintptr_t>(offset) > pLast_) {
b326000
+                throw Error(58);
b326000
+            }
b326000
             pData = const_cast<byte*>(pData_) + baseOffset() + offset;
b326000
+
b326000
+	    // check for size being invalid
b326000
             if (size > static_cast<uint32_t>(pLast_ - pData)) {
b326000
 #ifndef SUPPRESS_WARNINGS
b326000
                 EXV_ERROR << "Upper boundary of data for "