diff --git a/include/vips/vips.h b/include/vips/vips.h index 1b57da74..e1df633f 100644 --- a/include/vips/vips.h +++ b/include/vips/vips.h @@ -360,10 +360,11 @@ typedef struct im__IMAGE { GSList *preclosefns; /* list of pre-close callbacks */ GSList *invalidatefns; /* list of invalidate callbacks */ - /* Set this to indicate a truncated file. We've been able to read the - * header, but don't try reading outside the file size. + /* Record the file length here. We use this to stop ourselves mapping + * things beyond the end of the file in the case that the file has + * been truncated. */ - int nodata; + size_t file_length; } IMAGE; /* Only define if IM_ENABLE_DEPRECATED is set. diff --git a/libsrc/iofuncs/im_binfile.c b/libsrc/iofuncs/im_binfile.c index 2702f3be..3271342d 100644 --- a/libsrc/iofuncs/im_binfile.c +++ b/libsrc/iofuncs/im_binfile.c @@ -83,7 +83,6 @@ IMAGE * im_binfile( const char *name, int xs, int ys, int bands, int offset ) { IMAGE *im; - gint64 length; gint64 psize; /* Check parameters. @@ -112,14 +111,14 @@ im_binfile( const char *name, int xs, int ys, int bands, int offset ) /* Read the file length and check against what we think * the size should be. */ - if( (length = im_file_length( im->fd )) == -1 ) { + if( (im->file_length = im_file_length( im->fd )) == -1 ) { im_close( im ); return( NULL ); } /* Very common, so special message. */ - if( psize > length ) { + if( psize > im->file_length ) { im_error( "im_binfile", _( "unable to open %s: " "file has been truncated" ), im->filename ); im_close( im ); @@ -129,7 +128,7 @@ im_binfile( const char *name, int xs, int ys, int bands, int offset ) /* Just wierd. Only print a warning for this, since we should * still be able to process it without coredumps. */ - if( psize < length ) + if( psize < im->file_length ) im_warn( "im_binfile", _( "%s is longer than expected" ), im->filename ); diff --git a/libsrc/iofuncs/im_init.c b/libsrc/iofuncs/im_init.c index 75e92951..b181e8d9 100644 --- a/libsrc/iofuncs/im_init.c +++ b/libsrc/iofuncs/im_init.c @@ -32,7 +32,7 @@ * 9/8/08 * - lock global image list (thanks lee) * 19/3/09 - * - add nodata + * - add file_length */ /* @@ -170,7 +170,7 @@ im_init( const char *filename ) im->preclosefns = NULL; im->invalidatefns = NULL; - im->nodata = 0; + im->file_length = 0; if( !(im->filename = im_strdup( NULL, filename )) ) { im_close( im ); diff --git a/libsrc/iofuncs/im_mapfile.c b/libsrc/iofuncs/im_mapfile.c index 889c0ac6..f7bb389a 100644 --- a/libsrc/iofuncs/im_mapfile.c +++ b/libsrc/iofuncs/im_mapfile.c @@ -210,7 +210,6 @@ im__munmap( void *start, size_t length ) int im_mapfile( IMAGE *im ) { - gint64 length; struct stat st; mode_t m; @@ -219,15 +218,14 @@ im_mapfile( IMAGE *im ) /* Check the size of the file; if it is less than 64 bytes, then flag * an error. */ - if( (length = im_file_length( im->fd )) == -1 ) - return( -1 ); + g_assert( im->file_length > 0 ); if( fstat( im->fd, &st ) == -1 ) { im_error( "im_mapfile", "%s", _( "unable to get file status" ) ); return( -1 ); } m = (mode_t) st.st_mode; - if( length < 64 ) { + if( im->file_length < 64 ) { im_error( "im_mapfile", "%s", _( "file is less than 64 bytes" ) ); return( -1 ); @@ -238,13 +236,10 @@ im_mapfile( IMAGE *im ) return( -1 ); } - if( !(im->baseaddr = im__mmap( im->fd, 0, length, 0 )) ) + if( !(im->baseaddr = im__mmap( im->fd, 0, im->file_length, 0 )) ) return( -1 ); - /* im__mmap() will fail for >2GB, so this is safe even for large - * files. - */ - im->length = length; + im->length = im->file_length; return( 0 ); } @@ -254,7 +249,6 @@ im_mapfile( IMAGE *im ) int im_mapfilerw( IMAGE *im ) { - gint64 length; struct stat st; mode_t m; @@ -263,27 +257,23 @@ im_mapfilerw( IMAGE *im ) /* Check the size of the file if it is less than 64 bytes return * make also sure that it is a regular file */ - if( (length = im_file_length( im->fd )) == -1 ) - return( -1 ); + g_assert( im->file_length > 0 ); if( fstat( im->fd, &st ) == -1 ) { im_error( "im_mapfilerw", "%s", _( "unable to get file status" ) ); return( -1 ); } m = (mode_t) st.st_mode; - if( length < 64 || !S_ISREG( m ) ) { + if( im->file_length < 64 || !S_ISREG( m ) ) { im_error( "im_mapfile", "%s", _( "unable to read data" ) ); return( -1 ); } - if( !(im->baseaddr = im__mmap( im->fd, 1, length, 0 )) ) + if( !(im->baseaddr = im__mmap( im->fd, 1, im->file_length, 0 )) ) return( -1 ); - /* im__mmap() will fail for >2GB, so this is safe even for large - * files. - */ - im->length = length; + im->length = im->file_length; return( 0 ); } diff --git a/libsrc/iofuncs/im_open_vips.c b/libsrc/iofuncs/im_open_vips.c index 8ff551a5..075d0fb7 100644 --- a/libsrc/iofuncs/im_open_vips.c +++ b/libsrc/iofuncs/im_open_vips.c @@ -325,14 +325,12 @@ read_chunk( int fd, gint64 offset, size_t length ) int im__has_extension_block( IMAGE *im ) { - gint64 length; gint64 psize; psize = im__image_pixel_length( im ); - if( (length = im_file_length( im->fd )) == -1 ) - return( 0 ); + g_assert( im->file_length > 0 ); - return( length - psize > 0 ); + return( im->file_length - psize > 0 ); } /* Read everything after the pixels into memory. @@ -340,29 +338,27 @@ im__has_extension_block( IMAGE *im ) void * im__read_extension_block( IMAGE *im, int *size ) { - gint64 length; gint64 psize; void *buf; psize = im__image_pixel_length( im ); - if( (length = im_file_length( im->fd )) == -1 ) - return( NULL ); - if( length - psize > 10 * 1024 * 1024 ) { + g_assert( im->file_length > 0 ); + if( im->file_length - psize > 10 * 1024 * 1024 ) { im_error( "im_readhist", "%s", _( "more than a 10 megabytes of XML? " "sufferin' succotash!" ) ); return( NULL ); } - if( length - psize == 0 ) + if( im->file_length - psize == 0 ) return( NULL ); - if( !(buf = read_chunk( im->fd, psize, length - psize )) ) + if( !(buf = read_chunk( im->fd, psize, im->file_length - psize )) ) return( NULL ); if( size ) - *size = length - psize; + *size = im->file_length - psize; #ifdef DEBUG printf( "im__read_extension_block: read %d bytes from %s\n", - (int) (length - psize), im->filename ); + (int) (im->file_length - psize), im->filename ); printf( "data: \"%s\"\n", (char *) buf ); #endif /*DEBUG*/ @@ -896,7 +892,6 @@ im__read_header( IMAGE *image ) */ unsigned char header[IM_SIZEOF_HEADER]; - gint64 length; gint64 psize; image->dtype = IM_OPENIN; @@ -913,13 +908,11 @@ im__read_header( IMAGE *image ) /* Predict and check the file size. */ psize = im__image_pixel_length( image ); - if( (length = im_file_length( image->fd )) == -1 ) + if( (image->file_length = im_file_length( image->fd )) == -1 ) return( -1 ); - if( psize > length ) { + if( psize > image->file_length ) im_warn( "im_openin", _( "unable to read data for \"%s\", %s" ), image->filename, _( "file has been truncated" ) ); - image->nodata = 1; - } /* Set demand style. Allow the most permissive sort. */ @@ -960,9 +953,13 @@ im_openin( IMAGE *image ) if( im__read_header( image ) ) return( -1 ); + /* Make sure we can map the whole thing without running over the VM + * limit or running out of file. + */ size = (gint64) IM_IMAGE_SIZEOF_LINE( image ) * image->Ysize + image->sizeof_header; - if( size < im__mmap_limit && !image->nodata ) { + if( size < im__mmap_limit && + image->file_length >= size ) { if( im_mapfile( image ) ) return( -1 ); image->data = image->baseaddr + image->sizeof_header; diff --git a/libsrc/iofuncs/window.c b/libsrc/iofuncs/window.c index f7eac7b0..eb036774 100644 --- a/libsrc/iofuncs/window.c +++ b/libsrc/iofuncs/window.c @@ -219,15 +219,6 @@ im_window_set( im_window_t *window, int top, int height ) gint64 start, end, pagestart; size_t length, pagelength; - /* Make sure this image has data. - */ - if( window->im->nodata ) { - im_error( "im_window_set", - _( "unable to read data for \"%s\", %s" ), - window->im->filename, _( "file has been truncated" ) ); - return( -1 ); - } - /* Calculate start and length for our window. */ start = window->im->sizeof_header + @@ -238,6 +229,15 @@ im_window_set( im_window_t *window, int top, int height ) end = start + length; pagelength = end - pagestart; + /* Make sure we have enough file. + */ + if( end > window->im->file_length ) { + im_error( "im_window_set", + _( "unable to read data for \"%s\", %s" ), + window->im->filename, _( "file has been truncated" ) ); + return( -1 ); + } + if( !(baseaddr = im__mmap( window->im->fd, 0, pagelength, pagestart )) ) return( -1 );