Introduce unlimited flag, enabling unlimited text chunks in PNGs (#2419)
* Introduce unlimited flag, enabling unlimited text chunks * remove extraneous optional flag causing GLib-GObject-CRITICAL **: 17:10:34.095: validate_and_install_class_property * Address feedback from @jcupitt * various compilation error fixes * Interlace detection uses unlimited=false * attempt to fix tests * documentation changes, introduced MAX_PNG_TEXT_CHUNKS and bumped max to 20 (was 10)
This commit is contained in:
parent
b0b8e6ee65
commit
608a7cee9b
@ -4562,6 +4562,7 @@ VImage phasecor( VImage in2, VOption *options = 0 ) const;
|
|||||||
* - **sequential** -- Sequential read only, bool.
|
* - **sequential** -- Sequential read only, bool.
|
||||||
* - **fail** -- Fail on first error, bool.
|
* - **fail** -- Fail on first error, bool.
|
||||||
* - **disc** -- Open to disc, bool.
|
* - **disc** -- Open to disc, bool.
|
||||||
|
* - **unlimited** -- Remove all denial of service limits.
|
||||||
*
|
*
|
||||||
* @param filename Filename to load from.
|
* @param filename Filename to load from.
|
||||||
* @param options Set of options.
|
* @param options Set of options.
|
||||||
@ -4578,6 +4579,7 @@ static VImage pngload( const char *filename, VOption *options = 0 );
|
|||||||
* - **sequential** -- Sequential read only, bool.
|
* - **sequential** -- Sequential read only, bool.
|
||||||
* - **fail** -- Fail on first error, bool.
|
* - **fail** -- Fail on first error, bool.
|
||||||
* - **disc** -- Open to disc, bool.
|
* - **disc** -- Open to disc, bool.
|
||||||
|
* - **unlimited** -- Remove all denial of service limits.
|
||||||
*
|
*
|
||||||
* @param buffer Buffer to load from.
|
* @param buffer Buffer to load from.
|
||||||
* @param options Set of options.
|
* @param options Set of options.
|
||||||
@ -4594,6 +4596,7 @@ static VImage pngload_buffer( VipsBlob *buffer, VOption *options = 0 );
|
|||||||
* - **sequential** -- Sequential read only, bool.
|
* - **sequential** -- Sequential read only, bool.
|
||||||
* - **fail** -- Fail on first error, bool.
|
* - **fail** -- Fail on first error, bool.
|
||||||
* - **disc** -- Open to disc, bool.
|
* - **disc** -- Open to disc, bool.
|
||||||
|
* - **unlimited** -- Remove all denial of service limits.
|
||||||
*
|
*
|
||||||
* @param source Source to load from.
|
* @param source Source to load from.
|
||||||
* @param options Set of options.
|
* @param options Set of options.
|
||||||
|
@ -45,6 +45,8 @@ extern "C" {
|
|||||||
)
|
)
|
||||||
#endif /*HAVE_CHECKED_MUL*/
|
#endif /*HAVE_CHECKED_MUL*/
|
||||||
|
|
||||||
|
#define MAX_PNG_TEXT_CHUNKS 20
|
||||||
|
|
||||||
void vips__tiff_init( void );
|
void vips__tiff_init( void );
|
||||||
|
|
||||||
int vips__tiff_write( VipsImage *in, const char *filename,
|
int vips__tiff_write( VipsImage *in, const char *filename,
|
||||||
@ -177,9 +179,9 @@ int vips__jpeg_read_source( VipsSource *source, VipsImage *out,
|
|||||||
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 );
|
||||||
int vips__png_header_source( VipsSource *source, VipsImage *out );
|
int vips__png_header_source( VipsSource *source, VipsImage *out, gboolean unlimited );
|
||||||
int vips__png_read_source( VipsSource *source, VipsImage *out,
|
int vips__png_read_source( VipsSource *source, VipsImage *out,
|
||||||
gboolean fail );
|
gboolean fail, gboolean unlimited );
|
||||||
gboolean vips__png_isinterlaced_source( VipsSource *source );
|
gboolean vips__png_isinterlaced_source( VipsSource *source );
|
||||||
extern const char *vips__png_suffs[];
|
extern const char *vips__png_suffs[];
|
||||||
|
|
||||||
|
@ -59,6 +59,10 @@ typedef struct _VipsForeignLoadPng {
|
|||||||
*/
|
*/
|
||||||
VipsSource *source;
|
VipsSource *source;
|
||||||
|
|
||||||
|
/* remove all denial of service limits.
|
||||||
|
*/
|
||||||
|
gboolean unlimited;
|
||||||
|
|
||||||
} VipsForeignLoadPng;
|
} VipsForeignLoadPng;
|
||||||
|
|
||||||
typedef VipsForeignLoadClass VipsForeignLoadPngClass;
|
typedef VipsForeignLoadClass VipsForeignLoadPngClass;
|
||||||
@ -118,7 +122,7 @@ vips_foreign_load_png_header( VipsForeignLoad *load )
|
|||||||
{
|
{
|
||||||
VipsForeignLoadPng *png = (VipsForeignLoadPng *) load;
|
VipsForeignLoadPng *png = (VipsForeignLoadPng *) load;
|
||||||
|
|
||||||
if( vips__png_header_source( png->source, load->out ) )
|
if( vips__png_header_source( png->source, load->out, png->unlimited ) )
|
||||||
return( -1 );
|
return( -1 );
|
||||||
|
|
||||||
return( 0 );
|
return( 0 );
|
||||||
@ -129,7 +133,7 @@ vips_foreign_load_png_load( VipsForeignLoad *load )
|
|||||||
{
|
{
|
||||||
VipsForeignLoadPng *png = (VipsForeignLoadPng *) load;
|
VipsForeignLoadPng *png = (VipsForeignLoadPng *) load;
|
||||||
|
|
||||||
if( vips__png_read_source( png->source, load->real, load->fail ) )
|
if( vips__png_read_source( png->source, load->real, load->fail, png->unlimited ) )
|
||||||
return( -1 );
|
return( -1 );
|
||||||
|
|
||||||
return( 0 );
|
return( 0 );
|
||||||
@ -144,6 +148,8 @@ vips_foreign_load_png_class_init( VipsForeignLoadPngClass *class )
|
|||||||
VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class;
|
VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class;
|
||||||
|
|
||||||
gobject_class->dispose = vips_foreign_load_png_dispose;
|
gobject_class->dispose = vips_foreign_load_png_dispose;
|
||||||
|
gobject_class->set_property = vips_object_set_property;
|
||||||
|
gobject_class->get_property = vips_object_get_property;
|
||||||
|
|
||||||
object_class->nickname = "pngload_base";
|
object_class->nickname = "pngload_base";
|
||||||
object_class->description = _( "load png base class" );
|
object_class->description = _( "load png base class" );
|
||||||
@ -158,6 +164,12 @@ vips_foreign_load_png_class_init( VipsForeignLoadPngClass *class )
|
|||||||
load_class->header = vips_foreign_load_png_header;
|
load_class->header = vips_foreign_load_png_header;
|
||||||
load_class->load = vips_foreign_load_png_load;
|
load_class->load = vips_foreign_load_png_load;
|
||||||
|
|
||||||
|
VIPS_ARG_BOOL( class, "unlimited", 23,
|
||||||
|
_( "Unlimited" ),
|
||||||
|
_( "Remove all denial of service limits" ),
|
||||||
|
VIPS_ARGUMENT_OPTIONAL_INPUT,
|
||||||
|
G_STRUCT_OFFSET( VipsForeignLoadPng, unlimited ),
|
||||||
|
FALSE );
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -395,12 +407,20 @@ vips_foreign_load_png_buffer_init( VipsForeignLoadPngBuffer *buffer )
|
|||||||
* @out: (out): decompressed image
|
* @out: (out): decompressed image
|
||||||
* @...: %NULL-terminated list of optional named arguments
|
* @...: %NULL-terminated list of optional named arguments
|
||||||
*
|
*
|
||||||
|
* Optional arguments:
|
||||||
|
*
|
||||||
|
* * @unlimited: %gboolean, remove all denial of service limits
|
||||||
|
*
|
||||||
* Read a PNG file into a VIPS image. It can read all png images, including 8-
|
* Read a PNG file into a VIPS image. It can read all png images, including 8-
|
||||||
* and 16-bit images, 1 and 3 channel, with and without an alpha channel.
|
* and 16-bit images, 1 and 3 channel, with and without an alpha channel.
|
||||||
*
|
*
|
||||||
* Any ICC profile is read and attached to the VIPS image. It also supports
|
* Any ICC profile is read and attached to the VIPS image. It also supports
|
||||||
* XMP metadata.
|
* XMP metadata.
|
||||||
*
|
*
|
||||||
|
* By default, the PNG loader limits the number of text and data chunks to
|
||||||
|
* block some denial of service attacks. Set @unlimited to disable these
|
||||||
|
* limits.
|
||||||
|
*
|
||||||
* See also: vips_image_new_from_file().
|
* See also: vips_image_new_from_file().
|
||||||
*
|
*
|
||||||
* Returns: 0 on success, -1 on error.
|
* Returns: 0 on success, -1 on error.
|
||||||
@ -425,6 +445,10 @@ vips_pngload( const char *filename, VipsImage **out, ... )
|
|||||||
* @out: (out): image to write
|
* @out: (out): image to write
|
||||||
* @...: %NULL-terminated list of optional named arguments
|
* @...: %NULL-terminated list of optional named arguments
|
||||||
*
|
*
|
||||||
|
* Optional arguments:
|
||||||
|
*
|
||||||
|
* * @unlimited: %gboolean, Remove all denial of service limits
|
||||||
|
*
|
||||||
* Exactly as vips_pngload(), but read from a PNG-formatted memory block.
|
* Exactly as vips_pngload(), but read from a PNG-formatted memory block.
|
||||||
*
|
*
|
||||||
* You must not free the buffer while @out is active. The
|
* You must not free the buffer while @out is active. The
|
||||||
@ -460,6 +484,10 @@ vips_pngload_buffer( void *buf, size_t len, VipsImage **out, ... )
|
|||||||
* @out: (out): image to write
|
* @out: (out): image to write
|
||||||
* @...: %NULL-terminated list of optional named arguments
|
* @...: %NULL-terminated list of optional named arguments
|
||||||
*
|
*
|
||||||
|
* Optional arguments:
|
||||||
|
*
|
||||||
|
* * @unlimited: %gboolean, Remove all denial of service limits
|
||||||
|
*
|
||||||
* Exactly as vips_pngload(), but read from a source.
|
* Exactly as vips_pngload(), but read from a source.
|
||||||
*
|
*
|
||||||
* See also: vips_pngload().
|
* See also: vips_pngload().
|
||||||
|
@ -63,6 +63,10 @@ typedef struct _VipsForeignLoadPng {
|
|||||||
*/
|
*/
|
||||||
VipsSource *source;
|
VipsSource *source;
|
||||||
|
|
||||||
|
/* Remove DoS limits.
|
||||||
|
*/
|
||||||
|
gboolean unlimited;
|
||||||
|
|
||||||
spng_ctx *ctx;
|
spng_ctx *ctx;
|
||||||
struct spng_ihdr ihdr;
|
struct spng_ihdr ihdr;
|
||||||
enum spng_format fmt;
|
enum spng_format fmt;
|
||||||
@ -249,7 +253,8 @@ vips_foreign_load_png_set_header( VipsForeignLoadPng *png, VipsImage *image )
|
|||||||
/* Very large numbers of text chunks are used in DoS
|
/* Very large numbers of text chunks are used in DoS
|
||||||
* attacks.
|
* attacks.
|
||||||
*/
|
*/
|
||||||
if( n_text > 10 ) {
|
|
||||||
|
if( !png->unlimited && n_text > MAX_PNG_TEXT_CHUNKS ) {
|
||||||
vips_error( class->nickname,
|
vips_error( class->nickname,
|
||||||
"%s", _( "too many text chunks" ) );
|
"%s", _( "too many text chunks" ) );
|
||||||
return( -1 );
|
return( -1 );
|
||||||
@ -349,8 +354,10 @@ vips_foreign_load_png_header( VipsForeignLoad *load )
|
|||||||
* No need to test the decoded image size -- the user can do that if
|
* No need to test the decoded image size -- the user can do that if
|
||||||
* they wish.
|
* they wish.
|
||||||
*/
|
*/
|
||||||
spng_set_image_limits( png->ctx, VIPS_MAX_COORD, VIPS_MAX_COORD );
|
if ( !png->unlimited ) {
|
||||||
spng_set_chunk_limits( png->ctx, 60 * 1024 * 1024, 60 * 1024 * 1024 );
|
spng_set_image_limits( png->ctx, VIPS_MAX_COORD, VIPS_MAX_COORD );
|
||||||
|
spng_set_chunk_limits( png->ctx, 60 * 1024 * 1024, 60 * 1024 * 1024 );
|
||||||
|
}
|
||||||
|
|
||||||
if( vips_source_rewind( png->source ) )
|
if( vips_source_rewind( png->source ) )
|
||||||
return( -1 );
|
return( -1 );
|
||||||
@ -648,6 +655,8 @@ vips_foreign_load_png_class_init( VipsForeignLoadPngClass *class )
|
|||||||
VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class;
|
VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class;
|
||||||
|
|
||||||
gobject_class->dispose = vips_foreign_load_png_dispose;
|
gobject_class->dispose = vips_foreign_load_png_dispose;
|
||||||
|
gobject_class->set_property = vips_object_set_property;
|
||||||
|
gobject_class->get_property = vips_object_get_property;
|
||||||
|
|
||||||
object_class->nickname = "pngload_base";
|
object_class->nickname = "pngload_base";
|
||||||
object_class->description = _( "load png base class" );
|
object_class->description = _( "load png base class" );
|
||||||
@ -662,6 +671,12 @@ vips_foreign_load_png_class_init( VipsForeignLoadPngClass *class )
|
|||||||
load_class->header = vips_foreign_load_png_header;
|
load_class->header = vips_foreign_load_png_header;
|
||||||
load_class->load = vips_foreign_load_png_load;
|
load_class->load = vips_foreign_load_png_load;
|
||||||
|
|
||||||
|
VIPS_ARG_BOOL( class, "unlimited", 23,
|
||||||
|
_( "Unlimited" ),
|
||||||
|
_( "Remove all denial of service limits" ),
|
||||||
|
VIPS_ARGUMENT_OPTIONAL_INPUT,
|
||||||
|
G_STRUCT_OFFSET( VipsForeignLoadPng, unlimited ),
|
||||||
|
FALSE );
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -173,6 +173,7 @@ typedef struct {
|
|||||||
char *name;
|
char *name;
|
||||||
VipsImage *out;
|
VipsImage *out;
|
||||||
gboolean fail;
|
gboolean fail;
|
||||||
|
gboolean unlimited;
|
||||||
|
|
||||||
int y_pos;
|
int y_pos;
|
||||||
png_structp pPng;
|
png_structp pPng;
|
||||||
@ -255,7 +256,7 @@ vips_png_read_source( png_structp pPng, png_bytep data, png_size_t length )
|
|||||||
}
|
}
|
||||||
|
|
||||||
static Read *
|
static Read *
|
||||||
read_new( VipsSource *source, VipsImage *out, gboolean fail )
|
read_new( VipsSource *source, VipsImage *out, gboolean fail, gboolean unlimited )
|
||||||
{
|
{
|
||||||
Read *read;
|
Read *read;
|
||||||
|
|
||||||
@ -270,6 +271,8 @@ read_new( VipsSource *source, VipsImage *out, gboolean fail )
|
|||||||
read->pInfo = NULL;
|
read->pInfo = NULL;
|
||||||
read->row_pointer = NULL;
|
read->row_pointer = NULL;
|
||||||
read->source = source;
|
read->source = source;
|
||||||
|
read->unlimited = unlimited;
|
||||||
|
|
||||||
g_object_ref( source );
|
g_object_ref( source );
|
||||||
|
|
||||||
g_signal_connect( out, "close",
|
g_signal_connect( out, "close",
|
||||||
@ -564,7 +567,7 @@ png2vips_header( Read *read, VipsImage *out )
|
|||||||
/* Very large numbers of text chunks are used in DoS
|
/* Very large numbers of text chunks are used in DoS
|
||||||
* attacks.
|
* attacks.
|
||||||
*/
|
*/
|
||||||
if( num_text > 10 ) {
|
if( !read->unlimited && num_text > MAX_PNG_TEXT_CHUNKS ) {
|
||||||
vips_error( "vipspng",
|
vips_error( "vipspng",
|
||||||
"%s", _( "too many text chunks" ) );
|
"%s", _( "too many text chunks" ) );
|
||||||
return( -1 );
|
return( -1 );
|
||||||
@ -778,11 +781,11 @@ vips__png_ispng_source( VipsSource *source )
|
|||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
vips__png_header_source( VipsSource *source, VipsImage *out )
|
vips__png_header_source( VipsSource *source, VipsImage *out, gboolean unlimited )
|
||||||
{
|
{
|
||||||
Read *read;
|
Read *read;
|
||||||
|
|
||||||
if( !(read = read_new( source, out, TRUE )) ||
|
if( !(read = read_new( source, out, TRUE, unlimited )) ||
|
||||||
png2vips_header( read, out ) ) {
|
png2vips_header( read, out ) ) {
|
||||||
vips_error( "png2vips", _( "unable to read source %s" ),
|
vips_error( "png2vips", _( "unable to read source %s" ),
|
||||||
vips_connection_nick( VIPS_CONNECTION( source ) ) );
|
vips_connection_nick( VIPS_CONNECTION( source ) ) );
|
||||||
@ -795,11 +798,11 @@ vips__png_header_source( VipsSource *source, VipsImage *out )
|
|||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
vips__png_read_source( VipsSource *source, VipsImage *out, gboolean fail )
|
vips__png_read_source( VipsSource *source, VipsImage *out, gboolean fail, gboolean unlimited )
|
||||||
{
|
{
|
||||||
Read *read;
|
Read *read;
|
||||||
|
|
||||||
if( !(read = read_new( source, out, fail )) ||
|
if( !(read = read_new( source, out, fail, unlimited )) ||
|
||||||
png2vips_image( read, out ) ||
|
png2vips_image( read, out ) ||
|
||||||
vips_source_decode( source ) ) {
|
vips_source_decode( source ) ) {
|
||||||
vips_error( "png2vips", _( "unable to read source %s" ),
|
vips_error( "png2vips", _( "unable to read source %s" ),
|
||||||
@ -822,7 +825,7 @@ vips__png_isinterlaced_source( VipsSource *source )
|
|||||||
|
|
||||||
image = vips_image_new();
|
image = vips_image_new();
|
||||||
|
|
||||||
if( !(read = read_new( source, image, TRUE )) ) {
|
if( !(read = read_new( source, image, TRUE, FALSE )) ) {
|
||||||
g_object_unref( image );
|
g_object_unref( image );
|
||||||
return( -1 );
|
return( -1 );
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user