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

DOS bug while reading attributes in Header::readfrom #248

Closed
noirfate opened this issue Sep 27, 2017 · 9 comments
Closed

DOS bug while reading attributes in Header::readfrom #248

noirfate opened this issue Sep 27, 2017 · 9 comments
Assignees
Labels
Bug A bug in the source code

Comments

@noirfate
Copy link

noirfate commented Sep 27, 2017

I use ImageMagick to convert exr image, and it report allocate memory failure. After took a look, ImageMagick calls ImfOpenInputFile to open exr file, this function only takes filename as argument, so I think it is a openexr bug.

Version :
ImageMagick-7.0.7-4
openexr-2.2.0
Both are built with ASAN

You can get the POC file from https://github.com/noirfate/test/blob/master/test.exr and
run : magick test.exr 1.png

root@test:~# ~/deps/bin/magick test.exr 1.png
==8518==WARNING: AddressSanitizer failed to allocate 0xffffffffffffffff bytes
==8518==AddressSanitizer's allocator is terminating the process instead of returning 0
==8518==If you don't like this behavior set allocator_may_return_null=1
==8518==AddressSanitizer CHECK failed: /home/snd-local/releases/4.0.1/release/final/llvm.src/projects/compiler-rt/lib/sanitizer_common/sanitizer_allocator.cc:221 "((0)) != (0)" (0x0, 0x0)
    #0 0x4c898f in __asan::AsanCheckFailed(char const*, int, char const*, unsigned long long, unsigned long long) /home/snd-local/releases/4.0.1/release/final/llvm.src/projects/compiler-rt/lib/asan/asan_rtl.cc:69:3
    #1 0x4dc2ef in __sanitizer::CheckFailed(char const*, int, char const*, unsigned long long, unsigned long long) /home/snd-local/releases/4.0.1/release/final/llvm.src/projects/compiler-rt/lib/sanitizer_common/sanitizer_termination.cc:79:5
    #2 0x4cbc2f in __sanitizer::ReportAllocatorCannotReturnNull(bool) /home/snd-local/releases/4.0.1/release/final/llvm.src/projects/compiler-rt/lib/sanitizer_common/sanitizer_allocator.cc:221:3
    #3 0x41bd9f in ReturnNullOrDieOnBadRequest /home/snd-local/releases/4.0.1/release/final/llvm.src/projects/compiler-rt/lib/asan/../sanitizer_common/sanitizer_allocator_combined.h:88:5
    #4 0x41bd9f in __asan::Allocator::Allocate(unsigned long, unsigned long, __sanitizer::BufferedStackTrace*, __asan::AllocType, bool) /home/snd-local/releases/4.0.1/release/final/llvm.src/projects/compiler-rt/lib/asan/asan_allocator.cc:398
    #5 0x4c1090 in __interceptor_malloc /home/snd-local/releases/4.0.1/release/final/llvm.src/projects/compiler-rt/lib/asan/asan_malloc_linux.cc:67:10
    #6 0x7f09bc789e77 in operator new(unsigned long) (/usr/lib/x86_64-linux-gnu/libstdc++.so.6+0x8de77)
    #7 0x7f09bc789f18 in operator new[](unsigned long) (/usr/lib/x86_64-linux-gnu/libstdc++.so.6+0x8df18)
    #8 0x7f09bef9619c in Imf_2_2::Array<char>::resizeErase(long) /root/dep_src/openexr-2.2.0/IlmImf/./ImfArray.h:196:14
    #9 0x7f09bef9619c in Imf_2_2::OpaqueAttribute::readValueFrom(Imf_2_2::IStream&, int, int) /root/dep_src/openexr-2.2.0/IlmImf/ImfOpaqueAttribute.cpp:100
    #10 0x7f09bef730c7 in Imf_2_2::Header::readFrom(Imf_2_2::IStream&, int&) /root/dep_src/openexr-2.2.0/IlmImf/ImfHeader.cpp:1219:9
    #11 0x7f09bf0e9cf6 in Imf_2_2::MultiPartInputFile::initialize() /root/dep_src/openexr-2.2.0/IlmImf/ImfMultiPartInputFile.cpp:316:16
    #12 0x7f09bf0ebe9d in Imf_2_2::MultiPartInputFile::MultiPartInputFile(Imf_2_2::IStream&, int, bool) /root/dep_src/openexr-2.2.0/IlmImf/ImfMultiPartInputFile.cpp:161:9
    #13 0x7f09bef8072c in Imf_2_2::InputFile::compatibilityInitialize(Imf_2_2::IStream&) /root/dep_src/openexr-2.2.0/IlmImf/ImfInputFile.cpp:492:32
    #14 0x7f09bef7f688 in Imf_2_2::InputFile::InputFile(char const*, int) /root/dep_src/openexr-2.2.0/IlmImf/ImfInputFile.cpp:362:13
    #15 0x7f09befb68f0 in Imf_2_2::RgbaInputFile::RgbaInputFile(char const*, int) /root/dep_src/openexr-2.2.0/IlmImf/ImfRgbaFile.cpp:1166:21
    #16 0x7f09bef534b2 in ImfOpenInputFile /root/dep_src/openexr-2.2.0/IlmImf/ImfCRgbaFile.cpp:1170:30
    #17 0x7f09c62105c5 in ReadEXRImage /root/dep_src/ImageMagick-7.0.7-4/coders/exr.c:202:8
    #18 0x7f09c5c1c3d8 in ReadImage /root/dep_src/ImageMagick-7.0.7-4/MagickCore/constitute.c:497:13
    #19 0x7f09c5c1eaa4 in ReadImages /root/dep_src/ImageMagick-7.0.7-4/MagickCore/constitute.c:866:9
    #20 0x7f09c55ddc29 in CLINoImageOperator /root/dep_src/ImageMagick-7.0.7-4/MagickWand/operation.c:4760:22
    #21 0x7f09c55e034c in CLIOption /root/dep_src/ImageMagick-7.0.7-4/MagickWand/operation.c:5255:7
    #22 0x7f09c54da6c7 in ProcessCommandOptions /root/dep_src/ImageMagick-7.0.7-4/MagickWand/magick-cli.c:424:13
    #23 0x7f09c54db530 in MagickImageCommand /root/dep_src/ImageMagick-7.0.7-4/MagickWand/magick-cli.c:794:5
    #24 0x7f09c550dc27 in MagickCommandGenesis /root/dep_src/ImageMagick-7.0.7-4/MagickWand/mogrify.c:183:14
    #25 0x4ee15d in MagickMain /root/dep_src/ImageMagick-7.0.7-4/utilities/magick.c:149:10
    #26 0x4ee15d in main /root/dep_src/ImageMagick-7.0.7-4/utilities/magick.c:180
    #27 0x7f09bca9e82f in __libc_start_main /build/glibc-bfm8X4/glibc-2.23/csu/../csu/libc-start.c:291
    #28 0x41a2c8 in _start (/root/deps/bin/magick+0x41a2c8)

In my debugging, the allocation size is controlled by attacker, so it not only can cause allocation failure and cause huge memory consumption as well.

In the POC file, 0x159~0x15c is the size

0000150: 0000 0013 2401 0000 0000 00cb 8401 0000

And the debug info :

1182            OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (is, size);
1: size = 203 (0xcb)
(gdb) 
1184            AttributeMap::iterator i = _map.find (name);
1: size = -889192448 (0xcb000000)
(gdb) 
1186            if (i != _map.end())
1: size = -889192448
(gdb) 
1212                if (Attribute::knownType (typeName))
1: size = -889192448
(gdb) 
1215                    attr = new OpaqueAttribute (typeName);
1: size = -889192448
(gdb) 
1219                    attr->readValueFrom (is, size, version);
@fgeek
Copy link

fgeek commented Oct 2, 2017

@fgeek
Copy link

fgeek commented Oct 9, 2017

Why are you running binaries as root btw?

@agx
Copy link

agx commented Nov 29, 2017

@noirfate @fgeek I wonder if there is an actual issue here. Array::resizeErase uses new to allocate memory which raises an Exception in case there is not enough memory. These are handled in the calling function.

@fgeek
Copy link

fgeek commented May 6, 2018

@agx That is what that ASan error usually means. I haven't analyzed this and I didn't request that CVE. I just cross-referenced in here from MITRE's database.

@kulikjak
Copy link

I did a little bit of digging and examined this bug/security issue more.

The problem is that size attribute, that is read in can have an arbitrarily big value and library than allocates so much memory that it will eighter drain system resources or crash the program altogether.

size is read at:
lmImf/ImfHeader.cpp:1182
Header::readFrom

OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (is, size);

and later used for new allocation:
IlmImf/ImfArray.h:196

T *tmp = new T[size];

However (if I'm not mistaken), there is no way to know if given size is right or wrong and the attribute has no theoretical limit. The library does correctly throw an exception (std:bad_alloc) when it cannot allocate memory and propagates it all the way to the in this case ImageMagick. There is also no way to exploit this "bug" in some more harmful way. Limiting amount of memory, that programs using this library are using, should be enough to prevent anything bug.

The real problem is in ImageMagick, which does not expect that exception can be thrown in openexr library and therefore dies together with the raised exception.

Please correct me if I'm wrong because I don't know the openexr that much and maybe my assumptions about the size attribute are wrong. However, if it really cannot be determined, then there is in my opinion no way to handle this situation better way.

@pgajdos
Copy link
Contributor

pgajdos commented Nov 8, 2018

Agreed, I think this could be closed as invalid and CVE rejected.

@fgeek
Copy link

fgeek commented Nov 8, 2018

Agreed, I think this could be closed as invalid and CVE rejected.

You can request it using https://cveform.mitre.org/

@cary-ilm cary-ilm added the Bug A bug in the source code label Jun 13, 2019
@cary-ilm cary-ilm added this to the Needs Attention milestone Jun 29, 2019
@cary-ilm cary-ilm self-assigned this Jul 11, 2019
@peterhillman
Copy link
Contributor

I've pushed an update to make an explicit check on the size attribute in this case. This will cause an "Invalid size field in header attribute" exception to be thrown, rather than a "std::badalloc", which should be more informative. It will also prevent address sanitizers treating this as an error.

I believe ImageMagick does handle OpenEXR exceptions correctly as long as an address sanitizer hasn't aborted it first.

@cary-ilm
Copy link
Member

Closing the issue for now, feel free to re-open or file a new issue if necessary.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug A bug in the source code
Projects
None yet
Development

No branches or pull requests

7 participants