Closed fgeek closed 6 years ago
This has been assigned CVE-2017-17724
This appears to be fixed on 'master'
506 rmills@rmillsmbp:~/Downloads $ exiv2 2018-01-09-exiv2-crash-002.tiff
invalid type value detected in Image::printIFDStructure: 40448
Exiv2 exception in print action for file 2018-01-09-exiv2-crash-002.tiff:
invalid type value detected in Image::printIFDStructure
507 rmills@rmillsmbp:~/Downloads $
@clanmills you need to build with ASan to detect the issue. Without ASan I see same output.
Thanks, Henri. I've reproduced this and I am investigating.
Also can be triggered with Valgrind:
kbabioch@tumbleweed:~> valgrind exiv2 poc_1.tiff
==10752== Memcheck, a memory error detector
==10752== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==10752== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==10752== Command: exiv2 poc_1.tiff
==10752==
==10752== Conditional jump or move depends on uninitialised value(s)
==10752== at 0x4F81200: Exiv2::Internal::binaryToString[abi:cxx11](unsigned char const*, unsigned long, unsigned long) (in /usr/lib64/libexiv2.so.26.0.0)
==10752== by 0x4F812D8: Exiv2::Internal::binaryToString[abi:cxx11](Exiv2::DataBuf&, unsigned long, unsigned long) (in /usr/lib64/libexiv2.so.26.0.0)
==10752== by 0x4F837BC: Exiv2::Image::printIFDStructure(Exiv2::BasicIo&, std::ostream&, Exiv2::PrintStructureOption, unsigned int, bool, char, int) (in /usr/lib64/libexiv2.so.26.0.0)
==10752== by 0x4F853C4: Exiv2::Image::printTiffStructure(Exiv2::BasicIo&, std::ostream&, Exiv2::PrintStructureOption, int, unsigned long) (in /usr/lib64/libexiv2.so.26.0.0)
==10752== by 0x4FEA303: Exiv2::TiffImage::printStructure(std::ostream&, Exiv2::PrintStructureOption, int) (in /usr/lib64/libexiv2.so.26.0.0)
==10752== by 0x4FEBD05: Exiv2::TiffImage::readMetadata() (in /usr/lib64/libexiv2.so.26.0.0)
==10752== by 0x127A08: Action::Print::printSummary() (in /usr/bin/exiv2)
==10752== by 0x12964F: Action::Print::run(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (in /usr/bin/exiv2)
==10752== by 0x113F0C: main (in /usr/bin/exiv2)
==10752==
==10752== Invalid read of size 1
==10752== at 0x4F88DA9: Exiv2::IptcData::printStructure(std::ostream&, unsigned char const*, unsigned long, unsigned int) (in /usr/lib64/libexiv2.so.26.0.0)
==10752== by 0x4F83929: Exiv2::Image::printIFDStructure(Exiv2::BasicIo&, std::ostream&, Exiv2::PrintStructureOption, unsigned int, bool, char, int) (in /usr/lib64/libexiv2.so.26.0.0)
==10752== by 0x4F853C4: Exiv2::Image::printTiffStructure(Exiv2::BasicIo&, std::ostream&, Exiv2::PrintStructureOption, int, unsigned long) (in /usr/lib64/libexiv2.so.26.0.0)
==10752== by 0x4FEA303: Exiv2::TiffImage::printStructure(std::ostream&, Exiv2::PrintStructureOption, int) (in /usr/lib64/libexiv2.so.26.0.0)
==10752== by 0x4FEBD05: Exiv2::TiffImage::readMetadata() (in /usr/lib64/libexiv2.so.26.0.0)
==10752== by 0x127A08: Action::Print::printSummary() (in /usr/bin/exiv2)
==10752== by 0x12964F: Action::Print::run(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (in /usr/bin/exiv2)
==10752== by 0x113F0C: main (in /usr/bin/exiv2)
==10752== Address 0x68a98c0 is 0 bytes after a block of size 0 alloc'd
==10752== at 0x4C2EE1F: operator new[](unsigned long) (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==10752== by 0x4F838F1: Exiv2::Image::printIFDStructure(Exiv2::BasicIo&, std::ostream&, Exiv2::PrintStructureOption, unsigned int, bool, char, int) (in /usr/lib64/libexiv2.so.26.0.0)
==10752== by 0x4F853C4: Exiv2::Image::printTiffStructure(Exiv2::BasicIo&, std::ostream&, Exiv2::PrintStructureOption, int, unsigned long) (in /usr/lib64/libexiv2.so.26.0.0)
==10752== by 0x4FEA303: Exiv2::TiffImage::printStructure(std::ostream&, Exiv2::PrintStructureOption, int) (in /usr/lib64/libexiv2.so.26.0.0)
==10752== by 0x4FEBD05: Exiv2::TiffImage::readMetadata() (in /usr/lib64/libexiv2.so.26.0.0)
==10752== by 0x127A08: Action::Print::printSummary() (in /usr/bin/exiv2)
==10752== by 0x12964F: Action::Print::run(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (in /usr/bin/exiv2)
==10752== by 0x113F0C: main (in /usr/bin/exiv2)
==10752==
==10752== Invalid read of size 1
==10752== at 0x4F88DB0: Exiv2::IptcData::printStructure(std::ostream&, unsigned char const*, unsigned long, unsigned int) (in /usr/lib64/libexiv2.so.26.0.0)
==10752== by 0x4F83929: Exiv2::Image::printIFDStructure(Exiv2::BasicIo&, std::ostream&, Exiv2::PrintStructureOption, unsigned int, bool, char, int) (in /usr/lib64/libexiv2.so.26.0.0)
==10752== by 0x4F853C4: Exiv2::Image::printTiffStructure(Exiv2::BasicIo&, std::ostream&, Exiv2::PrintStructureOption, int, unsigned long) (in /usr/lib64/libexiv2.so.26.0.0)
==10752== by 0x4FEA303: Exiv2::TiffImage::printStructure(std::ostream&, Exiv2::PrintStructureOption, int) (in /usr/lib64/libexiv2.so.26.0.0)
==10752== by 0x4FEBD05: Exiv2::TiffImage::readMetadata() (in /usr/lib64/libexiv2.so.26.0.0)
==10752== by 0x127A08: Action::Print::printSummary() (in /usr/bin/exiv2)
==10752== by 0x12964F: Action::Print::run(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (in /usr/bin/exiv2)
==10752== by 0x113F0C: main (in /usr/bin/exiv2)
==10752== Address 0x68a98c1 is 1 bytes after a block of size 0 alloc'd
==10752== at 0x4C2EE1F: operator new[](unsigned long) (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==10752== by 0x4F838F1: Exiv2::Image::printIFDStructure(Exiv2::BasicIo&, std::ostream&, Exiv2::PrintStructureOption, unsigned int, bool, char, int) (in /usr/lib64/libexiv2.so.26.0.0)
==10752== by 0x4F853C4: Exiv2::Image::printTiffStructure(Exiv2::BasicIo&, std::ostream&, Exiv2::PrintStructureOption, int, unsigned long) (in /usr/lib64/libexiv2.so.26.0.0)
==10752== by 0x4FEA303: Exiv2::TiffImage::printStructure(std::ostream&, Exiv2::PrintStructureOption, int) (in /usr/lib64/libexiv2.so.26.0.0)
==10752== by 0x4FEBD05: Exiv2::TiffImage::readMetadata() (in /usr/lib64/libexiv2.so.26.0.0)
==10752== by 0x127A08: Action::Print::printSummary() (in /usr/bin/exiv2)
==10752== by 0x12964F: Action::Print::run(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (in /usr/bin/exiv2)
==10752== by 0x113F0C: main (in /usr/bin/exiv2)
==10752==
==10752==
==10752== Process terminating with default action of signal 11 (SIGSEGV): dumping core
==10752== Access not within mapped region at address 0x6C6F000
==10752== at 0x4F88DB0: Exiv2::IptcData::printStructure(std::ostream&, unsigned char const*, unsigned long, unsigned int) (in /usr/lib64/libexiv2.so.26.0.0)
==10752== by 0x4F83929: Exiv2::Image::printIFDStructure(Exiv2::BasicIo&, std::ostream&, Exiv2::PrintStructureOption, unsigned int, bool, char, int) (in /usr/lib64/libexiv2.so.26.0.0)
==10752== by 0x4F853C4: Exiv2::Image::printTiffStructure(Exiv2::BasicIo&, std::ostream&, Exiv2::PrintStructureOption, int, unsigned long) (in /usr/lib64/libexiv2.so.26.0.0)
==10752== by 0x4FEA303: Exiv2::TiffImage::printStructure(std::ostream&, Exiv2::PrintStructureOption, int) (in /usr/lib64/libexiv2.so.26.0.0)
==10752== by 0x4FEBD05: Exiv2::TiffImage::readMetadata() (in /usr/lib64/libexiv2.so.26.0.0)
==10752== by 0x127A08: Action::Print::printSummary() (in /usr/bin/exiv2)
==10752== by 0x12964F: Action::Print::run(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (in /usr/bin/exiv2)
==10752== by 0x113F0C: main (in /usr/bin/exiv2)
==10752== If you believe this happened as a result of a stack
==10752== overflow in your program's main thread (unlikely but
==10752== possible), you can try to increase the size of the
==10752== main thread stack using the --main-stacksize= flag.
==10752== The main thread stack size used in this run was 8388608.
==10752==
==10752== HEAP SUMMARY:
==10752== in use at exit: 31,943 bytes in 491 blocks
==10752== total heap usage: 860 allocs, 369 frees, 179,019 bytes allocated
==10752==
==10752== LEAK SUMMARY:
==10752== definitely lost: 0 bytes in 0 blocks
==10752== indirectly lost: 0 bytes in 0 blocks
==10752== possibly lost: 0 bytes in 0 blocks
==10752== still reachable: 31,943 bytes in 491 blocks
==10752== suppressed: 0 bytes in 0 blocks
==10752== Rerun with --leak-check=full to see details of leaked memory
==10752==
==10752== For counts of detected and suppressed errors, rerun with: -v
==10752== Use --track-origins=yes to see where uninitialised values come from
==10752== ERROR SUMMARY: 3954513 errors from 3 contexts (suppressed: 0 from 0)
Speicherzugriffsfehler (Speicherabzug geschrieben)
I know what's causing this and I'm working on a fix. The code in Exiv2::IptcData::printStructure is reading bytes past the end of buffer. The current code is:
void IptcData::printStructure(std::ostream& out, const byte* bytes,const size_t size,uint32_t depth)
{
uint32_t i = 0 ;
while ( i < size-3 && bytes[i] != 0x1c ) i++;
...
The following modification allows the "crashing tiff" (2018-01-09-exiv2-crash-002.tiff) to work:
void IptcData::printStructure(std::ostream& out, const byte* bytes,const size_t size,uint32_t depth)
{
size_t i = 0 ;
while ( (i+5) < size && bytes[i] != 0x1c ) i++;
if ( (i+5) >= size ) return;
...
I will revisit the IPTC spec to remind myself about the data format of an IPTC buffer and how it is terminated.
@kbabiochSUSE There is a secondary issue (as you've observed) with Exiv2::Internal::binaryToString(). By "secondary", I mean this not the principle reason for the crash in this bug report and my work-around ensures that binaryToString() isn't called.
However, you have made a valid observation that binaryToString() can cause issues and I'll investigate that once I've dealt with IptcData::printStructure().
I think the "secondary" issue is already logged. https://github.com/Exiv2/exiv2/issues/209
The reason that it's "secondary" in this context is because Valgrind failed to detect the "primary" issue of the buffer overrun in Exiv2::IptcData::printStructure which was detected when clang compiled the code with -fsanitize=address
Is there a patch for this CVE-2017-17724?
@ret2libc #180 will fix this.
@fgeek The reproducer for this is exactly the same as the one for #209. Did you forget to upload a reproducer or am I missing a difference between the two reports?
This got fixed by #461.
http://bugs.fi/media/afl/exiv2/2018-01-09-exiv2-crash-002.tiff 4be065595e4b81e876e32c9c4705f8313f896d43