Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SIGABRT in types.cpp Exiv2::DataBuf::alloc function #302

Closed
legend-issue opened this issue May 9, 2018 · 7 comments
Closed

SIGABRT in types.cpp Exiv2::DataBuf::alloc function #302

legend-issue opened this issue May 9, 2018 · 7 comments
Milestone

Comments

@legend-issue
Copy link

legend-issue commented May 9, 2018

$rax   : 0x0000000000000000
$rbx   : 0x00007fffffffd360    0x0000000000000000
$rcx   : 0x0000000000ec0fed    0x6e69676522000001
$rdx   : 0x00007fffffffd360    0x0000000000000000
$rsp   : 0x00007fffffffd200    0x0000000000000000
$rbp   : 0x00000000ffffffea
$rsi   : 0x00000000ffffffea
$rdi   : 0x0000000000000000
$rip   : 0x00000000007685c7    <Exiv2::DataBuf::alloc(long)+279> mov rdi, rbp
$r8    : 0xffffffffffffe310
$r9    : 0xffffffffffffe300
$r10   : 0xffffffffffffe2f0
$r11   : 0x000000000000047a
$r12   : 0x0000000000ec146b    0xbcaea80000000000
$r13   : 0x000000000000001c
$r14   : 0x0000000000000000
$r15   : 0x0000000000000000
$eflags: [carry PARITY adjust ZERO sign trap INTERRUPT direction overflow resume virtualx86 identification]
$es: 0x0000  $gs: 0x0000  $ds: 0x0000  $ss: 0x002b  $fs: 0x0000  $cs: 0x0033  
───────────────────────────────────────────────────────────────────[ stack ]────
0x00007fffffffd200+0x00: 0x0000000000000000	  $rsp
0x00007fffffffd208+0x08: 0x00007fffffffd360    0x0000000000000000
0x00007fffffffd210+0x10: 0x00000000fffffff5
0x00007fffffffd218+0x18: 0x0000000000813738    <Exiv2::Internal::PngChunk::zlibUncompress(unsigned+0> mov rdi, QWORD PTR [rbx]
0x00007fffffffd220+0x20: 0x00000000ffffffea
0x00007fffffffd228+0x28: 0xa65c0e3e1fcb3000
0x00007fffffffd230+0x30: 0x0000000000ec0fd0    0x2e6d6f633a4c4d58
0x00007fffffffd238+0x38: 0x00007fffffffd360    0x0000000000000000
────────────────────────────────────────────────────────[ code:i386:x86-64 ]────
     0x7685b0 <Exiv2::DataBuf::alloc(long)+256> lea    rsp, [rsp+0x98]
     0x7685b8 <Exiv2::DataBuf::alloc(long)+264> mov    QWORD PTR [rbx], 0x0
     0x7685bf <Exiv2::DataBuf::alloc(long)+271> mov    QWORD PTR [rbx+0x8], 0x0
    0x7685c7 <Exiv2::DataBuf::alloc(long)+279> mov    rdi, rbp
     0x7685ca <Exiv2::DataBuf::alloc(long)+282> call   0x405ac0 <_Znam@plt>
     0x7685cf <Exiv2::DataBuf::alloc(long)+287> mov    QWORD PTR [rbx+0x8], rbp
     0x7685d3 <Exiv2::DataBuf::alloc(long)+291> mov    QWORD PTR [rbx], rax
     0x7685d6 <Exiv2::DataBuf::alloc(long)+294> add    rsp, 0x8
     0x7685da <Exiv2::DataBuf::alloc(long)+298> pop    rbx
────────────────────────────────────────────────────[ source:types.cpp+153 ]────
    148	     {
    149	         if (size > size_) {
    150	             delete[] pData_;
    151	             pData_ = 0;
    152	             size_ = 0;
		// size=0xffffffea
   153	             pData_ = new byte[size];
    154	             size_ = size;
    155	         }
    156	     }
    157	 
    158	     std::pair<byte*, long> DataBuf::release()
─────────────────────────────────────────────────────────────────[ threads ]────
[#0] Id 1, Name: "exiv2", stopped, reason: SINGLE STEP
───────────────────────────────────────────────────────────────────[ trace ]────
[#0] 0x7685c7  Name: Exiv2::DataBuf::alloc(this=0x7fffffffd360, size=0xffffffea)
[#1] 0x813738  Name: Exiv2::Internal::PngChunk::zlibUncompress(compressedText=0xec146b "", compressedTextSize=0xfffffff5, arr=@0x7fffffffd360)
[#2] 0x814330 → Name: Exiv2::Internal::PngChunk::parseTXTChunk(data=@0x7fffffffd3f0, keysize=0x1c, type=Exiv2::Internal::PngChunk::iTXt_Chunk)
[#3] 0x8153fe → Name: Exiv2::Internal::PngChunk::decodeTXTChunk(pImage=0xec0a90, data=@0x7fffffffd3f0, type=Exiv2::Internal::PngChunk::iTXt_Chunk)
[#4] 0x804342 → Name: Exiv2::PngImage::readMetadata(this=0xec0a90)
[#5] 0x480362 → Name: Action::Print::printSummary(this=0xec1c10)
[#6] 0x486d68 → Name: Action::Print::run(this=0xec1c10, path="id:000004,sig:06,src:000036,op:havoc,rep:128")
[#7] 0x40772d → Name: main(argc=0x2, argv=0x7fffffffdf38)
[#8] 0x7fffbe826830 → Name: __libc_start_main(main=0x4073d0 <main(int, char* const*)>, argc=0x2, argv=0x7fffffffdf38, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fffffffdf28)
[#9] 0x4277c9 → Name: _start()
────────────────────────────────────────────────────────────────────────────────
gef➤  
terminate called after throwing an instance of 'std::bad_alloc'
  what():  std::bad_alloc

Program received signal SIGABRT, Aborted.

I find this when I set ‘ulimit -v 1048576(1G)’.
The command is "exiv2 -et [poc]"
https://github.com/legend-issue/pocs/blob/master/exiv2/id:000004%2Csig:06%2Csrc:000036%2Cop:havoc%2Crep:128

@kbabioch
Copy link

The reproducer is not accessible, could you make it downloadable please?

@legend-issue
Copy link
Author

legend-issue commented May 14, 2018

I think it's OK now!

@fgeek
Copy link

fgeek commented May 15, 2018

Reproducer SHA1: e43c1eb7134d2fc4c5548253477fd09d6b2fac79
In bb20191 with ASan:

=================================================================
==11430==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x61a00001f710 at pc 0x7f1599a44063 bp 0x7fff2e000d70 sp 0x7fff2e000520
READ of size 1137 at 0x61a00001f710 thread T0
    #0 0x7f1599a44062  (/usr/lib/x86_64-linux-gnu/libasan.so.3+0x3c062)
    #1 0x7f1598e71aec in std::char_traits<char>::length(char const*) /usr/include/c++/6/bits/char_traits.h:267
    #2 0x7f1598e71aec in std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(char const*, std::allocator<char> const&) /usr/include/c++/6/bits/basic_string.h:456
    #3 0x7f1598e71aec in Exiv2::Internal::PngChunk::parseTXTChunk(Exiv2::DataBuf const&, int, Exiv2::Internal::PngChunk::TxtChunkType) /home/hsalo/src/exiv2/src/pngchunk_int.cpp:175
    #4 0x7f1598e72b54 in Exiv2::Internal::PngChunk::decodeTXTChunk(Exiv2::Image*, Exiv2::DataBuf const&, Exiv2::Internal::PngChunk::TxtChunkType) /home/hsalo/src/exiv2/src/pngchunk_int.cpp:81
    #5 0x7f1598e5fdc3 in Exiv2::PngImage::readMetadata() /home/hsalo/src/exiv2/src/pngimage.cpp:461
    #6 0x562ef0f1fc07 in Action::Extract::writeThumbnail() const /home/hsalo/src/exiv2/src/actions.cpp:1119
    #7 0x562ef0f3c8df in Action::Extract::run(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) /home/hsalo/src/exiv2/src/actions.cpp:1077
    #8 0x562ef0ec12b8 in main /home/hsalo/src/exiv2/src/exiv2.cpp:166
    #9 0x7f1597afc2e0 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x202e0)
    #10 0x562ef0ec20d9 in _start (/home/hsalo/builds/exiv2/bb2019149ae2b6f226e8d6be5f5828898b455a03/bin/exiv2+0x130d9)

0x61a00001f710 is located 0 bytes to the right of 1168-byte region [0x61a00001f280,0x61a00001f710)
allocated by thread T0 here:
    #0 0x7f1599acad70 in operator new[](unsigned long) (/usr/lib/x86_64-linux-gnu/libasan.so.3+0xc2d70)
    #1 0x7f1598e5f3d7 in Exiv2::DataBuf::DataBuf(long) ../include/exiv2/types.hpp:206
    #2 0x7f1598e5f3d7 in Exiv2::PngImage::readMetadata() /home/hsalo/src/exiv2/src/pngimage.cpp:420
    #3 0x562ef0f1fc07 in Action::Extract::writeThumbnail() const /home/hsalo/src/exiv2/src/actions.cpp:1119
    #4 0x562ef0f3c8df in Action::Extract::run(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) /home/hsalo/src/exiv2/src/actions.cpp:1077
    #5 0x562ef0ec12b8 in main /home/hsalo/src/exiv2/src/exiv2.cpp:166
    #6 0x7f1597afc2e0 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x202e0)

SUMMARY: AddressSanitizer: heap-buffer-overflow (/usr/lib/x86_64-linux-gnu/libasan.so.3+0x3c062)
Shadow bytes around the buggy address:
  0x0c347fffbe90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c347fffbea0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c347fffbeb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c347fffbec0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c347fffbed0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0c347fffbee0: 00 00[fa]fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c347fffbef0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c347fffbf00: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c347fffbf10: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c347fffbf20: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c347fffbf30: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07
  Heap left redzone:       fa
  Heap right redzone:      fb
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack partial redzone:   f4
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
==11430==ABORTING

Minimized sample (SHA1: 878078e9db9a8bdb875297d1d1131037dc996e8b) exiv2-issue-302.png.zip with afl-tmin:

File size reduced by : 98.72% (to 1125 bytes)
Characters simplified : 7757.60%
Number of execs done : 828
Fruitless execs : path=637 crash=0 hang=0

@piponazo
Copy link
Collaborator

This issue was also solved by #316

@rcsanchez97
Copy link
Contributor

rcsanchez97 commented Jun 26, 2018

@piponazo I am trying to backport the fix for CVE-2018-10958/CVE-2018-10999 to older versions of exiv2 in Debian (0.25, 0.24, and 0.23). I have prepared two patches based on commits 2fb00c8 and 3ad0050. In particular, I tried to avoid introducing the new enforce mechanism and instead tried to accomplish the same effect with if statements. I would appreciate it if you could review my work and provide any feedback on any adjustments that I might need to make.

Patch 1:

--- exiv2.git.orig/src/pngchunk.cpp
+++ exiv2.git/src/pngchunk.cpp
@@ -60,6 +60,7 @@
 #include <iostream>
 #include <cassert>
 #include <cstdio>
+#include <algorithm>
 
 /*
 
@@ -166,6 +167,9 @@
         }
         else if(type == iTXt_Chunk)
         {
+            const int nullSeparators = std::count(&data.pData_[keysize+3], &data.pData_[data.size_-1], '\0');
+            if (nullSeparators < 2) throw Error(58);
+
             // Extract a deflate compressed or uncompressed UTF-8 text chunk
 
             // we get the compression flag after the key
--- exiv2.git.orig/src/error.cpp
+++ exiv2.git/src/error.cpp
@@ -105,7 +105,8 @@
         { 49, N_("TIFF directory %1 has too many entries") }, // %1=TIFF directory name
         { 50, N_("Multiple TIFF array element tags %1 in one directory") }, // %1=tag number
         { 51, N_("TIFF array element tag %1 has wrong type") }, // %1=tag number
-        { 52, N_("%1 has invalid XMP value type `%2'") } // %1=key, %2=value type
+        { 52, N_("%1 has invalid XMP value type `%2'") }, // %1=key, %2=value type
+        { 58, N_("corrupted image metadata") }
     };
 
 }

Patch 2:

--- exiv2.git.orig/src/pngchunk.cpp
+++ exiv2.git/src/pngchunk.cpp
@@ -168,14 +168,24 @@
         else if(type == iTXt_Chunk)
         {
             const int nullSeparators = std::count(&data.pData_[keysize+3], &data.pData_[data.size_-1], '\0');
-            if (nullSeparators < 2) throw Error(58);
+            if (nullSeparators < 2) throw Error(58, "iTXt chunk: not enough null separators");
 
             // Extract a deflate compressed or uncompressed UTF-8 text chunk
 
             // we get the compression flag after the key
-            const byte* compressionFlag   = data.pData_ + keysize + 1;
+            const byte compressionFlag   = data.pData_[keysize + 1];
             // we get the compression method after the compression flag
-            const byte* compressionMethod = data.pData_ + keysize + 2;
+            const byte compressionMethod = data.pData_[keysize + 2];
+
+            if (compressionFlag != 0x00 && compressionFlag != 0x01)
+            {
+                    throw Error(58, "iTXt chunk: not valid value in compressionFlag");
+            }
+            if (compressionMethod != 0x00)
+            {
+                    throw Error(58, "iTXt chunk: not valid value in compressionMethod");
+            }
+
             // language description string after the compression technique spec
             std::string languageText((const char*)(data.pData_ + keysize + 3));
             unsigned int languageTextSize = static_cast<unsigned int>(languageText.size());
@@ -183,7 +193,7 @@
             std::string translatedKeyText((const char*)(data.pData_ + keysize + 3 + languageTextSize +1));
             unsigned int translatedKeyTextSize = static_cast<unsigned int>(translatedKeyText.size());

-            if ( compressionFlag[0] == 0x00 )
+            if ( compressionFlag == 0x00 )
             {
                 // then it's an uncompressed iTXt chunk
 #ifdef DEBUG
@@ -197,7 +207,7 @@
                 arr.alloc(textsize);
                 arr = DataBuf(text, textsize);
             }
-            else if ( compressionFlag[0] == 0x01 && compressionMethod[0] == 0x00 )
+            else if ( compressionFlag == 0x01 && compressionMethod == 0x00 )
             {
                 // then it's a zlib compressed iTXt chunk
 #ifdef DEBUG

@D4N
Copy link
Member

D4N commented Jul 28, 2018

@rcsanchez97 Sorry for not getting back to you earlier, but your first patch has a small issue, instead of:

+            const int nullSeparators = std::count(&data.pData_[keysize+3], &data.pData_[data.size_-1], '\0');

it should be:

+            const int nullSeparators = std::count(&data.pData_[keysize+3], &data.pData_[data.size_], '\0');

(the -1 was wrong, see the discussion of the associated pull request).

The rest looks good to me. You can drop the strings from the throws in the second patch where you throw an error 58, as the string will be ignored in the exception message anyway.

However, please test that your patches fix the issue by running exiv2 with asan.

@piponazo
Copy link
Collaborator

Hi @rcsanchez97 . I am also sorry for not replying before. I double checked the changes and the only issue I see is what @D4N pointed out already.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants