|
|
3f58c5 |
From 7c6f59619616a01e242401cf4c8e06428539a035 Mon Sep 17 00:00:00 2001
|
|
|
3f58c5 |
From: Luis Diaz Mas <piponazo@gmail.com>
|
|
|
3f58c5 |
Date: Sat, 16 Dec 2017 16:05:08 +0100
|
|
|
3f58c5 |
Subject: Fix arithmetic operation overflow
|
|
|
3f58c5 |
|
|
|
3f58c5 |
|
|
|
3f58c5 |
diff --git a/src/jp2image.cpp b/src/jp2image.cpp
|
|
|
3f58c5 |
index 09d023e2..a308bfd9 100644
|
|
|
3f58c5 |
--- a/src/jp2image.cpp
|
|
|
3f58c5 |
+++ b/src/jp2image.cpp
|
|
|
3f58c5 |
@@ -41,6 +41,7 @@ EXIV2_RCSID("@(#) $Id$")
|
|
|
3f58c5 |
#include "error.hpp"
|
|
|
3f58c5 |
#include "futils.hpp"
|
|
|
3f58c5 |
#include "types.hpp"
|
|
|
3f58c5 |
+#include "safe_op.hpp"
|
|
|
3f58c5 |
|
|
|
3f58c5 |
// + standard includes
|
|
|
3f58c5 |
#include <string>
|
|
|
3f58c5 |
@@ -269,15 +270,16 @@ namespace Exiv2
|
|
|
3f58c5 |
std::cout << "Exiv2::Jp2Image::readMetadata: "
|
|
|
3f58c5 |
<< "Color data found" << std::endl;
|
|
|
3f58c5 |
#endif
|
|
|
3f58c5 |
+
|
|
|
3f58c5 |
const long pad = 3 ; // 3 padding bytes 2 0 0
|
|
|
3f58c5 |
- DataBuf data(subBox.length+8);
|
|
|
3f58c5 |
+ DataBuf data(Safe::add(subBox.length, static_cast<uint32_t>(8)));
|
|
|
3f58c5 |
io_->read(data.pData_,data.size_);
|
|
|
3f58c5 |
const long iccLength = getULong(data.pData_+pad, bigEndian);
|
|
|
3f58c5 |
// subtracting pad from data.size_ is safe:
|
|
|
3f58c5 |
// size_ is at least 8 and pad = 3
|
|
|
3f58c5 |
if (iccLength > data.size_ - pad) {
|
|
|
3f58c5 |
throw Error(58);
|
|
|
3f58c5 |
- }
|
|
|
3f58c5 |
+ }
|
|
|
3f58c5 |
DataBuf icc(iccLength);
|
|
|
3f58c5 |
::memcpy(icc.pData_,data.pData_+pad,icc.size_);
|
|
|
3f58c5 |
#ifdef DEBUG
|
|
|
3f58c5 |
diff --git a/src/safe_op.hpp b/src/safe_op.hpp
|
|
|
3f58c5 |
new file mode 100644
|
|
|
3f58c5 |
index 00000000..55d690e3
|
|
|
3f58c5 |
--- /dev/null
|
|
|
3f58c5 |
+++ b/src/safe_op.hpp
|
|
|
3f58c5 |
@@ -0,0 +1,308 @@
|
|
|
3f58c5 |
+// ********************************************************* -*- C++ -*-
|
|
|
3f58c5 |
+/*
|
|
|
3f58c5 |
+ * Copyright (C) 2004-2017 Exiv2 maintainers
|
|
|
3f58c5 |
+ *
|
|
|
3f58c5 |
+ * This program is part of the Exiv2 distribution.
|
|
|
3f58c5 |
+ *
|
|
|
3f58c5 |
+ * This program is free software; you can redistribute it and/or
|
|
|
3f58c5 |
+ * modify it under the terms of the GNU General Public License
|
|
|
3f58c5 |
+ * as published by the Free Software Foundation; either version 2
|
|
|
3f58c5 |
+ * of the License, or (at your option) any later version.
|
|
|
3f58c5 |
+ *
|
|
|
3f58c5 |
+ * This program is distributed in the hope that it will be useful,
|
|
|
3f58c5 |
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
3f58c5 |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
3f58c5 |
+ * GNU General Public License for more details.
|
|
|
3f58c5 |
+ *
|
|
|
3f58c5 |
+ * You should have received a copy of the GNU General Public License
|
|
|
3f58c5 |
+ * along with this program; if not, write to the Free Software
|
|
|
3f58c5 |
+ * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA.
|
|
|
3f58c5 |
+ */
|
|
|
3f58c5 |
+/*!
|
|
|
3f58c5 |
+ @file safe_op.hpp
|
|
|
3f58c5 |
+ @brief Overflow checks for integers
|
|
|
3f58c5 |
+ @author Dan Čermák (D4N)
|
|
|
3f58c5 |
+ dan.cermak@cgc-instruments.com
|
|
|
3f58c5 |
+ @date 14-Dec-17, D4N: created
|
|
|
3f58c5 |
+ */
|
|
|
3f58c5 |
+
|
|
|
3f58c5 |
+#ifndef SAFE_OP_HPP_
|
|
|
3f58c5 |
+#define SAFE_OP_HPP_
|
|
|
3f58c5 |
+
|
|
|
3f58c5 |
+#include <limits>
|
|
|
3f58c5 |
+#include <stdexcept>
|
|
|
3f58c5 |
+
|
|
|
3f58c5 |
+#ifdef _MSC_VER
|
|
|
3f58c5 |
+#include <Intsafe.h>
|
|
|
3f58c5 |
+#endif
|
|
|
3f58c5 |
+
|
|
|
3f58c5 |
+/*!
|
|
|
3f58c5 |
+ * @brief Arithmetic operations with overflow checks
|
|
|
3f58c5 |
+ */
|
|
|
3f58c5 |
+namespace Safe
|
|
|
3f58c5 |
+{
|
|
|
3f58c5 |
+ /*!
|
|
|
3f58c5 |
+ * @brief Helper structs for providing integer overflow checks.
|
|
|
3f58c5 |
+ *
|
|
|
3f58c5 |
+ * This namespace contains the internal helper structs fallback_add_overflow
|
|
|
3f58c5 |
+ * and builtin_add_overflow. Both have a public static member function add
|
|
|
3f58c5 |
+ * with the following interface:
|
|
|
3f58c5 |
+ *
|
|
|
3f58c5 |
+ * bool add(T summand_1, T summand_2, T& result)
|
|
|
3f58c5 |
+ *
|
|
|
3f58c5 |
+ * where T is the type over which the struct is templated.
|
|
|
3f58c5 |
+ *
|
|
|
3f58c5 |
+ * The function performs a check whether the addition summand_1 + summand_2
|
|
|
3f58c5 |
+ * can be performed without an overflow. If the operation would overflow,
|
|
|
3f58c5 |
+ * true is returned and the addition is not performed if it would result in
|
|
|
3f58c5 |
+ * undefined behavior. If no overflow occurs, the sum is saved in result and
|
|
|
3f58c5 |
+ * false is returned.
|
|
|
3f58c5 |
+ *
|
|
|
3f58c5 |
+ * fallback_add_overflow implements a portable but slower overflow check.
|
|
|
3f58c5 |
+ * builtin_add_overflow uses compiler builtins (when available) and should
|
|
|
3f58c5 |
+ * be considerably faster. As builtins are not available for all types,
|
|
|
3f58c5 |
+ * builtin_add_overflow falls back to fallback_add_overflow when no builtin
|
|
|
3f58c5 |
+ * is available.
|
|
|
3f58c5 |
+ */
|
|
|
3f58c5 |
+ namespace Internal
|
|
|
3f58c5 |
+ {
|
|
|
3f58c5 |
+ /*!
|
|
|
3f58c5 |
+ * @brief Helper struct to determine whether a type is signed or unsigned
|
|
|
3f58c5 |
+
|
|
|
3f58c5 |
+ * This struct is a backport of std::is_signed from C++11. It has a public
|
|
|
3f58c5 |
+ * enum with the property VALUE which is true when the type is signed or
|
|
|
3f58c5 |
+ * false if it is unsigned.
|
|
|
3f58c5 |
+ */
|
|
|
3f58c5 |
+ template <typename T>
|
|
|
3f58c5 |
+ struct is_signed
|
|
|
3f58c5 |
+ {
|
|
|
3f58c5 |
+ enum
|
|
|
3f58c5 |
+ {
|
|
|
3f58c5 |
+ VALUE = T(-1) < T(0)
|
|
|
3f58c5 |
+ };
|
|
|
3f58c5 |
+ };
|
|
|
3f58c5 |
+
|
|
|
3f58c5 |
+ /*!
|
|
|
3f58c5 |
+ * @brief Helper struct for SFINAE, from C++11
|
|
|
3f58c5 |
+
|
|
|
3f58c5 |
+ * This struct has a public typedef called type typedef'd to T if B is
|
|
|
3f58c5 |
+ * true. Otherwise there is no typedef.
|
|
|
3f58c5 |
+ */
|
|
|
3f58c5 |
+ template <bool B, class T = void>
|
|
|
3f58c5 |
+ struct enable_if
|
|
|
3f58c5 |
+ {
|
|
|
3f58c5 |
+ };
|
|
|
3f58c5 |
+
|
|
|
3f58c5 |
+ /*!
|
|
|
3f58c5 |
+ * @brief Specialization of enable_if for the case B == true
|
|
|
3f58c5 |
+ */
|
|
|
3f58c5 |
+ template <class T>
|
|
|
3f58c5 |
+ struct enable_if<true, T>
|
|
|
3f58c5 |
+ {
|
|
|
3f58c5 |
+ typedef T type;
|
|
|
3f58c5 |
+ };
|
|
|
3f58c5 |
+
|
|
|
3f58c5 |
+ /*!
|
|
|
3f58c5 |
+ * @brief Fallback overflow checker, specialized via SFINAE
|
|
|
3f58c5 |
+ *
|
|
|
3f58c5 |
+ * This struct implements a 'fallback' addition with an overflow check,
|
|
|
3f58c5 |
+ * i.e. it does not rely on compiler intrinsics. It is specialized via
|
|
|
3f58c5 |
+ * SFINAE for signed and unsigned integer types and provides a public
|
|
|
3f58c5 |
+ * static member function add.
|
|
|
3f58c5 |
+ */
|
|
|
3f58c5 |
+ template <typename T, typename = void>
|
|
|
3f58c5 |
+ struct fallback_add_overflow;
|
|
|
3f58c5 |
+
|
|
|
3f58c5 |
+ /*!
|
|
|
3f58c5 |
+ * @brief Overload of fallback_add_overflow for signed integers
|
|
|
3f58c5 |
+ */
|
|
|
3f58c5 |
+ template <typename T>
|
|
|
3f58c5 |
+ struct fallback_add_overflow<T, typename enable_if<is_signed<T>::VALUE>::type>
|
|
|
3f58c5 |
+ {
|
|
|
3f58c5 |
+ /*!
|
|
|
3f58c5 |
+ * @brief Adds the two summands only if no overflow occurs
|
|
|
3f58c5 |
+ *
|
|
|
3f58c5 |
+ * This function performs a check if summand_1 + summand_2 would
|
|
|
3f58c5 |
+ * overflow and returns true in that case. If no overflow occurs,
|
|
|
3f58c5 |
+ * the sum is saved in result and false is returned.
|
|
|
3f58c5 |
+ *
|
|
|
3f58c5 |
+ * @return true on overflow, false on no overflow
|
|
|
3f58c5 |
+ *
|
|
|
3f58c5 |
+ * The check for an overflow is performed before the addition to
|
|
|
3f58c5 |
+ * ensure that no undefined behavior occurs. The value in result is
|
|
|
3f58c5 |
+ * only valid when the function returns false.
|
|
|
3f58c5 |
+ *
|
|
|
3f58c5 |
+ * Further information:
|
|
|
3f58c5 |
+ * https://wiki.sei.cmu.edu/confluence/display/c/INT32-C.+Ensure+that+operations+on+signed+integers+do+not+result+in+overflow
|
|
|
3f58c5 |
+ */
|
|
|
3f58c5 |
+ static bool add(T summand_1, T summand_2, T& result)
|
|
|
3f58c5 |
+ {
|
|
|
3f58c5 |
+ if (((summand_2 >= 0) && (summand_1 > std::numeric_limits<T>::max() - summand_2)) ||
|
|
|
3f58c5 |
+ ((summand_2 < 0) && (summand_1 < std::numeric_limits<T>::min() - summand_2))) {
|
|
|
3f58c5 |
+ return true;
|
|
|
3f58c5 |
+ } else {
|
|
|
3f58c5 |
+ result = summand_1 + summand_2;
|
|
|
3f58c5 |
+ return false;
|
|
|
3f58c5 |
+ }
|
|
|
3f58c5 |
+ }
|
|
|
3f58c5 |
+ };
|
|
|
3f58c5 |
+
|
|
|
3f58c5 |
+ /*!
|
|
|
3f58c5 |
+ * @brief Overload of fallback_add_overflow for unsigned integers
|
|
|
3f58c5 |
+ */
|
|
|
3f58c5 |
+ template <typename T>
|
|
|
3f58c5 |
+ struct fallback_add_overflow<T, typename enable_if<!is_signed<T>::VALUE>::type>
|
|
|
3f58c5 |
+ {
|
|
|
3f58c5 |
+ /*!
|
|
|
3f58c5 |
+ * @brief Adds the two summands only if no overflow occurs
|
|
|
3f58c5 |
+ *
|
|
|
3f58c5 |
+ * This function performs a check if summand_1 + summand_2 would
|
|
|
3f58c5 |
+ * overflow and returns true in that case. If no overflow occurs,
|
|
|
3f58c5 |
+ * the sum is saved in result and false is returned.
|
|
|
3f58c5 |
+ *
|
|
|
3f58c5 |
+ * @return true on overflow, false on no overflow
|
|
|
3f58c5 |
+ *
|
|
|
3f58c5 |
+ * Further information:
|
|
|
3f58c5 |
+ * https://wiki.sei.cmu.edu/confluence/display/c/INT30-C.+Ensure+that+unsigned+integer+operations+do+not+wrap
|
|
|
3f58c5 |
+ */
|
|
|
3f58c5 |
+ static bool add(T summand_1, T summand_2, T& result)
|
|
|
3f58c5 |
+ {
|
|
|
3f58c5 |
+ if (summand_1 > std::numeric_limits<T>::max() - summand_2) {
|
|
|
3f58c5 |
+ return true;
|
|
|
3f58c5 |
+ } else {
|
|
|
3f58c5 |
+ result = summand_1 + summand_2;
|
|
|
3f58c5 |
+ return false;
|
|
|
3f58c5 |
+ }
|
|
|
3f58c5 |
+ }
|
|
|
3f58c5 |
+ };
|
|
|
3f58c5 |
+
|
|
|
3f58c5 |
+ /*!
|
|
|
3f58c5 |
+ * @brief Overflow checker using compiler intrinsics
|
|
|
3f58c5 |
+ *
|
|
|
3f58c5 |
+ * This struct provides an add function with the same interface &
|
|
|
3f58c5 |
+ * behavior as fallback_add_overload::add but it relies on compiler
|
|
|
3f58c5 |
+ * intrinsics instead. This version should be considerably faster than
|
|
|
3f58c5 |
+ * the fallback version as it can fully utilize available CPU
|
|
|
3f58c5 |
+ * instructions & the compiler's diagnostic.
|
|
|
3f58c5 |
+ *
|
|
|
3f58c5 |
+ * However, as some compilers don't provide intrinsics for certain
|
|
|
3f58c5 |
+ * types, the default implementation of add is the version from falback.
|
|
|
3f58c5 |
+ *
|
|
|
3f58c5 |
+ * The struct is explicitly specialized for each type via #ifdefs for
|
|
|
3f58c5 |
+ * each compiler.
|
|
|
3f58c5 |
+ */
|
|
|
3f58c5 |
+ template <typename T>
|
|
|
3f58c5 |
+ struct builtin_add_overflow
|
|
|
3f58c5 |
+ {
|
|
|
3f58c5 |
+ /*!
|
|
|
3f58c5 |
+ * @brief Add summand_1 and summand_2 and check for overflows.
|
|
|
3f58c5 |
+ *
|
|
|
3f58c5 |
+ * This is the default add() function that uses
|
|
|
3f58c5 |
+ * fallback_add_overflow<T>::add(). All specializations must have
|
|
|
3f58c5 |
+ * exactly the same interface and behave the same way.
|
|
|
3f58c5 |
+ */
|
|
|
3f58c5 |
+ static inline bool add(T summand_1, T summand_2, T& result)
|
|
|
3f58c5 |
+ {
|
|
|
3f58c5 |
+ return fallback_add_overflow<T>::add(summand_1, summand_2, result);
|
|
|
3f58c5 |
+ }
|
|
|
3f58c5 |
+ };
|
|
|
3f58c5 |
+
|
|
|
3f58c5 |
+#if defined(__GNUC__) || defined(__clang__)
|
|
|
3f58c5 |
+
|
|
|
3f58c5 |
+/*!
|
|
|
3f58c5 |
+ * This macro pastes a specialization of builtin_add_overflow using gcc's &
|
|
|
3f58c5 |
+ * clang's __builtin_(s/u)add(l)(l)_overlow()
|
|
|
3f58c5 |
+ *
|
|
|
3f58c5 |
+ * The add function is implemented by forwarding the parameters to the intrinsic
|
|
|
3f58c5 |
+ * and returning its value.
|
|
|
3f58c5 |
+ *
|
|
|
3f58c5 |
+ * The intrinsics are documented here:
|
|
|
3f58c5 |
+ * https://gcc.gnu.org/onlinedocs/gcc/Integer-Overflow-Builtins.html#Integer-Overflow-Builtins
|
|
|
3f58c5 |
+ */
|
|
|
3f58c5 |
+#define SPECIALIZE_builtin_add_overflow(type, builtin_name) \
|
|
|
3f58c5 |
+ template <> \
|
|
|
3f58c5 |
+ struct builtin_add_overflow<type> \
|
|
|
3f58c5 |
+ { \
|
|
|
3f58c5 |
+ static inline bool add(type summand_1, type summand_2, type& result) \
|
|
|
3f58c5 |
+ { \
|
|
|
3f58c5 |
+ return builtin_name(summand_1, summand_2, &result); \
|
|
|
3f58c5 |
+ } \
|
|
|
3f58c5 |
+ }
|
|
|
3f58c5 |
+
|
|
|
3f58c5 |
+ SPECIALIZE_builtin_add_overflow(int, __builtin_sadd_overflow);
|
|
|
3f58c5 |
+ SPECIALIZE_builtin_add_overflow(long, __builtin_saddl_overflow);
|
|
|
3f58c5 |
+ SPECIALIZE_builtin_add_overflow(long long, __builtin_saddll_overflow);
|
|
|
3f58c5 |
+
|
|
|
3f58c5 |
+ SPECIALIZE_builtin_add_overflow(unsigned int, __builtin_uadd_overflow);
|
|
|
3f58c5 |
+ SPECIALIZE_builtin_add_overflow(unsigned long, __builtin_uaddl_overflow);
|
|
|
3f58c5 |
+ SPECIALIZE_builtin_add_overflow(unsigned long long, __builtin_uaddll_overflow);
|
|
|
3f58c5 |
+
|
|
|
3f58c5 |
+#undef SPECIALIZE_builtin_add_overflow
|
|
|
3f58c5 |
+
|
|
|
3f58c5 |
+#elif defined(_MSC_VER)
|
|
|
3f58c5 |
+
|
|
|
3f58c5 |
+/*!
|
|
|
3f58c5 |
+ * This macro pastes a specialization of builtin_add_overflow using MSVC's
|
|
|
3f58c5 |
+ * U(Int/Long/LongLong)Add.
|
|
|
3f58c5 |
+ *
|
|
|
3f58c5 |
+ * The add function is implemented by forwarding the parameters to the
|
|
|
3f58c5 |
+ * intrinsic. As MSVC's intrinsics return S_OK on success, this specialization
|
|
|
3f58c5 |
+ * returns whether the intrinsics return value does not equal S_OK. This ensures
|
|
|
3f58c5 |
+ * a uniform interface of the add function (false is returned when no overflow
|
|
|
3f58c5 |
+ * occurs, true on overflow).
|
|
|
3f58c5 |
+ *
|
|
|
3f58c5 |
+ * The intrinsics are documented here:
|
|
|
3f58c5 |
+ * https://msdn.microsoft.com/en-us/library/windows/desktop/ff516460(v=vs.85).aspx
|
|
|
3f58c5 |
+ */
|
|
|
3f58c5 |
+#define SPECIALIZE_builtin_add_overflow_WIN(type, builtin_name) \
|
|
|
3f58c5 |
+ template <> \
|
|
|
3f58c5 |
+ struct builtin_add_overflow<type> \
|
|
|
3f58c5 |
+ { \
|
|
|
3f58c5 |
+ static inline bool add(type summand_1, type summand_2, type& result) \
|
|
|
3f58c5 |
+ { \
|
|
|
3f58c5 |
+ return builtin_name(summand_1, summand_2, &result) != S_OK; \
|
|
|
3f58c5 |
+ } \
|
|
|
3f58c5 |
+ }
|
|
|
3f58c5 |
+
|
|
|
3f58c5 |
+ SPECIALIZE_builtin_add_overflow_WIN(unsigned int, UIntAdd);
|
|
|
3f58c5 |
+ SPECIALIZE_builtin_add_overflow_WIN(unsigned long, ULongAdd);
|
|
|
3f58c5 |
+ SPECIALIZE_builtin_add_overflow_WIN(unsigned long long, ULongLongAdd);
|
|
|
3f58c5 |
+
|
|
|
3f58c5 |
+#undef SPECIALIZE_builtin_add_overflow_WIN
|
|
|
3f58c5 |
+
|
|
|
3f58c5 |
+#endif
|
|
|
3f58c5 |
+
|
|
|
3f58c5 |
+ } // namespace Internal
|
|
|
3f58c5 |
+
|
|
|
3f58c5 |
+ /*!
|
|
|
3f58c5 |
+ * @brief Safe addition, throws an exception on overflow.
|
|
|
3f58c5 |
+ *
|
|
|
3f58c5 |
+ * This function returns the result of summand_1 and summand_2 only when the
|
|
|
3f58c5 |
+ * operation would not overflow, otherwise an exception of type
|
|
|
3f58c5 |
+ * std::overflow_error is thrown.
|
|
|
3f58c5 |
+ *
|
|
|
3f58c5 |
+ * @param[in] summand_1, summand_2 summands to be summed up
|
|
|
3f58c5 |
+ * @return the sum of summand_1 and summand_2
|
|
|
3f58c5 |
+ * @throws std::overflow_error if the addition would overflow
|
|
|
3f58c5 |
+ *
|
|
|
3f58c5 |
+ * This function utilizes compiler builtins when available and should have a
|
|
|
3f58c5 |
+ * very small performance hit then. When builtins are unavailable, a more
|
|
|
3f58c5 |
+ * extensive check is required.
|
|
|
3f58c5 |
+ *
|
|
|
3f58c5 |
+ * Builtins are available for the following configurations:
|
|
|
3f58c5 |
+ * - GCC/Clang for signed and unsigned int, long and long long (not char & short)
|
|
|
3f58c5 |
+ * - MSVC for unsigned int, long and long long
|
|
|
3f58c5 |
+ */
|
|
|
3f58c5 |
+ template <typename T>
|
|
|
3f58c5 |
+ T add(T summand_1, T summand_2)
|
|
|
3f58c5 |
+ {
|
|
|
3f58c5 |
+ T res = 0;
|
|
|
3f58c5 |
+ if (Internal::builtin_add_overflow<T>::add(summand_1, summand_2, res)) {
|
|
|
3f58c5 |
+ throw std::overflow_error("Overflow in addition");
|
|
|
3f58c5 |
+ }
|
|
|
3f58c5 |
+ return res;
|
|
|
3f58c5 |
+ }
|
|
|
3f58c5 |
+
|
|
|
3f58c5 |
+} // namespace Safe
|
|
|
3f58c5 |
+
|
|
|
3f58c5 |
+#endif // SAFE_OP_HPP_
|