diff --git a/src/rafimage.cpp b/src/rafimage.cpp index 0c23712e..bf3d29c7 100644 --- a/src/rafimage.cpp +++ b/src/rafimage.cpp @@ -34,6 +34,8 @@ #include "basicio.hpp" #include "error.hpp" #include "futils.hpp" +#include "enforce.hpp" +#include "safe_op.hpp" // + standard includes #include @@ -289,17 +291,31 @@ namespace Exiv2 { clearMetadata(); - io_->seek(84,BasicIo::beg); + if (io_->seek(84,BasicIo::beg) != 0) throw Error(kerFailedToReadImageData); byte jpg_img_offset [4]; - io_->read(jpg_img_offset, 4); + if (io_->read(jpg_img_offset, 4) != 4) throw Error(kerFailedToReadImageData); byte jpg_img_length [4]; - io_->read(jpg_img_length, 4); - long jpg_img_off = Exiv2::getULong((const byte *) jpg_img_offset, bigEndian); - long jpg_img_len = Exiv2::getULong((const byte *) jpg_img_length, bigEndian); + if (io_->read(jpg_img_length, 4) != 4) throw Error(kerFailedToReadImageData); + uint32_t jpg_img_off_u32 = Exiv2::getULong((const byte *) jpg_img_offset, bigEndian); + uint32_t jpg_img_len_u32 = Exiv2::getULong((const byte *) jpg_img_length, bigEndian); + + enforce(Safe::add(jpg_img_off_u32, jpg_img_len_u32) <= io_->size(), kerCorruptedMetadata); + +#if LONG_MAX < UINT_MAX + enforce(jpg_img_off_u32 <= static_cast(std::numeric_limits::max()), + kerCorruptedMetadata); + enforce(jpg_img_len_u32 <= static_cast(std::numeric_limits::max()), + kerCorruptedMetadata); +#endif + + long jpg_img_off = static_cast(jpg_img_off_u32); + long jpg_img_len = static_cast(jpg_img_len_u32); + + enforce(jpg_img_len >= 12, kerCorruptedMetadata); DataBuf buf(jpg_img_len - 12); - io_->seek(jpg_img_off + 12,BasicIo::beg); - io_->read(buf.pData_, buf.size_ - 12); + if (io_->seek(jpg_img_off + 12,BasicIo::beg) != 0) throw Error(kerFailedToReadImageData); + io_->read(buf.pData_, buf.size_); if (io_->error() || io_->eof()) throw Error(kerFailedToReadImageData); io_->seek(0,BasicIo::beg); // rewind diff --git a/test/data/issue_857_coverage.raf b/test/data/issue_857_coverage.raf new file mode 100644 index 00000000..3af0bea3 Binary files /dev/null and b/test/data/issue_857_coverage.raf differ diff --git a/test/data/issue_857_poc.raf b/test/data/issue_857_poc.raf new file mode 100644 index 00000000..109dedc4 Binary files /dev/null and b/test/data/issue_857_poc.raf differ diff --git a/tests/bugfixes/github/test_issue_857.py b/tests/bugfixes/github/test_issue_857.py new file mode 100644 index 00000000..266bebcd --- /dev/null +++ b/tests/bugfixes/github/test_issue_857.py @@ -0,0 +1,28 @@ +# -*- coding: utf-8 -*- + +from system_tests import CaseMeta, path + + +class OutOfMemoryInRafImageReadMetadata(metaclass=CaseMeta): + """ + Regression test for the bug described in: + https://github.com/Exiv2/exiv2/issues/857 + + There is no bounds check on the value of jpg_img_len in + RafImage::readMetadata(), leading to an out-of-memory error. + """ + url = "https://github.com/Exiv2/exiv2/issues/857" + + filename1 = path("$data_path/issue_857_poc.raf") + filename2 = path("$data_path/issue_857_coverage.raf") + commands = ["$exiv2 $filename1", "$exiv2 $filename2"] + stdout = ["", ""] + stderr = [ +"""Exiv2 exception in print action for file $filename1: +$kerCorruptedMetadata +""", +"""Exiv2 exception in print action for file $filename2: +This does not look like a TIFF image +""" +] + retval = [1,1]