From 6c4480d2980dc61f3fcd4f43a499e69764133f1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nikola=20Forr=C3=B3?= Date: Wed, 11 Jan 2017 12:50:33 +0100 Subject: [PATCH 1/5] Fix CVE-2016-9533, CVE-2016-9534, CVE-2016-9536, CVE-2016-9537 --- libtiff/tif_pixarlog.c | 55 +++++++++++++++++++++----------------------------- libtiff/tif_write.c | 7 +++++++ tools/thumbnail.c | 7 ++++++- tools/tiff2pdf.c | 22 ++++++++++++++++++-- tools/tiffcrop.c | 31 ++++++++++++++++++++++++---- 5 files changed, 83 insertions(+), 39 deletions(-) diff --git a/libtiff/tif_pixarlog.c b/libtiff/tif_pixarlog.c index c961529..6128f2f 100644 --- a/libtiff/tif_pixarlog.c +++ b/libtiff/tif_pixarlog.c @@ -981,17 +981,14 @@ horizontalDifferenceF(float *ip, int n, int stride, uint16 *wp, uint16 *FromLT2) a1 = (int32) CLAMP(ip[3]); wp[3] = (a1-a2) & mask; a2 = a1; } } else { - ip += n - 1; /* point to last one */ - wp += n - 1; /* point to last one */ - n -= stride; - while (n > 0) { - REPEAT(stride, wp[0] = (uint16) CLAMP(ip[0]); - wp[stride] -= wp[0]; - wp[stride] &= mask; - wp--; ip--) - n -= stride; - } - REPEAT(stride, wp[0] = (uint16) CLAMP(ip[0]); wp--; ip--) + REPEAT(stride, wp[0] = (uint16) CLAMP(ip[0]); wp++; ip++) + n -= stride; + while (n > 0) { + REPEAT(stride, + wp[0] = (uint16)(((int32)CLAMP(ip[0])-(int32)CLAMP(ip[-stride])) & mask); + wp++; ip++) + n -= stride; + } } } } @@ -1034,17 +1031,14 @@ horizontalDifference16(unsigned short *ip, int n, int stride, a1 = CLAMP(ip[3]); wp[3] = (a1-a2) & mask; a2 = a1; } } else { - ip += n - 1; /* point to last one */ - wp += n - 1; /* point to last one */ + REPEAT(stride, wp[0] = CLAMP(ip[0]); wp++; ip++) n -= stride; while (n > 0) { - REPEAT(stride, wp[0] = CLAMP(ip[0]); - wp[stride] -= wp[0]; - wp[stride] &= mask; - wp--; ip--) - n -= stride; - } - REPEAT(stride, wp[0] = CLAMP(ip[0]); wp--; ip--) + REPEAT(stride, + wp[0] = (uint16)((CLAMP(ip[0])-CLAMP(ip[-stride])) & mask); + wp++; ip++) + n -= stride; + } } } } @@ -1087,18 +1081,15 @@ horizontalDifference8(unsigned char *ip, int n, int stride, ip += 4; } } else { - wp += n + stride - 1; /* point to last one */ - ip += n + stride - 1; /* point to last one */ - n -= stride; - while (n > 0) { - REPEAT(stride, wp[0] = CLAMP(ip[0]); - wp[stride] -= wp[0]; - wp[stride] &= mask; - wp--; ip--) - n -= stride; - } - REPEAT(stride, wp[0] = CLAMP(ip[0]); wp--; ip--) - } + REPEAT(stride, wp[0] = CLAMP(ip[0]); wp++; ip++) + n -= stride; + while (n > 0) { + REPEAT(stride, + wp[0] = (uint16)((CLAMP(ip[0])-CLAMP(ip[-stride])) & mask); + wp++; ip++) + n -= stride; + } + } } } diff --git a/libtiff/tif_write.c b/libtiff/tif_write.c index 8792123..ce671af 100644 --- a/libtiff/tif_write.c +++ b/libtiff/tif_write.c @@ -742,7 +742,14 @@ TIFFFlushData1(TIFF* tif) if (!TIFFAppendToStrip(tif, isTiled(tif) ? tif->tif_curtile : tif->tif_curstrip, tif->tif_rawdata, tif->tif_rawcc)) + { + /* We update those variables even in case of error since there's */ + /* code that doesn't really check the return code of this */ + /* function */ + tif->tif_rawcc = 0; + tif->tif_rawcp = tif->tif_rawdata; return (0); + } tif->tif_rawcc = 0; tif->tif_rawcp = tif->tif_rawdata; } diff --git a/tools/thumbnail.c b/tools/thumbnail.c index e14d290..9a9c439 100644 --- a/tools/thumbnail.c +++ b/tools/thumbnail.c @@ -587,12 +587,17 @@ generateThumbnail(TIFF* in, TIFF* out) rowsize = TIFFScanlineSize(in); rastersize = sh * rowsize; fprintf(stderr, "rastersize=%u\n", (unsigned int)rastersize); - raster = (unsigned char*)_TIFFmalloc(rastersize + 3); + /* +3 : add a few guard bytes since setrow() can read a bit */ + /* outside buffer */ + raster = (unsigned char*)_TIFFmalloc(rastersize+3); if (!raster) { TIFFError(TIFFFileName(in), "Can't allocate space for raster buffer."); return 0; } + raster[rastersize] = 0; + raster[rastersize+1] = 0; + raster[rastersize+2] = 0; rp = raster; for (s = 0; s < ns; s++) { (void) TIFFReadEncodedStrip(in, s, rp, -1); diff --git a/tools/tiff2pdf.c b/tools/tiff2pdf.c index 2a64ec3..fbca305 100644 --- a/tools/tiff2pdf.c +++ b/tools/tiff2pdf.c @@ -285,7 +285,7 @@ tsize_t t2p_readwrite_pdf_image_tile(T2P*, TIFF*, TIFF*, ttile_t); int t2p_process_ojpeg_tables(T2P*, TIFF*); #endif #ifdef JPEG_SUPPORT -int t2p_process_jpeg_strip(unsigned char*, tsize_t*, unsigned char*, tsize_t*, tstrip_t, uint32); +int t2p_process_jpeg_strip(unsigned char*, tsize_t*, unsigned char*, tsize_t, tsize_t*, tstrip_t, uint32); #endif void t2p_tile_collapse_left(tdata_t, tsize_t, uint32, uint32, uint32); void t2p_write_advance_directory(T2P*, TIFF*); @@ -2348,7 +2348,8 @@ tsize_t t2p_readwrite_pdf_image(T2P* t2p, TIFF* input, TIFF* output){ if(!t2p_process_jpeg_strip( stripbuffer, &striplength, - buffer, + buffer, + t2p->tiff_datasize, &bufferoffset, i, t2p->tiff_length)){ @@ -3378,6 +3379,7 @@ int t2p_process_jpeg_strip( unsigned char* strip, tsize_t* striplength, unsigned char* buffer, + tsize_t buffersize, tsize_t* bufferoffset, tstrip_t no, uint32 height){ @@ -3412,6 +3414,8 @@ int t2p_process_jpeg_strip( } switch( strip[i] ){ case 0xd8: /* SOI - start of image */ + if( *bufferoffset + 2 > buffersize ) + return(0); _TIFFmemcpy(&(buffer[*bufferoffset]), &(strip[i-1]), 2); *bufferoffset+=2; break; @@ -3421,12 +3425,18 @@ int t2p_process_jpeg_strip( case 0xc9: /* SOF9 */ case 0xca: /* SOF10 */ if(no==0){ + if( *bufferoffset + datalen + 2 + 6 > buffersize ) + return(0); _TIFFmemcpy(&(buffer[*bufferoffset]), &(strip[i-1]), datalen+2); + if( *bufferoffset + 9 >= buffersize ) + return(0); ncomp = buffer[*bufferoffset+9]; if (ncomp < 1 || ncomp > 4) return(0); v_samp=1; h_samp=1; + if( *bufferoffset + 11 + 3*(ncomp-1) >= buffersize ) + return(0); for(j=0;j>4) > h_samp) @@ -3458,20 +3468,28 @@ int t2p_process_jpeg_strip( break; case 0xc4: /* DHT */ case 0xdb: /* DQT */ + if( *bufferoffset + datalen + 2 > buffersize ) + return(0); _TIFFmemcpy(&(buffer[*bufferoffset]), &(strip[i-1]), datalen+2); *bufferoffset+=datalen+2; break; case 0xda: /* SOS */ if(no==0){ + if( *bufferoffset + datalen + 2 > buffersize ) + return(0); _TIFFmemcpy(&(buffer[*bufferoffset]), &(strip[i-1]), datalen+2); *bufferoffset+=datalen+2; } else { + if( *bufferoffset + 2 > buffersize ) + return(0); buffer[(*bufferoffset)++]=0xff; buffer[(*bufferoffset)++]= (unsigned char)(0xd0 | ((no-1)%8)); } i += datalen + 1; /* copy remainder of strip */ + if( *bufferoffset + *striplength - i > buffersize ) + return(0); _TIFFmemcpy(&(buffer[*bufferoffset]), &(strip[i]), *striplength - i); *bufferoffset+= *striplength - i; return(1); diff --git a/tools/tiffcrop.c b/tools/tiffcrop.c index f04e2eb..02c53cd 100644 --- a/tools/tiffcrop.c +++ b/tools/tiffcrop.c @@ -5744,7 +5744,8 @@ loadImage(TIFF* in, struct image_data *image, struct dump_opts *dump, unsigned c { uint32 i; float xres = 0.0, yres = 0.0; - uint16 nstrips = 0, ntiles = 0, planar = 0; + uint32 nstrips = 0, ntiles = 0; + uint16 planar = 0; uint16 bps = 0, spp = 0, res_unit = 0; uint16 orientation = 0; uint16 input_compression = 0, input_photometric = 0; @@ -6049,17 +6050,31 @@ loadImage(TIFF* in, struct image_data *image, struct dump_opts *dump, unsigned c } read_buff = *read_ptr; + /* +3 : add a few guard bytes since reverseSamples16bits() can read a bit */ + /* outside buffer */ if (!read_buff) - read_buff = (unsigned char *)_TIFFmalloc(buffsize); + { + if( buffsize > 0xFFFFFFFFU - 3 ) + { + TIFFError("loadImage", "Unable to allocate/reallocate read buffer"); + return (-1); + } + read_buff = (unsigned char *)_TIFFmalloc(buffsize+3); + } else { if (prev_readsize < buffsize) + { + if( buffsize > 0xFFFFFFFFU - 3 ) { - new_buff = _TIFFrealloc(read_buff, buffsize); + TIFFError("loadImage", "Unable to allocate/reallocate read buffer"); + return (-1); + } + new_buff = _TIFFrealloc(read_buff, buffsize+3); if (!new_buff) { free (read_buff); - read_buff = (unsigned char *)_TIFFmalloc(buffsize); + read_buff = (unsigned char *)_TIFFmalloc(buffsize+3); } else read_buff = new_buff; @@ -6071,6 +6086,9 @@ loadImage(TIFF* in, struct image_data *image, struct dump_opts *dump, unsigned c TIFFError("loadImage", "Unable to allocate/reallocate read buffer"); return (-1); } + read_buff[buffsize] = 0; + read_buff[buffsize+1] = 0; + read_buff[buffsize+2] = 0; prev_readsize = buffsize; *read_ptr = read_buff; @@ -8877,6 +8895,11 @@ reverseSamplesBytes (uint16 spp, uint16 bps, uint32 width, } bytes_per_pixel = ((bps * spp) + 7) / 8; + if( bytes_per_pixel > sizeof(swapbuff) ) + { + TIFFError("reverseSamplesBytes","bytes_per_pixel too large"); + return (1); + } switch (bps / 8) { case 8: /* Use memcpy for multiple bytes per sample data */ -- 2.7.4