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
tags
TAGS
### End of VIM
### Distribution

View File

@ -2,6 +2,7 @@
- fix im7 feature detection in meson
- add a summary table at the end of configure in meson
- fix libpng fallback when spng is disabled in meson
- add "unlimited" to jpegload
21/11/21 started 8.13
- 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 )) )
return( -1 );
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 );
return( -1 );
}

View File

@ -112,6 +112,8 @@
* - set resolution unit from JFIF
* 24/7/21
* - add fail_on support
* 2/8/22
* - add "unlimited"
*/
/*
@ -169,6 +171,8 @@
/* Stuff we track during a read.
*/
typedef struct _ReadJpeg {
VipsImage *out;
/* Shrink by this much during load. 1, 2, 4, 8.
*/
int shrink;
@ -190,6 +194,10 @@ typedef struct _ReadJpeg {
*/
gboolean autorotate;
/* Remove DoS limits.
*/
gboolean unlimited;
/* 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
* 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;
}
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 );
}
else
WARNMS( cinfo, JWRN_JPEG_EOF );
@ -317,6 +329,8 @@ readjpeg_open_input( ReadJpeg *jpeg )
static void
readjpeg_emit_message( j_common_ptr cinfo, int msg_level )
{
ReadJpeg *jpeg = (ReadJpeg *) cinfo->client_data;
long num_warnings;
if( msg_level < 0 ) {
@ -325,11 +339,13 @@ readjpeg_emit_message( j_common_ptr cinfo, int msg_level )
num_warnings = ++cinfo->err->num_warnings;
/* 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 )
(*cinfo->err->output_message)( cinfo );
else if( num_warnings >= 100 )
else if( !jpeg ||
(!jpeg->unlimited && num_warnings >= 100) )
cinfo->err->error_exit( cinfo );
}
else if( cinfo->err->trace_level >= msg_level )
@ -381,13 +397,15 @@ readjpeg_minimise_cb( VipsImage *image, ReadJpeg *jpeg )
static ReadJpeg *
readjpeg_new( VipsSource *source, VipsImage *out,
int shrink, VipsFailOn fail_on, gboolean autorotate )
int shrink, VipsFailOn fail_on, gboolean autorotate,
gboolean unlimited )
{
ReadJpeg *jpeg;
if( !(jpeg = VIPS_NEW( out, ReadJpeg )) )
return( NULL );
jpeg->out = out;
jpeg->source = source;
g_object_ref( source );
jpeg->shrink = shrink;
@ -399,11 +417,8 @@ readjpeg_new( VipsSource *source, VipsImage *out,
jpeg->eman.fp = NULL;
jpeg->y_pos = 0;
jpeg->autorotate = autorotate;
/* This is used by the error handlers to signal invalidate on the
* output image.
*/
jpeg->cinfo.client_data = out;
jpeg->unlimited = unlimited;
jpeg->cinfo.client_data = jpeg;
/* jpeg_create_decompress() can fail on some sanity checks. Don't
* 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
vips__jpeg_read_source( VipsSource *source, VipsImage *out,
gboolean header_only, int shrink, VipsFailOn fail_on,
gboolean autorotate )
gboolean autorotate, gboolean unlimited )
{
ReadJpeg *jpeg;
if( !(jpeg = readjpeg_new( source, out, shrink, fail_on,
autorotate )) )
autorotate, unlimited )) )
return( -1 );
/* Here for longjmp() from vips__new_error_exit() during

View File

@ -74,6 +74,10 @@ typedef struct _VipsForeignLoadJpeg {
*/
VipsSource *source;
/* Remove DoS limits.
*/
gboolean unlimited;
/* Shrink by this much during load.
*/
int shrink;
@ -140,7 +144,7 @@ vips_foreign_load_jpeg_header( VipsForeignLoad *load )
if( vips__jpeg_read_source( jpeg->source,
load->out, TRUE, jpeg->shrink, load->fail_on,
jpeg->autorotate ) )
jpeg->autorotate, jpeg->unlimited ) )
return( -1 );
return( 0 );
@ -153,7 +157,7 @@ vips_foreign_load_jpeg_load( VipsForeignLoad *load )
if( vips__jpeg_read_source( jpeg->source,
load->real, FALSE, jpeg->shrink, load->fail_on,
jpeg->autorotate ) )
jpeg->autorotate, jpeg->unlimited ) )
return( -1 );
return( 0 );
@ -199,6 +203,13 @@ vips_foreign_load_jpeg_class_init( VipsForeignLoadJpegClass *class )
G_STRUCT_OFFSET( VipsForeignLoadJpeg, autorotate ),
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

View File

@ -153,7 +153,7 @@ int vips__jpeg_write_target( VipsImage *in, VipsTarget *target,
int vips__jpeg_read_source( VipsSource *source, VipsImage *out,
gboolean header_only, int shrink, VipsFailOn fail_on,
gboolean autorotate );
gboolean autorotate, gboolean unlimited );
int vips__isjpeg_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
printf( "vips__new_output_message: \"%s\"\n", buffer );
#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.

View File

@ -204,7 +204,7 @@ if test_supported matload; then
# test blocked and untrusted
printf "testing VIPS_BLOCK_UNTRUSTED with matio ... "
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"
exit 1
fi