add "unlimited" to jpegload

To disable DoS limits for JPEG loading. Adding API on a stable branch is
bad, but this fixes a regression, so I think it's necessary,
unfortunately.

See https://github.com/libvips/libvips/issues/2973
This commit is contained in:
John Cupitt 2022-08-02 13:50:09 +01:00
parent a6fa62605c
commit 2c4c039056
8 changed files with 44 additions and 22 deletions

1
.gitignore vendored
View File

@ -154,6 +154,7 @@ tmp-*
# Auto-generated tag files # Auto-generated tag files
tags tags
TAGS
### End of VIM ### End of VIM
### Distribution ### Distribution

View File

@ -2,6 +2,7 @@
- fix im7 feature detection in meson - fix im7 feature detection in meson
- add a summary table at the end of configure in meson - add a summary table at the end of configure in meson
- fix libpng fallback when spng is disabled in meson - fix libpng fallback when spng is disabled in meson
- add "unlimited" to jpegload
21/11/21 started 8.13 21/11/21 started 8.13
- configure fails for requested but unmet dependencies [remicollet] - configure fails for requested but unmet dependencies [remicollet]

View File

@ -117,7 +117,7 @@ jpeg2vips( const char *name, IMAGE *out, gboolean header_only )
if( !(source = vips_source_new_from_file( filename )) ) if( !(source = vips_source_new_from_file( filename )) )
return( -1 ); return( -1 );
if( vips__jpeg_read_source( source, out, if( vips__jpeg_read_source( source, out,
header_only, shrink, fail_on_warn, FALSE ) ) { header_only, shrink, fail_on_warn, FALSE, FALSE ) ) {
VIPS_UNREF( source ); VIPS_UNREF( source );
return( -1 ); return( -1 );
} }

View File

@ -112,6 +112,8 @@
* - set resolution unit from JFIF * - set resolution unit from JFIF
* 24/7/21 * 24/7/21
* - add fail_on support * - add fail_on support
* 2/8/22
* - add "unlimited"
*/ */
/* /*
@ -169,6 +171,8 @@
/* Stuff we track during a read. /* Stuff we track during a read.
*/ */
typedef struct _ReadJpeg { typedef struct _ReadJpeg {
VipsImage *out;
/* Shrink by this much during load. 1, 2, 4, 8. /* Shrink by this much during load. 1, 2, 4, 8.
*/ */
int shrink; int shrink;
@ -190,6 +194,10 @@ typedef struct _ReadJpeg {
*/ */
gboolean autorotate; gboolean autorotate;
/* Remove DoS limits.
*/
gboolean unlimited;
/* cinfo->output_width and height can be larger than we want since /* cinfo->output_width and height can be larger than we want since
* libjpeg rounds up on shrink-on-load. This is the real size we will * libjpeg rounds up on shrink-on-load. This is the real size we will
* output, as opposed to the size we decompress to. * output, as opposed to the size we decompress to.
@ -251,8 +259,12 @@ source_fill_input_buffer( j_decompress_ptr cinfo )
src->pub.bytes_in_buffer = bytes_read; src->pub.bytes_in_buffer = bytes_read;
} }
else { else {
if( src->jpeg->fail_on >= VIPS_FAIL_ON_TRUNCATED ) if( src->jpeg->fail_on >= VIPS_FAIL_ON_TRUNCATED ) {
/* Knock the output out of cache.
*/
vips_foreign_load_invalidate( src->jpeg->out );
ERREXIT( cinfo, JERR_INPUT_EOF ); ERREXIT( cinfo, JERR_INPUT_EOF );
}
else else
WARNMS( cinfo, JWRN_JPEG_EOF ); WARNMS( cinfo, JWRN_JPEG_EOF );
@ -317,6 +329,8 @@ readjpeg_open_input( ReadJpeg *jpeg )
static void static void
readjpeg_emit_message( j_common_ptr cinfo, int msg_level ) readjpeg_emit_message( j_common_ptr cinfo, int msg_level )
{ {
ReadJpeg *jpeg = (ReadJpeg *) cinfo->client_data;
long num_warnings; long num_warnings;
if( msg_level < 0 ) { if( msg_level < 0 ) {
@ -325,11 +339,13 @@ readjpeg_emit_message( j_common_ptr cinfo, int msg_level )
num_warnings = ++cinfo->err->num_warnings; num_warnings = ++cinfo->err->num_warnings;
/* Corrupt files may give many warnings, the policy here is to /* Corrupt files may give many warnings, the policy here is to
* show only the first warning and treat many warnings as fatal. * show only the first warning and treat many warnings as fatal,
* unless unlimited is set.
*/ */
if( num_warnings == 1 ) if( num_warnings == 1 )
(*cinfo->err->output_message)( cinfo ); (*cinfo->err->output_message)( cinfo );
else if( num_warnings >= 100 ) else if( !jpeg ||
(!jpeg->unlimited && num_warnings >= 100) )
cinfo->err->error_exit( cinfo ); cinfo->err->error_exit( cinfo );
} }
else if( cinfo->err->trace_level >= msg_level ) else if( cinfo->err->trace_level >= msg_level )
@ -381,13 +397,15 @@ readjpeg_minimise_cb( VipsImage *image, ReadJpeg *jpeg )
static ReadJpeg * static ReadJpeg *
readjpeg_new( VipsSource *source, VipsImage *out, readjpeg_new( VipsSource *source, VipsImage *out,
int shrink, VipsFailOn fail_on, gboolean autorotate ) int shrink, VipsFailOn fail_on, gboolean autorotate,
gboolean unlimited )
{ {
ReadJpeg *jpeg; ReadJpeg *jpeg;
if( !(jpeg = VIPS_NEW( out, ReadJpeg )) ) if( !(jpeg = VIPS_NEW( out, ReadJpeg )) )
return( NULL ); return( NULL );
jpeg->out = out;
jpeg->source = source; jpeg->source = source;
g_object_ref( source ); g_object_ref( source );
jpeg->shrink = shrink; jpeg->shrink = shrink;
@ -399,11 +417,8 @@ readjpeg_new( VipsSource *source, VipsImage *out,
jpeg->eman.fp = NULL; jpeg->eman.fp = NULL;
jpeg->y_pos = 0; jpeg->y_pos = 0;
jpeg->autorotate = autorotate; jpeg->autorotate = autorotate;
jpeg->unlimited = unlimited;
/* This is used by the error handlers to signal invalidate on the jpeg->cinfo.client_data = jpeg;
* output image.
*/
jpeg->cinfo.client_data = out;
/* jpeg_create_decompress() can fail on some sanity checks. Don't /* jpeg_create_decompress() can fail on some sanity checks. Don't
* readjpeg_free() since we don't want to jpeg_destroy_decompress(). * readjpeg_free() since we don't want to jpeg_destroy_decompress().
@ -982,12 +997,12 @@ vips__jpeg_read( ReadJpeg *jpeg, VipsImage *out, gboolean header_only )
int int
vips__jpeg_read_source( VipsSource *source, VipsImage *out, vips__jpeg_read_source( VipsSource *source, VipsImage *out,
gboolean header_only, int shrink, VipsFailOn fail_on, gboolean header_only, int shrink, VipsFailOn fail_on,
gboolean autorotate ) gboolean autorotate, gboolean unlimited )
{ {
ReadJpeg *jpeg; ReadJpeg *jpeg;
if( !(jpeg = readjpeg_new( source, out, shrink, fail_on, if( !(jpeg = readjpeg_new( source, out, shrink, fail_on,
autorotate )) ) autorotate, unlimited )) )
return( -1 ); return( -1 );
/* Here for longjmp() from vips__new_error_exit() during /* Here for longjmp() from vips__new_error_exit() during

View File

@ -74,6 +74,10 @@ typedef struct _VipsForeignLoadJpeg {
*/ */
VipsSource *source; VipsSource *source;
/* Remove DoS limits.
*/
gboolean unlimited;
/* Shrink by this much during load. /* Shrink by this much during load.
*/ */
int shrink; int shrink;
@ -140,7 +144,7 @@ vips_foreign_load_jpeg_header( VipsForeignLoad *load )
if( vips__jpeg_read_source( jpeg->source, if( vips__jpeg_read_source( jpeg->source,
load->out, TRUE, jpeg->shrink, load->fail_on, load->out, TRUE, jpeg->shrink, load->fail_on,
jpeg->autorotate ) ) jpeg->autorotate, jpeg->unlimited ) )
return( -1 ); return( -1 );
return( 0 ); return( 0 );
@ -153,7 +157,7 @@ vips_foreign_load_jpeg_load( VipsForeignLoad *load )
if( vips__jpeg_read_source( jpeg->source, if( vips__jpeg_read_source( jpeg->source,
load->real, FALSE, jpeg->shrink, load->fail_on, load->real, FALSE, jpeg->shrink, load->fail_on,
jpeg->autorotate ) ) jpeg->autorotate, jpeg->unlimited ) )
return( -1 ); return( -1 );
return( 0 ); return( 0 );
@ -199,6 +203,13 @@ vips_foreign_load_jpeg_class_init( VipsForeignLoadJpegClass *class )
G_STRUCT_OFFSET( VipsForeignLoadJpeg, autorotate ), G_STRUCT_OFFSET( VipsForeignLoadJpeg, autorotate ),
FALSE ); FALSE );
VIPS_ARG_BOOL( class, "unlimited", 22,
_( "Unlimited" ),
_( "Remove all denial of service limits" ),
VIPS_ARGUMENT_OPTIONAL_INPUT,
G_STRUCT_OFFSET( VipsForeignLoadJpeg, unlimited ),
FALSE );
} }
static void static void

View File

@ -153,7 +153,7 @@ int vips__jpeg_write_target( VipsImage *in, VipsTarget *target,
int vips__jpeg_read_source( VipsSource *source, VipsImage *out, int vips__jpeg_read_source( VipsSource *source, VipsImage *out,
gboolean header_only, int shrink, VipsFailOn fail_on, gboolean header_only, int shrink, VipsFailOn fail_on,
gboolean autorotate ); gboolean autorotate, gboolean unlimited );
int vips__isjpeg_source( VipsSource *source ); int vips__isjpeg_source( VipsSource *source );
int vips__png_ispng_source( VipsSource *source ); int vips__png_ispng_source( VipsSource *source );

View File

@ -173,12 +173,6 @@ vips__new_output_message( j_common_ptr cinfo )
#ifdef DEBUG #ifdef DEBUG
printf( "vips__new_output_message: \"%s\"\n", buffer ); printf( "vips__new_output_message: \"%s\"\n", buffer );
#endif /*DEBUG*/ #endif /*DEBUG*/
/* This is run for things like file truncated. Signal invalidate to
* force this op out of cache.
*/
if( cinfo->client_data )
vips_foreign_load_invalidate( VIPS_IMAGE( cinfo->client_data ) );
} }
/* New error_exit handler. /* New error_exit handler.

View File

@ -204,7 +204,7 @@ if test_supported matload; then
# test blocked and untrusted # test blocked and untrusted
printf "testing VIPS_BLOCK_UNTRUSTED with matio ... " printf "testing VIPS_BLOCK_UNTRUSTED with matio ... "
export VIPS_BLOCK_UNTRUSTED=1 export VIPS_BLOCK_UNTRUSTED=1
if vips matload $matlab $tmp/block.png; then if $vips matload $matlab $tmp/block.png; then
echo "failed to block matload" echo "failed to block matload"
exit 1 exit 1
fi fi