-
Notifications
You must be signed in to change notification settings - Fork 50
Heap buffer overflow(read) in _cfImageReadTIFF #116
Copy link
Copy link
Open
Description
Hello! I have found a heap buffer overflow in image-tiff.c
It does not occur in the project itself, but rather is caused by it. Specifically, the line 545
libcupsfilters/cupsfilters/image-tiff.c
Line 545 in a02c490
| TIFFReadScanline(tif, in, row, 0); |
With a specific TIFF file
in is allocated with size img->xsize * 3 + 3 (294 bytes here). Due to the call to TIFFReadScanline() libtiff writes TIFFScanlineSize(tif) (scanwidth, 388 here, which matches width * samples) bytes to in and that overruns in by 94 bytes, which in turn results in a crash in zlib (inflate() -> updatewindow()).
I don't think it is exploitable in any way, so I am writing this to the issues tab, not the security tab.
Output:
TIFFReadDirectoryCheckOrder: Warning, Invalid TIFF directory; tags are not sorted in ascending order.
TIFFReadDirectory: Warning, Incorrect count for "ColorMap"; tag ignored.
TIFFReadDirectory: Warning, Sum of Photometric type-related color channels and ExtraSamples doesn't match SamplesPerPixel. Defining non-color channels as ExtraSamples..
=================================================================
==108589==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x512000000466 at pc 0x6336adcdd9a4 bp 0x7ffe80349220 sp 0x7ffe803489d8
READ of size 388 at 0x512000000466 thread T0
#0 0x6336adcdd9a3 in memcpy (/orig/libcupsfilters/overflow+0xcb9a3) (BuildId: 87fb0c8d052c1d70bc771abaced78e38ad6d0aac)
#1 0x7f33470db9da in updatewindow /orig_zlib/zlib/inflate.c:282:9
#2 0x7f33470db6c5 in inflate /orig_zlib/zlib/inflate.c:1135:13
#3 0x7f3347bf1671 in ZIPDecode /tiff/libtiff/tif_zip.c:259:17
#4 0x7f3347be8588 in TIFFReadScanline /tiff/libtiff/tif_read.c:458:14
#5 0x6336add296d1 in _cfImageReadTIFF /orig/libcupsfilters/cupsfilters/image-tiff.c:545:15
#6 0x6336add20fe6 in cfImageOpenFP /orig/libcupsfilters/cupsfilters/image.c:409:14
#7 0x6336add1eeb1 in main /orig/libcupsfilters/overflow.c:22:5
#8 0x7f33473aa249 in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16
#9 0x7f33473aa304 in __libc_start_main csu/../csu/libc-start.c:360:3
#10 0x6336adc3f700 in _start (/orig/libcupsfilters/overflow+0x2d700) (BuildId: 87fb0c8d052c1d70bc771abaced78e38ad6d0aac)
0x512000000466 is located 0 bytes after 294-byte region [0x512000000340,0x512000000466)
allocated by thread T0 here:
#0 0x6336adcdeb69 in calloc (/orig/libcupsfilters/overflow+0xccb69) (BuildId: 87fb0c8d052c1d70bc771abaced78e38ad6d0aac)
#1 0x6336add28447 in _cfImageReadTIFF /orig/libcupsfilters/cupsfilters/image-tiff.c:367:26
#2 0x6336add20fe6 in cfImageOpenFP /orig/libcupsfilters/cupsfilters/image.c:409:14
#3 0x6336add1eeb1 in main /orig/libcupsfilters/overflow.c:22:5
#4 0x7f33473aa249 in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16
SUMMARY: AddressSanitizer: heap-buffer-overflow (/orig/libcupsfilters/overflow+0xcb9a3) (BuildId: 87fb0c8d052c1d70bc771abaced78e38ad6d0aac) in memcpy
Shadow bytes around the buggy address:
0x512000000180: fa fa fa fa fa fa fa fa 00 00 00 00 00 00 00 00
0x512000000200: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x512000000280: 00 00 00 00 00 00 00 00 00 00 00 00 fa fa fa fa
0x512000000300: fa fa fa fa fa fa fa fa 00 00 00 00 00 00 00 00
0x512000000380: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x512000000400: 00 00 00 00 00 00 00 00 00 00 00 00[06]fa fa fa
0x512000000480: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x512000000500: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x512000000580: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x512000000600: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x512000000680: 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
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
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
==108589==ABORTING
Steps to reproduce:
- Build the project with sanitizers:
export CFLAGS="-g -O0 -fsanitize=address"
export CXXFLAGS="-g -O0 -fsanitize=address"
export CC=clang
export CXX=clang++
autoreconf -fi
./configure --enable-static --disable-silent-rules --with-mutool-path=/usr/bin/mutool --enable-mutool
make- Build the example:
$CC $CFLAGS -O0 -o overflow overflow.c ./.libs/libcupsfilters.a -I./ -lcups -ltiff -ljpeg -lpng -lexif -lm -ldl -ljxloverflow.c:
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <cupsfilters/filter.h>
#include <cupsfilters/raster.h>
#include <cupsfilters/colormanager.h>
#include <cupsfilters/ipp.h>
#include <cupsfilters/image-private.h>
#include <cupsfilters/libcups2-private.h>
extern char *
fparseln(FILE *fp, size_t *size, size_t *lineno, const char str[3], int flags);
int main(int argc, char** argv)
{
if (argc < 2) return 0;
FILE *fp = fopen(argv[1], "r");
if (!fp) return 0;
cfImageOpenFP(fp, CF_IMAGE_BLACK, CF_IMAGE_BLACK, 100, 0, NULL);
return 0;
}- Launch the example with the provided input:
./overflow hbo_inputSuggested workaround:
I don't know if ensuring that in buffer is big enough is the correct approach, so no PR this time.
diff --git a/cupsfilters/image-tiff.c b/cupsfilters/image-tiff.c
index 02aa4b76..49c0fb40 100644
--- a/cupsfilters/image-tiff.c
+++ b/cupsfilters/image-tiff.c
@@ -363,8 +363,11 @@ _cfImageReadTIFF(
pstep = xdir * 3;
else
pstep = xdir;
-
- if ((in = (cf_ib_t*)calloc(img->xsize * 3 + 3, sizeof(cf_ib_t))) == NULL)
+ int inbytes = img->xsize * 3 + 3;
+ if (scanwidth > inbytes)
+ inbytes = scanwidth;
+ in = (cf_ib_t*)calloc(inbytes, sizeof(cf_ib_t));
+ if (in == NULL)
{
DEBUG_puts("DEBUG: No enough memory.\n");
TIFFClose(tif);
@@ -386,8 +389,11 @@ _cfImageReadTIFF(
pstep = ydir * 3;
else
pstep = ydir;
-
- if ((in = (cf_ib_t*)calloc(img->ysize * 3 + 3, sizeof(cf_ib_t))) == NULL)
+ int inbytes = img->ysize * 3 + 3;
+ if (scanwidth > inbytes)
+ inbytes = scanwidth;
+ in = (cf_ib_t*)calloc(inbytes, sizeof(cf_ib_t));
+ if (in == NULL)
{
DEBUG_puts("DEBUG: No enough memory.\n");
TIFFClose(tif);Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels