jasper-software / jasper

Official Repository for the JasPer Image Coding Toolkit
http://www.ece.uvic.ca/~mdadams/jasper
Other
223 stars 101 forks source link

Memory allocate failure in jas_malloc (jas_malloc.c) #35

Closed asarubbo closed 7 years ago

asarubbo commented 7 years ago

I get a memory allocate failure on 1.900.5

Stacktrace:

# imginfo -f $FILE
THE BMP FORMAT IS NOT FULLY SUPPORTED!                                                                                                                                                                                                                                         
THAT IS, THE JASPER SOFTWARE CANNOT DECODE ALL TYPES OF BMP DATA.                                                                                                                                                                                                              
IF YOU HAVE ANY PROBLEMS, PLEASE TRY CONVERTING YOUR IMAGE DATA                                                                                                                                                                                                                
TO THE PNM FORMAT, AND USING THIS FORMAT INSTEAD.                                                                                                                                                                                                                              
==18943==ERROR: AddressSanitizer failed to allocate 0x1000002000 (68719484928) bytes of LargeMmapAllocator (error code: 12)                                                                                                                                                    
==18943==Process memory map follows:                                                                                                                                                                                                                                           
        0x000000400000-0x000000520000   /usr/bin/imginfo                                                                                                                                                                                                                       
        0x00000071f000-0x000000720000   /usr/bin/imginfo                                                                                                                                                                                                                       
        0x000000720000-0x000000724000   /usr/bin/imginfo                                                                                                                                                                                                                       
        0x000000724000-0x0000013a6000                                                                                                                                                                                                                                          
        0x00007fff7000-0x00008fff7000                                                                                                                                                                                                                                          
        0x00008fff7000-0x02008fff7000                                                                                                                                                                                                                                          
        0x02008fff7000-0x10007fff8000                                                                                                                                                                                                                                          
        0x600000000000-0x602000000000                                                                                                                                                                                                                                          
        0x602000000000-0x602000010000                                                                                                                                                                                                                                          
        0x602000010000-0x603000000000                                                                                                                                                                                                                                          
        0x603000000000-0x603000010000                                                                                                                                                                                                                                          
        0x603000010000-0x604000000000                                                                                                                                                                                                                                          
        0x604000000000-0x604000010000                                                                                                                                                                                                                                          
        0x604000010000-0x606000000000                                                                                                                                                                                                                                          
        0x606000000000-0x606000010000                                                                                                                                                                                                                                          
        0x606000010000-0x60b000000000                                                                                                                                                                                                                                          
        0x60b000000000-0x60b000010000                                                                                                                                                                                                                                          
        0x60b000010000-0x619000000000                                                                                                                                                                                                                                          
        0x619000000000-0x619000020000                                                                                                                                                                                                                                          
        0x619000020000-0x625000000000                                                                                                                                                                                                                                          
        0x625000000000-0x625000020000                                                                                                                                                                                                                                          
        0x625000020000-0x640000000000                                                                                                                                                                                                                                          
        0x640000000000-0x640000003000                                                                                                                                                                                                                                          
        0x7f4f00738000-0x7f4f03593000                                                                                                                                                                                                                                          
        0x7f4f03593000-0x7f4f035fc000   /usr/lib64/libjpeg.so.62.2.0                                                                                                                                                                                                           
        0x7f4f035fc000-0x7f4f037fb000   /usr/lib64/libjpeg.so.62.2.0                                                                                                                                                                                                           
        0x7f4f037fb000-0x7f4f037fc000   /usr/lib64/libjpeg.so.62.2.0                                                                                                                                                                                                           
        0x7f4f037fc000-0x7f4f037fd000   /usr/lib64/libjpeg.so.62.2.0                                                                                                                                                                                                           
        0x7f4f037fd000-0x7f4f03990000   /lib64/libc-2.22.so                                                                                                                                                                                                                    
        0x7f4f03990000-0x7f4f03b90000   /lib64/libc-2.22.so                                                                                                                                                                                                                    
        0x7f4f03b90000-0x7f4f03b94000   /lib64/libc-2.22.so                                                                                                                                                                                                                    
        0x7f4f03b94000-0x7f4f03b96000   /lib64/libc-2.22.so                                                                                                                                                                                                                    
        0x7f4f03b96000-0x7f4f03b9a000                                                                                                                                                                                                                                          
        0x7f4f03b9a000-0x7f4f03bb0000   /usr/lib64/gcc/x86_64-pc-linux-gnu/4.9.3/libgcc_s.so.1                                                                                                                                                                                 
        0x7f4f03bb0000-0x7f4f03daf000   /usr/lib64/gcc/x86_64-pc-linux-gnu/4.9.3/libgcc_s.so.1                                                                                                                                                                                 
        0x7f4f03daf000-0x7f4f03db0000   /usr/lib64/gcc/x86_64-pc-linux-gnu/4.9.3/libgcc_s.so.1                                                                                                                                                                                 
        0x7f4f03db0000-0x7f4f03db1000   /usr/lib64/gcc/x86_64-pc-linux-gnu/4.9.3/libgcc_s.so.1                                                                                                                                                                                 
        0x7f4f03db1000-0x7f4f03db3000   /lib64/libdl-2.22.so
        0x7f4f03db3000-0x7f4f03fb3000   /lib64/libdl-2.22.so
        0x7f4f03fb3000-0x7f4f03fb4000   /lib64/libdl-2.22.so
        0x7f4f03fb4000-0x7f4f03fb5000   /lib64/libdl-2.22.so
        0x7f4f03fb5000-0x7f4f03fbb000   /lib64/librt-2.22.so
        0x7f4f03fbb000-0x7f4f041bb000   /lib64/librt-2.22.so
        0x7f4f041bb000-0x7f4f041bc000   /lib64/librt-2.22.so
        0x7f4f041bc000-0x7f4f041bd000   /lib64/librt-2.22.so
        0x7f4f041bd000-0x7f4f041d4000   /lib64/libpthread-2.22.so
        0x7f4f041d4000-0x7f4f043d3000   /lib64/libpthread-2.22.so
        0x7f4f043d3000-0x7f4f043d4000   /lib64/libpthread-2.22.so
        0x7f4f043d4000-0x7f4f043d5000   /lib64/libpthread-2.22.so
        0x7f4f043d5000-0x7f4f043d9000
        0x7f4f043d9000-0x7f4f044d6000   /lib64/libm-2.22.so
        0x7f4f044d6000-0x7f4f046d5000   /lib64/libm-2.22.so
        0x7f4f046d5000-0x7f4f046d6000   /lib64/libm-2.22.so
        0x7f4f046d6000-0x7f4f046d7000   /lib64/libm-2.22.so
        0x7f4f046d7000-0x7f4f04891000   /usr/lib64/libjasper.so.1.0.0
        0x7f4f04891000-0x7f4f04a90000   /usr/lib64/libjasper.so.1.0.0
        0x7f4f04a90000-0x7f4f04a94000   /usr/lib64/libjasper.so.1.0.0
        0x7f4f04a94000-0x7f4f04aa3000   /usr/lib64/libjasper.so.1.0.0
        0x7f4f04aa3000-0x7f4f04aac000
        0x7f4f04aac000-0x7f4f04ace000   /lib64/ld-2.22.so
        0x7f4f04c67000-0x7f4f04cc2000
        0x7f4f04cc2000-0x7f4f04ccd000
        0x7f4f04ccd000-0x7f4f04cce000   /lib64/ld-2.22.so
        0x7f4f04cce000-0x7f4f04ccf000   /lib64/ld-2.22.so
        0x7f4f04ccf000-0x7f4f04cd0000
        0x7ffeaeaca000-0x7ffeaeaeb000   [stack]
        0x7ffeaeb8a000-0x7ffeaeb8c000   [vvar]
        0x7ffeaeb8c000-0x7ffeaeb8e000   [vdso]
        0xffffffffff600000-0xffffffffff601000   [vsyscall]
==18943==End of process memory map.
==18943==AddressSanitizer CHECK failed: /var/tmp/portage/sys-devel/llvm-3.8.1-r2/work/llvm-3.8.1.src/projects/compiler-rt/lib/sanitizer_common/sanitizer_common.cc:183 "((0 && "unable to mmap")) != (0)" (0x0, 0x0)
    #0 0x4c9ccd in AsanCheckFailed /var/tmp/portage/sys-devel/llvm-3.8.1-r2/work/llvm-3.8.1.src/projects/compiler-rt/lib/asan/asan_rtl.cc:67
    #1 0x4d0803 in __sanitizer::CheckFailed(char const*, int, char const*, unsigned long long, unsigned long long) /var/tmp/portage/sys-devel/llvm-3.8.1-r2/work/llvm-3.8.1.src/projects/compiler-rt/lib/sanitizer_common/sanitizer_common.cc:159
    #2 0x4d09f1 in __sanitizer::ReportMmapFailureAndDie(unsigned long, char const*, char const*, int, bool) /var/tmp/portage/sys-devel/llvm-3.8.1-r2/work/llvm-3.8.1.src/projects/compiler-rt/lib/sanitizer_common/sanitizer_common.cc:183
    #3 0x4d9a2a in __sanitizer::MmapOrDie(unsigned long, char const*, bool) /var/tmp/portage/sys-devel/llvm-3.8.1-r2/work/llvm-3.8.1.src/projects/compiler-rt/lib/sanitizer_common/sanitizer_posix.cc:122
    #4 0x421dbf in __sanitizer::LargeMmapAllocator<__asan::AsanMapUnmapCallback>::Allocate(__sanitizer::AllocatorStats*, unsigned long, unsigned long) /var/tmp/portage/sys-devel/llvm-3.8.1-r2/work/llvm-3.8.1.src/projects/compiler-rt/lib/asan/../sanitizer_common/sanitizer_allocator.h:1033
    #5 0x421dbf in __sanitizer::CombinedAllocator<__sanitizer::SizeClassAllocator64<105553116266496ul, 4398046511104ul, 0ul, __sanitizer::SizeClassMap<17ul, 128ul, 16ul>, __asan::AsanMapUnmapCallback>, __sanitizer::SizeClassAllocatorLocalCache<__sanitizer::SizeClassAllocator64<105553116266496ul, 4398046511104ul, 0ul, __sanitizer::SizeClassMap<17ul, 128ul, 16ul>, __asan::AsanMapUnmapCallback> >, __sanitizer::LargeMmapAllocator<__asan::AsanMapUnmapCallback> >::Allocate(__sanitizer::SizeClassAllocatorLocalCache<__sanitizer::SizeClassAllocator64<105553116266496ul, 4398046511104ul, 0ul, __sanitizer::SizeClassMap<17ul, 128ul, 16ul>, __asan::AsanMapUnmapCallback> >*, unsigned long, unsigned long, bool, bool) /var/tmp/portage/sys-devel/llvm-3.8.1-r2/work/llvm-3.8.1.src/projects/compiler-rt/lib/asan/../sanitizer_common/sanitizer_allocator.h:1302
    #6 0x421dbf in __asan::Allocator::Allocate(unsigned long, unsigned long, __sanitizer::BufferedStackTrace*, __asan::AllocType, bool) /var/tmp/portage/sys-devel/llvm-3.8.1-r2/work/llvm-3.8.1.src/projects/compiler-rt/lib/asan/asan_allocator.cc:368
    #7 0x421dbf in __asan::asan_malloc(unsigned long, __sanitizer::BufferedStackTrace*) /var/tmp/portage/sys-devel/llvm-3.8.1-r2/work/llvm-3.8.1.src/projects/compiler-rt/lib/asan/asan_allocator.cc:718
    #8 0x4c0391 in malloc /var/tmp/portage/sys-devel/llvm-3.8.1-r2/work/llvm-3.8.1.src/projects/compiler-rt/lib/asan/asan_malloc_linux.cc:53
    #9 0x7f4f0474e170 in jas_malloc /tmp/portage/media-libs/jasper-1.900.5/work/jasper-1.900.5/src/libjasper/base/jas_malloc.c:117:9
    #10 0x7f4f0474e170 in jas_alloc2 /tmp/portage/media-libs/jasper-1.900.5/work/jasper-1.900.5/src/libjasper/base/jas_malloc.c:141
    #11 0x7f4f04764b4f in bmp_getinfo /tmp/portage/media-libs/jasper-1.900.5/work/jasper-1.900.5/src/libjasper/bmp/bmp_dec.c:297:25
    #12 0x7f4f04764b4f in bmp_decode /tmp/portage/media-libs/jasper-1.900.5/work/jasper-1.900.5/src/libjasper/bmp/bmp_dec.c:132
    #13 0x7f4f0470ef39 in jas_image_decode /tmp/portage/media-libs/jasper-1.900.5/work/jasper-1.900.5/src/libjasper/base/jas_image.c:380:16
    #14 0x4f1686 in main /tmp/portage/media-libs/jasper-1.900.5/work/jasper-1.900.5/src/appl/imginfo.c:188:16
    #15 0x7f4f0381d61f in __libc_start_main /var/tmp/portage/sys-libs/glibc-2.22-r4/work/glibc-2.22/csu/libc-start.c:289
    #16 0x418e68 in _init (/usr/bin/imginfo+0x418e68)

Testcase: 2.crashes.zip

mdadams commented 7 years ago

This is not a bug. The BMP file claims to use palette with a few billion colors. This requires a large memory allocation (on the order of 64 GB), which fails. ASAN is just saying that we are out of memory.

asarubbo commented 7 years ago

Afaik this is a bug. Issues like this received a CVE because it is a memory consumption.

mdadams commented 7 years ago

The issue s this: To the best of my knowledge, ASAN always generates a warning/error if one requests a huge amount of memory that cannot be succesfully allocated. This is certainly the case on my machine. For example, the following completely correct code will generate an ASAN failure on my machine, due to the malloc failing as a result of insufficient memory:

include

include

include

int main() { char *p;

if (!(p = malloc(SIZE_MAX))) {
    printf("failed\n");
    exit(1);
}
free(p);

}

Clearly, it is not the fault of the program that there is insufficient memory available to satisfy the malloc request. That is, there is no bug in this program. Similarly, there is no bug in jasper. You are giving jasper a corrupt JPEG file. In order to process this file, jasper needs to correctly allocate a huge amount of memory (which is assumed to be needed later) to handle the massive palette in the JPEG file. This malloc fails and jasper terminates gracefully due to being out of memory. At least, this is the case on my machine. From the output that you provided, it seems that the same thing is happening on your machine as well. So, unless you have some evidence to the contrary, I do not see any bug here.

asarubbo commented 7 years ago

See https://cwe.mitre.org/data/definitions/789.html

mdadams commented 7 years ago

I am sorry but I meant "BMP file" not "JPEG" file above, as the test file was in BMP (not JPEG) format.

@asarubbo: The practical problem is that there is no good way to fix this problem without imposing arbitrary restrictions that would prevent certain legitimate uses of jasper on certain platforms. The above URL is basically saying that code should never allow someone to allocate too much memory. But "too much memory" is subjective. Where do I draw the line? JasPer is used on a very wide range of hardware (from small embedded systems to large supercomputers). Therefore, there is no good choice of a maximum memory allocation threshold. I could artificially impose arbitrary restrictions on the size of palettes and many other things, but this would easily preclude some legitimate uses of the code. Furthermore, if using too much memory is a genuine concern, there are much bigger fish to fry than this particular BMP issue. If someone really wants to impose memory usage restrictions, it is easy to do (e.g., modify malloc or jas_malloc, or use resource limits in the OS, etc.). It's just that I don't want to ram my own personal memory-usage policy choice (which would inevitably be a bad choice for some users) down the throat of every user. Does this make sense?

As best I can tell, the large memory request is not due to an overflow. It is due to a large amount of memory being necessary to do the job. If I am mistaken, and the large request should not be large (and is only large due to overflow), please let me know because in this case there is a bug that needs fixing.

asarubbo commented 7 years ago

While you are opening the image with the imginfo binary, if it goes out of memory, it is just an inconvenience. While there is an application which relies on jasper to parse some images, then there will be a Denial of Service.

So usually, people may not consider these type of bugs security relevant, but I never seen similar cases not considered as a bug.

However is not normal at all that jasper needs more that 64GB of ram to parse an image of 50 byte.

asarubbo commented 7 years ago

The solution for me is do more checks before allocate the memory.

mdadams commented 7 years ago

What should the check be? It must work for all possible file formats that JasPer supports now and might support in the future. Since compression can be extremely high in some special cases, you cannot assume that a small coded image file must always require only a small amount of memory to decode. Also, the approach must also work well for small embedded systems with only a few MB of memory and for massive machines with TB of memory. For these reasons, I don't think that the checking should be done in the codec themselves, which some of your comments seem to suggest. My point is not that there is no solution. It's just that things need to be thought about more carefully in order to arrive at a solution that works well for ALL users of JasPer.

Please understand that I am not saying that your comments are without any validity. It's just that I do not necessarily agree with the solutions that some of your comments seem to imply. I will give more thought to this matter, but please understand that I consider things like memory corruption and undefined behavior bugs much more serious than this particular issue. Maybe modifying the JasPer memory allocator to track total memory usage and then allowing the library user to set an upper threshold on memory use would address this issue. This is not something that can be handled correctly inside the code for the JPEG2000/JPEG/BMP/etc. codec themselves, however.

Anyways, I have made a note of this issue in my to-do list. Let's just leave it for now.

mdadams commented 7 years ago

As an experimental feature, I have added the ability to limit the total memory usage used by the JasPer library. See commit 65536647d380571d1a9a6c91fa03775fb5bbd256. You can try it out if you like. It is not enabled by default.

To enable this feature, build the code with something like: EXTRA_CFLAGS=-DJAS_DEFAULT_MAX_MEM_USAGE=1000000 ./configure --prefix=/tmp/jasper make clean && make Note: You need C11. Also, you probably don't want to set the detault to only about 1 MB like I did above.

mdadams commented 7 years ago

As an addendum to my previous comment, you can do things like: imginfo --memory-limit 1000000 < data/images/stawamuschief.pnm This overrides the default maximum memory usage set at build time.