diff --git a/src/quicktimevideo.cpp b/src/quicktimevideo.cpp index 352fe4b0..fa567eca 100644 --- a/src/quicktimevideo.cpp +++ b/src/quicktimevideo.cpp @@ -575,6 +575,14 @@ void QuickTimeVideo::decodeBlock(std::string const& entered_from) { tagDecoder(buf, newsize); } // QuickTimeVideo::decodeBlock +static std::string readString(BasicIo& io, size_t size) { + enforce(size <= io.size() - io.tell(), Exiv2::ErrorCode::kerCorruptedMetadata); + Exiv2::DataBuf str(size + 1); + io.readOrThrow(str.data(), size); + str.write_uint8(size, 0); // nul-terminate string + return Exiv2::toString(str.data()); +} + void QuickTimeVideo::tagDecoder(Exiv2::DataBuf& buf, size_t size) { assert(buf.size() > 4); @@ -626,30 +634,21 @@ void QuickTimeVideo::tagDecoder(Exiv2::DataBuf& buf, size_t size) { keysTagDecoder(size); else if (equalsQTimeTag(buf, "url ")) { - Exiv2::DataBuf url(size + 1); - io_->readOrThrow(url.data(), size); - url.write_uint8(size, 0); if (currentStream_ == Video) - xmpData_["Xmp.video.URL"] = Exiv2::toString(url.data()); + xmpData_["Xmp.video.URL"] = readString(*io_, size); else if (currentStream_ == Audio) - xmpData_["Xmp.audio.URL"] = Exiv2::toString(url.data()); + xmpData_["Xmp.audio.URL"] = readString(*io_, size); } else if (equalsQTimeTag(buf, "urn ")) { - Exiv2::DataBuf urn(size + 1); - io_->readOrThrow(urn.data(), size); - urn.write_uint8(size, 0); if (currentStream_ == Video) - xmpData_["Xmp.video.URN"] = Exiv2::toString(urn.data()); + xmpData_["Xmp.video.URN"] = readString(*io_, size); else if (currentStream_ == Audio) - xmpData_["Xmp.audio.URN"] = Exiv2::toString(urn.data()); + xmpData_["Xmp.audio.URN"] = readString(*io_, size); } else if (equalsQTimeTag(buf, "dcom")) { - Exiv2::DataBuf dcom(size + 1); - io_->readOrThrow(dcom.data(), size); - dcom.write_uint8(size, 0); - xmpData_["Xmp.video.Compressor"] = Exiv2::toString(dcom.data()); + xmpData_["Xmp.video.Compressor"] = readString(*io_, size); } else if (equalsQTimeTag(buf, "smhd")) { @@ -782,6 +781,7 @@ void QuickTimeVideo::CameraTagsDecoder(size_t size_external) { xmpData_["Xmp.video.FocalLength"] = buf.read_uint32(0, littleEndian) / (double)buf2.read_uint32(0, littleEndian); io_->seek(static_cast(95), BasicIo::cur); io_->readOrThrow(buf.data(), 48); + buf.write_uint8(48, 0); xmpData_["Xmp.video.Software"] = Exiv2::toString(buf.data()); io_->readOrThrow(buf.data(), 4); xmpData_["Xmp.video.ISO"] = buf.read_uint32(0, littleEndian); @@ -829,8 +829,8 @@ void QuickTimeVideo::userDataDecoder(size_t size_external) { else if (equalsQTimeTag(buf, "CNCV") || equalsQTimeTag(buf, "CNFV") || equalsQTimeTag(buf, "CNMN") || equalsQTimeTag(buf, "NCHD") || equalsQTimeTag(buf, "FFMV")) { - io_->readOrThrow(buf.data(), size - 8); - xmpData_[exvGettext(tv->label_)] = Exiv2::toString(buf.data()); + enforce(tv, Exiv2::ErrorCode::kerCorruptedMetadata); + xmpData_[exvGettext(tv->label_)] = readString(*io_, size - 8); } else if (equalsQTimeTag(buf, "CMbo") || equalsQTimeTag(buf, "Cmbo")) { @@ -845,15 +845,8 @@ void QuickTimeVideo::userDataDecoder(size_t size_external) { } else if (tv) { - const size_t tv_size = size - 12; - if (tv_size >= buf.size()) { - enforce(tv_size <= io_->size() - io_->tell(), Exiv2::ErrorCode::kerCorruptedMetadata); - buf.resize(tv_size + 1); - } io_->readOrThrow(buf.data(), 4); - io_->readOrThrow(buf.data(), tv_size); - buf.write_uint8(tv_size, 0); // nul-terminate string - xmpData_[exvGettext(tv->label_)] = Exiv2::toString(buf.data()); + xmpData_[exvGettext(tv->label_)] = readString(*io_, size - 12); } else if (td) diff --git a/test/data/issue_2376_poc.mp4 b/test/data/issue_2376_poc.mp4 new file mode 100644 index 00000000..fc2c61bd Binary files /dev/null and b/test/data/issue_2376_poc.mp4 differ diff --git a/test/data/issue_2377_poc.mp4 b/test/data/issue_2377_poc.mp4 new file mode 100644 index 00000000..74735138 Binary files /dev/null and b/test/data/issue_2377_poc.mp4 differ diff --git a/tests/bugfixes/github/test_issue_2376.py b/tests/bugfixes/github/test_issue_2376.py new file mode 100644 index 00000000..2afdbc96 --- /dev/null +++ b/tests/bugfixes/github/test_issue_2376.py @@ -0,0 +1,13 @@ +# -*- coding: utf-8 -*- + +from system_tests import CaseMeta, check_no_ASAN_UBSAN_errors + +class issue_2376_QuickTimeVideo_userDataDecoder_null_deref(metaclass=CaseMeta): + url = "https://github.com/Exiv2/exiv2/issues/2376" + filename = "$data_path/issue_2376_poc.mp4" + commands = ["$exiv2 $filename"] + retval = [1] + stderr = ["""$exiv2_exception_message $filename: +$kerCorruptedMetadata +"""] + stdout = [""] diff --git a/tests/bugfixes/github/test_issue_2377.py b/tests/bugfixes/github/test_issue_2377.py new file mode 100644 index 00000000..010a4668 --- /dev/null +++ b/tests/bugfixes/github/test_issue_2377.py @@ -0,0 +1,17 @@ +# -*- coding: utf-8 -*- + +from system_tests import CaseMeta, check_no_ASAN_UBSAN_errors + +class issue_2377_QuickTimeVideo_userDataDecoder_buffer_overflow(metaclass=CaseMeta): + url = "https://github.com/Exiv2/exiv2/issues/2377" + filename = "$data_path/issue_2377_poc.mp4" + commands = ["$exiv2 $filename"] + retval = [253] + stderr = ["""$filename: No Exif data found in the file +"""] + stdout = ["""File name : $filename +File size : 225 Bytes +MIME type : video/quicktime +Image size : 0 x 0 +"""] + diff --git a/tests/regression_tests/test_regression_allfiles.py b/tests/regression_tests/test_regression_allfiles.py index c9b23775..d4fb53b9 100644 --- a/tests/regression_tests/test_regression_allfiles.py +++ b/tests/regression_tests/test_regression_allfiles.py @@ -61,6 +61,8 @@ def get_valid_files(data_dir): "issue_2340_poc.mp4", "issue_2345_poc.mp4", "issue_2366_poc.mp4", + "issue_2376_poc.mp4", + "issue_2377_poc.mp4", "2018-01-09-exiv2-crash-001.tiff", "cve_2017_1000126_stack-oob-read.webp", "exiv2-bug1247.jpg",