diff --git a/ChangeLog b/ChangeLog index 92a17d62..a6bed668 100644 --- a/ChangeLog +++ b/ChangeLog @@ -7,6 +7,7 @@ - add spngsave - jpeg2000 load left-justifies bitdepth - add "password" option to pdfload +- add vips_operation_block_set(), vips_operation_block_untrusted_set() - improve the pixel rng - new meson build system [tintou] - improve introspection annotations [tintou] diff --git a/libvips/foreign/analyzeload.c b/libvips/foreign/analyzeload.c index c0b0a575..e2fc47cd 100644 --- a/libvips/foreign/analyzeload.c +++ b/libvips/foreign/analyzeload.c @@ -109,6 +109,7 @@ vips_foreign_load_analyze_class_init( VipsForeignLoadAnalyzeClass *class ) { GObjectClass *gobject_class = G_OBJECT_CLASS( class ); VipsObjectClass *object_class = (VipsObjectClass *) class; + VipsOperationClass *operation_class = VIPS_OPERATION_CLASS( class ); VipsForeignClass *foreign_class = (VipsForeignClass *) class; VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; @@ -118,6 +119,11 @@ vips_foreign_load_analyze_class_init( VipsForeignLoadAnalyzeClass *class ) object_class->nickname = "analyzeload"; object_class->description = _( "load an Analyze6 image" ); + /* This is fuzzed, but you're unlikely to want to use it on + * untrusted files. + */ + operation_class->flags |= VIPS_OPERATION_UNTRUSTED; + foreign_class->suffs = vips_foreign_analyze_suffs; /* is_a() is not that quick ... lower the priority. diff --git a/libvips/foreign/csvload.c b/libvips/foreign/csvload.c index 74ba16fe..815648bc 100644 --- a/libvips/foreign/csvload.c +++ b/libvips/foreign/csvload.c @@ -470,6 +470,7 @@ vips_foreign_load_csv_class_init( VipsForeignLoadCsvClass *class ) { GObjectClass *gobject_class = G_OBJECT_CLASS( class ); VipsObjectClass *object_class = (VipsObjectClass *) class; + VipsOperationClass *operation_class = VIPS_OPERATION_CLASS( class ); VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->dispose = vips_foreign_load_csv_dispose; @@ -480,6 +481,11 @@ vips_foreign_load_csv_class_init( VipsForeignLoadCsvClass *class ) object_class->description = _( "load csv" ); object_class->build = vips_foreign_load_csv_build; + /* This is fuzzed, but you're unlikely to want to use it on + * untrusted files. + */ + operation_class->flags |= VIPS_OPERATION_UNTRUSTED; + load_class->get_flags = vips_foreign_load_csv_get_flags; load_class->header = vips_foreign_load_csv_header; load_class->load = vips_foreign_load_csv_load; diff --git a/libvips/foreign/fitsload.c b/libvips/foreign/fitsload.c index 6e8f3453..cdf67b97 100644 --- a/libvips/foreign/fitsload.c +++ b/libvips/foreign/fitsload.c @@ -173,6 +173,7 @@ vips_foreign_load_fits_class_init( VipsForeignLoadFitsClass *class ) { GObjectClass *gobject_class = G_OBJECT_CLASS( class ); VipsObjectClass *object_class = (VipsObjectClass *) class; + VipsOperationClass *operation_class = VIPS_OPERATION_CLASS( class ); VipsForeignClass *foreign_class = (VipsForeignClass *) class; VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; @@ -184,6 +185,11 @@ vips_foreign_load_fits_class_init( VipsForeignLoadFitsClass *class ) object_class->description = _( "FITS loader base class" ); object_class->build = vips_foreign_load_fits_build; + /* cfitsio has not been fuzzed, so should not be used with + * untrusted input unless you are very careful. + */ + operation_class->flags = VIPS_OPERATION_UNTRUSTED; + /* is_a() is not that quick ... lower the priority. */ foreign_class->priority = -50; diff --git a/libvips/foreign/fitssave.c b/libvips/foreign/fitssave.c index ac7032ed..cc7c7e6d 100644 --- a/libvips/foreign/fitssave.c +++ b/libvips/foreign/fitssave.c @@ -119,6 +119,7 @@ vips_foreign_save_fits_class_init( VipsForeignSaveFitsClass *class ) { GObjectClass *gobject_class = G_OBJECT_CLASS( class ); VipsObjectClass *object_class = (VipsObjectClass *) class; + VipsOperationClass *operation_class = VIPS_OPERATION_CLASS( class ); VipsForeignClass *foreign_class = (VipsForeignClass *) class; VipsForeignSaveClass *save_class = (VipsForeignSaveClass *) class; @@ -129,6 +130,11 @@ vips_foreign_save_fits_class_init( VipsForeignSaveFitsClass *class ) object_class->description = _( "save image to fits file" ); object_class->build = vips_foreign_save_fits_build; + /* cfitsio has not been fuzzed, so should not be used with + * untrusted input unless you are very careful. + */ + operation_class->flags = VIPS_OPERATION_UNTRUSTED; + foreign_class->suffs = vips__fits_suffs; save_class->saveable = VIPS_SAVEABLE_ANY; diff --git a/libvips/foreign/foreign.c b/libvips/foreign/foreign.c index a20a2ebb..07344eae 100644 --- a/libvips/foreign/foreign.c +++ b/libvips/foreign/foreign.c @@ -1165,8 +1165,8 @@ vips_foreign_load_class_init( VipsForeignLoadClass *class ) object_class->build = vips_foreign_load_build; object_class->summary_class = vips_foreign_load_summary_class; object_class->new_from_string = vips_foreign_load_new_from_string; - object_class->nickname = "fileload"; - object_class->description = _( "file loaders" ); + object_class->nickname = "load"; + object_class->description = _( "loaders" ); operation_class->get_flags = vips_foreign_load_operation_get_flags; @@ -1767,8 +1767,8 @@ vips_foreign_save_class_init( VipsForeignSaveClass *class ) object_class->build = vips_foreign_save_build; object_class->summary_class = vips_foreign_save_summary_class; object_class->new_from_string = vips_foreign_save_new_from_string; - object_class->nickname = "filesave"; - object_class->description = _( "file savers" ); + object_class->nickname = "save"; + object_class->description = _( "savers" ); /* All savers are sequential by definition. Things like tiled tiff * write and interlaced png write, which are not, add extra caches diff --git a/libvips/foreign/jp2kload.c b/libvips/foreign/jp2kload.c index 4496f0d9..8cdfb62f 100644 --- a/libvips/foreign/jp2kload.c +++ b/libvips/foreign/jp2kload.c @@ -1038,6 +1038,7 @@ vips_foreign_load_jp2k_class_init( VipsForeignLoadJp2kClass *class ) { GObjectClass *gobject_class = G_OBJECT_CLASS( class ); VipsObjectClass *object_class = (VipsObjectClass *) class; + VipsOperationClass *operation_class = VIPS_OPERATION_CLASS( class ); VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->dispose = vips_foreign_load_jp2k_dispose; @@ -1048,6 +1049,10 @@ vips_foreign_load_jp2k_class_init( VipsForeignLoadJp2kClass *class ) object_class->description = _( "load JPEG2000 image" ); object_class->build = vips_foreign_load_jp2k_build; + /* OpenJPEG is fuzzed, but not by us. + */ + operation_class->flags |= VIPS_OPERATION_UNTRUSTED; + load_class->get_flags = vips_foreign_load_jp2k_get_flags; load_class->header = vips_foreign_load_jp2k_header; load_class->load = vips_foreign_load_jp2k_load; diff --git a/libvips/foreign/jxlload.c b/libvips/foreign/jxlload.c index bddd42bd..9e649667 100644 --- a/libvips/foreign/jxlload.c +++ b/libvips/foreign/jxlload.c @@ -697,6 +697,7 @@ vips_foreign_load_jxl_class_init( VipsForeignLoadJxlClass *class ) { GObjectClass *gobject_class = G_OBJECT_CLASS( class ); VipsObjectClass *object_class = (VipsObjectClass *) class; + VipsOperationClass *operation_class = VIPS_OPERATION_CLASS( class ); VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->dispose = vips_foreign_load_jxl_dispose; @@ -707,6 +708,11 @@ vips_foreign_load_jxl_class_init( VipsForeignLoadJxlClass *class ) object_class->description = _( "load JPEG-XL image" ); object_class->build = vips_foreign_load_jxl_build; + /* libjxl is fuzzed, but it's relatively young and bugs are + * still being found in jan 2022. Revise this status soon. + */ + operation_class->flags |= VIPS_OPERATION_UNTRUSTED; + load_class->get_flags = vips_foreign_load_jxl_get_flags; load_class->header = vips_foreign_load_jxl_header; load_class->load = vips_foreign_load_jxl_load; diff --git a/libvips/foreign/jxlsave.c b/libvips/foreign/jxlsave.c index 109ff450..e20da32e 100644 --- a/libvips/foreign/jxlsave.c +++ b/libvips/foreign/jxlsave.c @@ -451,6 +451,7 @@ vips_foreign_save_jxl_class_init( VipsForeignSaveJxlClass *class ) { GObjectClass *gobject_class = G_OBJECT_CLASS( class ); VipsObjectClass *object_class = (VipsObjectClass *) class; + VipsOperationClass *operation_class = VIPS_OPERATION_CLASS( class ); VipsForeignClass *foreign_class = (VipsForeignClass *) class; VipsForeignSaveClass *save_class = (VipsForeignSaveClass *) class; @@ -462,6 +463,11 @@ vips_foreign_save_jxl_class_init( VipsForeignSaveJxlClass *class ) object_class->description = _( "save image in JPEG-XL format" ); object_class->build = vips_foreign_save_jxl_build; + /* libjxl is fuzzed, but it's still relatively young and bugs are + * still being found in jan 2022. Revise this status soon. + */ + operation_class->flags |= VIPS_OPERATION_UNTRUSTED; + foreign_class->suffs = vips__jxl_suffs; save_class->saveable = VIPS_SAVEABLE_ANY; diff --git a/libvips/foreign/magick6load.c b/libvips/foreign/magick6load.c index 5f4d9e21..77419814 100644 --- a/libvips/foreign/magick6load.c +++ b/libvips/foreign/magick6load.c @@ -116,6 +116,11 @@ vips_foreign_load_magick_class_init( VipsForeignLoadMagickClass *class ) */ operation_class->flags = VIPS_OPERATION_NOCACHE; + /* *magick is fuzzed, but it's such a huge thing it's safer to + * disable it. + */ + operation_class->flags |= VIPS_OPERATION_UNTRUSTED; + /* We need to be well to the back of the queue since vips's * dedicated loaders are usually preferable. */ diff --git a/libvips/foreign/magick7load.c b/libvips/foreign/magick7load.c index 234c1d9e..0ece1ce6 100644 --- a/libvips/foreign/magick7load.c +++ b/libvips/foreign/magick7load.c @@ -341,6 +341,7 @@ vips_foreign_load_magick7_class_init( VipsForeignLoadMagick7Class *class ) { GObjectClass *gobject_class = G_OBJECT_CLASS( class ); VipsObjectClass *object_class = (VipsObjectClass *) class; + VipsOperationClass *operation_class = VIPS_OPERATION_CLASS( class ); VipsForeignClass *foreign_class = (VipsForeignClass *) class; VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; @@ -352,6 +353,15 @@ vips_foreign_load_magick7_class_init( VipsForeignLoadMagick7Class *class ) object_class->description = _( "load with ImageMagick7" ); object_class->build = vips_foreign_load_magick7_build; + /* Don't cache magickload: it can gobble up memory and disc. + */ + operation_class->flags = VIPS_OPERATION_NOCACHE; + + /* *magick is fuzzed, but it's such a huge thing it's safer to + * disable it. + */ + operation_class->flags |= VIPS_OPERATION_UNTRUSTED; + /* We need to be well to the back of the queue since vips's * dedicated loaders are usually preferable. */ diff --git a/libvips/foreign/matload.c b/libvips/foreign/matload.c index 1d423342..e6fc7e0f 100644 --- a/libvips/foreign/matload.c +++ b/libvips/foreign/matload.c @@ -111,6 +111,7 @@ vips_foreign_load_mat_class_init( VipsForeignLoadMatClass *class ) { GObjectClass *gobject_class = G_OBJECT_CLASS( class ); VipsObjectClass *object_class = (VipsObjectClass *) class; + VipsOperationClass *operation_class = VIPS_OPERATION_CLASS( class ); VipsForeignClass *foreign_class = (VipsForeignClass *) class; VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; @@ -120,6 +121,10 @@ vips_foreign_load_mat_class_init( VipsForeignLoadMatClass *class ) object_class->nickname = "matload"; object_class->description = _( "load mat from file" ); + /* libmatio is fuzzed, but not by us. + */ + operation_class->flags |= VIPS_OPERATION_UNTRUSTED; + foreign_class->suffs = vips__mat_suffs; load_class->is_a = vips__mat_ismat; diff --git a/libvips/foreign/niftiload.c b/libvips/foreign/niftiload.c index c993e97e..a530dbe2 100644 --- a/libvips/foreign/niftiload.c +++ b/libvips/foreign/niftiload.c @@ -580,6 +580,7 @@ vips_foreign_load_nifti_class_init( VipsForeignLoadNiftiClass *class ) { GObjectClass *gobject_class = G_OBJECT_CLASS( class ); VipsObjectClass *object_class = (VipsObjectClass *) class; + VipsOperationClass *operation_class = VIPS_OPERATION_CLASS( class ); VipsForeignClass *foreign_class = (VipsForeignClass *) class; VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; @@ -591,6 +592,11 @@ vips_foreign_load_nifti_class_init( VipsForeignLoadNiftiClass *class ) object_class->description = _( "load a NIFTI image" ); object_class->build = vips_foreign_load_nifti_build; + /* nificlib has not been fuzzed, so should not be used with + * untrusted input unless you are very careful. + */ + operation_class->flags = VIPS_OPERATION_UNTRUSTED; + /* is_a() is not that quick ... lower the priority. */ foreign_class->priority = -50; diff --git a/libvips/foreign/niftisave.c b/libvips/foreign/niftisave.c index 65936c08..f899a79e 100644 --- a/libvips/foreign/niftisave.c +++ b/libvips/foreign/niftisave.c @@ -417,6 +417,7 @@ vips_foreign_save_nifti_class_init( VipsForeignSaveNiftiClass *class ) { GObjectClass *gobject_class = G_OBJECT_CLASS( class ); VipsObjectClass *object_class = (VipsObjectClass *) class; + VipsOperationClass *operation_class = VIPS_OPERATION_CLASS( class ); VipsForeignClass *foreign_class = (VipsForeignClass *) class; VipsForeignSaveClass *save_class = (VipsForeignSaveClass *) class; @@ -428,6 +429,11 @@ vips_foreign_save_nifti_class_init( VipsForeignSaveNiftiClass *class ) object_class->description = _( "save image to nifti file" ); object_class->build = vips_foreign_save_nifti_build; + /* nificlib has not been fuzzed, so should not be used with + * untrusted input unless you are very careful. + */ + operation_class->flags = VIPS_OPERATION_UNTRUSTED; + foreign_class->suffs = vips_foreign_nifti_suffs; save_class->saveable = VIPS_SAVEABLE_ANY; diff --git a/libvips/foreign/openexrload.c b/libvips/foreign/openexrload.c index 172b7734..e830ac1d 100644 --- a/libvips/foreign/openexrload.c +++ b/libvips/foreign/openexrload.c @@ -118,6 +118,7 @@ vips_foreign_load_openexr_class_init( VipsForeignLoadOpenexrClass *class ) { GObjectClass *gobject_class = G_OBJECT_CLASS( class ); VipsObjectClass *object_class = (VipsObjectClass *) class; + VipsOperationClass *operation_class = VIPS_OPERATION_CLASS( class ); VipsForeignClass *foreign_class = (VipsForeignClass *) class; VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; @@ -127,6 +128,10 @@ vips_foreign_load_openexr_class_init( VipsForeignLoadOpenexrClass *class ) object_class->nickname = "openexrload"; object_class->description = _( "load an OpenEXR image" ); + /* OpenEXR is fuzzed, but not by us. + */ + operation_class->flags |= VIPS_OPERATION_UNTRUSTED; + foreign_class->suffs = vips_foreign_openexr_suffs; /* We are fast at is_a(), so high priority. diff --git a/libvips/foreign/openslideload.c b/libvips/foreign/openslideload.c index 64a53776..c86d7dd4 100644 --- a/libvips/foreign/openslideload.c +++ b/libvips/foreign/openslideload.c @@ -1063,8 +1063,16 @@ vips_foreign_load_openslide_source_class_init( object_class->description = _( "load source with OpenSlide" ); object_class->build = vips_foreign_load_openslide_source_build; + /* libopenslide does not try to recover from errors, so it's not safe + * to cache. + */ operation_class->flags = VIPS_OPERATION_NOCACHE; + /* openslide has not been fuzzed and is largly unmaintained, so should + * not be used with untrusted input unless you are very careful. + */ + operation_class->flags |= VIPS_OPERATION_UNTRUSTED; + load_class->is_a_source = vips_foreign_load_openslide_source_is_a_source; diff --git a/libvips/foreign/popplerload.c b/libvips/foreign/popplerload.c index 5ec70f10..a9284518 100644 --- a/libvips/foreign/popplerload.c +++ b/libvips/foreign/popplerload.c @@ -188,7 +188,8 @@ vips_foreign_load_pdf_build( VipsObject *object ) pdf->stream = vips_g_input_stream_new_from_source( pdf->source ); if( !(pdf->doc = poppler_document_new_from_stream( pdf->stream, - vips_source_length( pdf->source ), pdf->password, NULL, &error )) ) { + vips_source_length( pdf->source ), pdf->password, + NULL, &error )) ) { vips_g_error( &error ); return( -1 ); } @@ -228,7 +229,8 @@ vips_foreign_load_pdf_get_page( VipsForeignLoadPdf *pdf, int page_no ) printf( "vips_foreign_load_pdf_get_page: %d\n", page_no ); #endif /*DEBUG*/ - if( !(pdf->page = poppler_document_get_page( pdf->doc, page_no )) ) { + if( !(pdf->page = + poppler_document_get_page( pdf->doc, page_no )) ) { vips_error( class->nickname, _( "unable to load page %d" ), page_no ); return( -1 ); diff --git a/libvips/foreign/ppmload.c b/libvips/foreign/ppmload.c index f94ad348..3c599a8e 100644 --- a/libvips/foreign/ppmload.c +++ b/libvips/foreign/ppmload.c @@ -736,6 +736,7 @@ vips_foreign_load_ppm_class_init( VipsForeignLoadPpmClass *class ) { GObjectClass *gobject_class = G_OBJECT_CLASS( class ); VipsObjectClass *object_class = (VipsObjectClass *) class; + VipsOperationClass *operation_class = VIPS_OPERATION_CLASS( class ); VipsForeignClass *foreign_class = (VipsForeignClass *) class; VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; @@ -747,6 +748,10 @@ vips_foreign_load_ppm_class_init( VipsForeignLoadPpmClass *class ) object_class->description = _( "load ppm base class" ); object_class->build = vips_foreign_load_ppm_build; + /* You're unlikely to want to use this on untrusted files. + */ + operation_class->flags |= VIPS_OPERATION_UNTRUSTED; + foreign_class->suffs = vips__ppm_suffs; /* We are fast at is_a(), so high priority. diff --git a/libvips/foreign/radload.c b/libvips/foreign/radload.c index 8e388a70..35f1e4ac 100644 --- a/libvips/foreign/radload.c +++ b/libvips/foreign/radload.c @@ -116,6 +116,7 @@ vips_foreign_load_rad_class_init( VipsForeignLoadRadClass *class ) { GObjectClass *gobject_class = G_OBJECT_CLASS( class ); VipsObjectClass *object_class = (VipsObjectClass *) class; + VipsOperationClass *operation_class = VIPS_OPERATION_CLASS( class ); VipsForeignClass *foreign_class = (VipsForeignClass *) class; VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; @@ -124,6 +125,10 @@ vips_foreign_load_rad_class_init( VipsForeignLoadRadClass *class ) object_class->nickname = "radload_base"; object_class->description = _( "load rad base class" ); + /* You're unlikely to want to use this on untrusted files. + */ + operation_class->flags |= VIPS_OPERATION_UNTRUSTED; + /* is_a() is not that quick ... lower the priority. */ foreign_class->priority = -50; diff --git a/libvips/foreign/rawload.c b/libvips/foreign/rawload.c index 4644569f..682d45c9 100644 --- a/libvips/foreign/rawload.c +++ b/libvips/foreign/rawload.c @@ -117,11 +117,16 @@ vips_foreign_load_raw_class_init( VipsForeignLoadRawClass *class ) { GObjectClass *gobject_class = G_OBJECT_CLASS( class ); VipsObjectClass *object_class = (VipsObjectClass *) class; + VipsOperationClass *operation_class = VIPS_OPERATION_CLASS( class ); VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; + /* You're unlikely to want to use this on untrusted files. + */ + operation_class->flags |= VIPS_OPERATION_UNTRUSTED; + object_class->nickname = "rawload"; object_class->description = _( "load raw data from a file" ); diff --git a/libvips/foreign/svgload.c b/libvips/foreign/svgload.c index 68d88f65..fd6fd3a0 100644 --- a/libvips/foreign/svgload.c +++ b/libvips/foreign/svgload.c @@ -504,6 +504,7 @@ vips_foreign_load_svg_class_init( VipsForeignLoadSvgClass *class ) { GObjectClass *gobject_class = G_OBJECT_CLASS( class ); VipsObjectClass *object_class = (VipsObjectClass *) class; + VipsOperationClass *operation_class = VIPS_OPERATION_CLASS( class ); VipsForeignClass *foreign_class = (VipsForeignClass *) class; VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; @@ -514,6 +515,11 @@ vips_foreign_load_svg_class_init( VipsForeignLoadSvgClass *class ) object_class->nickname = "svgload_base"; object_class->description = _( "load SVG with rsvg" ); + /* librsvg has not been fuzzed, so should not be used with + * untrusted input unless you are very careful. + */ + operation_class->flags = VIPS_OPERATION_UNTRUSTED; + /* is_a() is not that quick ... lower the priority. */ foreign_class->priority = -5; diff --git a/libvips/foreign/vips2magick.c b/libvips/foreign/vips2magick.c index 13332e3e..96cdcf6c 100644 --- a/libvips/foreign/vips2magick.c +++ b/libvips/foreign/vips2magick.c @@ -439,6 +439,7 @@ vips_foreign_save_magick_class_init( VipsForeignSaveMagickClass *class ) { GObjectClass *gobject_class = G_OBJECT_CLASS( class ); VipsObjectClass *object_class = (VipsObjectClass *) class; + VipsOperationClass *operation_class = (VipsOperationClass *) class; VipsForeignClass *foreign_class = (VipsForeignClass *) class; VipsForeignSaveClass *save_class = (VipsForeignSaveClass *) class; @@ -450,6 +451,11 @@ vips_foreign_save_magick_class_init( VipsForeignSaveMagickClass *class ) object_class->description = _( "save with ImageMagick" ); object_class->build = vips_foreign_save_magick_build; + /* *magick is fuzzed, but it's such a huge thing it's safer to + * disable it. + */ + operation_class->flags = VIPS_OPERATION_UNTRUSTED; + /* We need to be well to the back of the queue since vips's * dedicated savers are usually preferable. */ diff --git a/libvips/foreign/vipsload.c b/libvips/foreign/vipsload.c index bd662866..95fbbccd 100644 --- a/libvips/foreign/vipsload.c +++ b/libvips/foreign/vipsload.c @@ -145,6 +145,7 @@ vips_foreign_load_vips_class_init( VipsForeignLoadVipsClass *class ) { GObjectClass *gobject_class = G_OBJECT_CLASS( class ); VipsObjectClass *object_class = (VipsObjectClass *) class; + VipsOperationClass *operation_class = VIPS_OPERATION_CLASS( class ); VipsForeignClass *foreign_class = (VipsForeignClass *) class; VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; @@ -153,6 +154,10 @@ vips_foreign_load_vips_class_init( VipsForeignLoadVipsClass *class ) object_class->nickname = "vipsload_base"; object_class->description = _( "load vips base class" ); + /* You're unlikely to want to use this on untrusted files. + */ + operation_class->flags |= VIPS_OPERATION_UNTRUSTED; + /* We are fast at is_a(), so high priority. */ foreign_class->priority = 200; diff --git a/libvips/include/vips/internal.h b/libvips/include/vips/internal.h index bcb3a790..f8d01835 100644 --- a/libvips/include/vips/internal.h +++ b/libvips/include/vips/internal.h @@ -125,10 +125,6 @@ extern int vips__leak; */ extern int vips__progress; -/* Leak check on exit. - */ -extern int vips__leak; - /* Show info messages. Handy for debugging. */ extern int vips__info; diff --git a/libvips/include/vips/operation.h b/libvips/include/vips/operation.h index 251652bc..7ddbdfc0 100644 --- a/libvips/include/vips/operation.h +++ b/libvips/include/vips/operation.h @@ -46,7 +46,9 @@ typedef enum /*< flags >*/ { VIPS_OPERATION_SEQUENTIAL = 1, VIPS_OPERATION_SEQUENTIAL_UNBUFFERED = 2, VIPS_OPERATION_NOCACHE = 4, - VIPS_OPERATION_DEPRECATED = 8 + VIPS_OPERATION_DEPRECATED = 8, + VIPS_OPERATION_UNTRUSTED = 16, + VIPS_OPERATION_BLOCKED = 32 } VipsOperationFlags; #define VIPS_TYPE_OPERATION (vips_operation_get_type()) @@ -141,6 +143,8 @@ void vips_cache_set_trace( gboolean trace ); void vips_concurrency_set( int concurrency ); int vips_concurrency_get( void ); +void vips_operation_block_set( const char *name, gboolean state ); + #ifdef __cplusplus } #endif /*__cplusplus*/ diff --git a/libvips/include/vips/vips.h b/libvips/include/vips/vips.h index 45bb728d..a1efd2b4 100644 --- a/libvips/include/vips/vips.h +++ b/libvips/include/vips/vips.h @@ -181,7 +181,9 @@ void vips_thread_shutdown( void ); void vips_add_option_entries( GOptionGroup *option_group ); -extern void vips_leak_set( gboolean leak ); +void vips_leak_set( gboolean leak ); + +void vips_block_untrusted_set( gboolean state ); const char *vips_version_string( void ); int vips_version( int flag ); diff --git a/libvips/iofuncs/enumtypes.c b/libvips/iofuncs/enumtypes.c index a963c5c3..e2490669 100644 --- a/libvips/iofuncs/enumtypes.c +++ b/libvips/iofuncs/enumtypes.c @@ -972,6 +972,8 @@ vips_operation_flags_get_type( void ) {VIPS_OPERATION_SEQUENTIAL_UNBUFFERED, "VIPS_OPERATION_SEQUENTIAL_UNBUFFERED", "sequential-unbuffered"}, {VIPS_OPERATION_NOCACHE, "VIPS_OPERATION_NOCACHE", "nocache"}, {VIPS_OPERATION_DEPRECATED, "VIPS_OPERATION_DEPRECATED", "deprecated"}, + {VIPS_OPERATION_UNTRUSTED, "VIPS_OPERATION_UNTRUSTED", "untrusted"}, + {VIPS_OPERATION_BLOCKED, "VIPS_OPERATION_BLOCKED", "blocked"}, {0, NULL, NULL} }; diff --git a/libvips/iofuncs/init.c b/libvips/iofuncs/init.c index e2814ea4..dd560d0c 100644 --- a/libvips/iofuncs/init.c +++ b/libvips/iofuncs/init.c @@ -186,9 +186,6 @@ vips_get_prgname( void ) * VIPS_INIT: * @ARGV0: name of application * - * gtk-doc mistakenly tags this macro as deprecated for unknown reasons. It is - * *NOT* deprecated, please ignore the warning above. - * * VIPS_INIT() starts up the world of VIPS. You should call this on * program startup before using any other VIPS operations. If you do not call * VIPS_INIT(), VIPS will call it for you when you use your first VIPS @@ -647,8 +644,6 @@ vips_init( const char *argv0 ) g_quark_from_static_string( "vips-image-pixels" ); #endif /*DEBUG_LEAK*/ - done = TRUE; - /* If VIPS_WARNING is defined, suppress all warning messages from vips. * * Libraries should not call g_log_set_handler(), it is @@ -664,11 +659,18 @@ vips_init( const char *argv0 ) g_log_set_handler( G_LOG_DOMAIN, G_LOG_LEVEL_WARNING, empty_log_handler, NULL ); + /* Block any untrusted operations. This must come after plugin load. + */ + if( g_getenv( "VIPS_BLOCK_UNTRUSTED" ) ) + vips_block_untrusted_set( TRUE ); + /* Set a minimum stacksize, if we can. */ if( (vips_min_stack_size = g_getenv( "VIPS_MIN_STACK_SIZE" )) ) (void) set_stacksize( vips__parse_size( vips_min_stack_size ) ); + done = TRUE; + vips__thread_gate_stop( "init: startup" ); return( 0 ); @@ -1309,3 +1311,39 @@ vips__get_sizeof_vipsobject( void ) return( sizeof( VipsObject ) ); } +static void * +vips_block_untrusted_set_operation( VipsOperationClass *class, gboolean *state ) +{ + g_assert( VIPS_IS_OPERATION_CLASS( class ) ); + + if( class->flags & VIPS_OPERATION_UNTRUSTED ) + vips_operation_block_set( VIPS_OBJECT_CLASS( class )->nickname, + *state ); + + return( NULL ); +} + +/** + * vips_block_untrusted_set: + * @state: the block state to set + * + * Set the block state on all untrusted operations. + * + * |[ + * vips_block_untrusted_set( TRUE ); + * ]| + * + * Will block all untrusted operations from running. + * + * Use `vips -l` at the command-line to see the class hierarchy and which + * operations are marked as untrusted. + * + * Set the environment variable `VIPS_BLOCK_UNTRUSTED` to block all untrusted + * operations on vips_init(). + */ +void +vips_block_untrusted_set( gboolean state ) +{ + vips_class_map_all( g_type_from_name( "VipsOperation" ), + (VipsClassMapFn) vips_block_untrusted_set_operation, &state ); +} diff --git a/libvips/iofuncs/operation.c b/libvips/iofuncs/operation.c index 60731a72..5043fc22 100644 --- a/libvips/iofuncs/operation.c +++ b/libvips/iofuncs/operation.c @@ -171,6 +171,8 @@ * @VIPS_OPERATION_SEQUENTIAL: can work sequentially with a small buffer * @VIPS_OPERATION_NOCACHE: must not be cached * @VIPS_OPERATION_DEPRECATED: a compatibility thing + * @VIPS_OPERATION_UNTRUSTED: not hardened for untrusted input + * @VIPS_OPERATION_BLOCKED: prevent this operation from running * * Flags we associate with an operation. * @@ -193,6 +195,13 @@ * * @VIPS_OPERATION_DEPRECATED means this is an old operation kept in vips for * compatibility only and should be hidden from users. + * + * @VIPS_OPERATION_UNTRUSTED means the operation depends on external libraries which have + * not been hardened against attack. It should probably not be used on untrusted input. + * Use vips_operation_block_untrusted() to block all untrusted operations. + * + * @VIPS_OPERATION_BLOCKED means the operation is prevented from executing. Use + * vips_operation_block_set() to enable and disable groups of operations. */ /* Abstract base class for operations. @@ -531,6 +540,30 @@ vips_operation_vips_operation_print_summary_arg( VipsObject *object, return( NULL ); } +static int +vips_operation_build( VipsObject *object ) +{ + VipsOperationClass *class = VIPS_OPERATION_GET_CLASS( object ); + +#ifdef VIPS_DEBUG + printf( "vips_operation_build: " ); + vips_object_print_name( object ); + printf( "\n" ); +#endif /*VIPS_DEBUG*/ + + if( class->flags & VIPS_OPERATION_BLOCKED ) { + vips_error( VIPS_OBJECT_CLASS( class )->nickname, + "%s", _( "operation is blocked" ) ); + return( -1 ); + } + + if( VIPS_OBJECT_CLASS( vips_operation_parent_class )-> + build( object ) ) + return( -1 ); + + return( 0 ); +} + static void vips_operation_summary( VipsObject *object, VipsBuf *buf ) { @@ -564,10 +597,11 @@ vips_operation_class_init( VipsOperationClass *class ) gobject_class->finalize = vips_operation_finalize; gobject_class->dispose = vips_operation_dispose; - vobject_class->nickname = "operation"; - vobject_class->description = _( "operations" ); + vobject_class->build = vips_operation_build; vobject_class->summary = vips_operation_summary; vobject_class->dump = vips_operation_dump; + vobject_class->nickname = "operation"; + vobject_class->description = _( "operations" ); class->usage = vips_operation_usage; class->get_flags = vips_operation_real_get_flags; @@ -636,9 +670,8 @@ vips_operation_invalidate( VipsOperation *operation ) * Return a new #VipsOperation with the specified nickname. Useful for * language bindings. * - * You'll need to set - * any arguments and build the operation before you can use it. See - * vips_call() for a higher-level way to make new operations. + * You'll need to set any arguments and build the operation before you can use + * it. See vips_call() for a higher-level way to make new operations. * * Returns: (transfer full): the new operation. */ @@ -1393,3 +1426,57 @@ vips_call_argv( VipsOperation *operation, int argc, char **argv ) return( 0 ); } + +static void * +vips_operation_block_set_operation( VipsOperationClass *class, gboolean *state ) +{ + g_assert( VIPS_IS_OPERATION_CLASS( class ) ); + +#ifdef VIPS_DEBUG + if( ((class->flags & VIPS_OPERATION_BLOCKED) != 0) != *state ) + VIPS_DEBUG_MSG( "vips_operation_block_set_operation: " + "setting block state on %s = %d\n", + VIPS_OBJECT_CLASS( class )->nickname, *state ); +#endif + + if( state ) + class->flags |= VIPS_OPERATION_BLOCKED; + else + class->flags &= ~VIPS_OPERATION_BLOCKED; + + return( NULL ); +} + +/** + * vips_operation_block_set: + * @name: set block state at this point and below + * @state: the block state to set + * + * Set the block state on all operations in the libvips class hierarchy at + * @name and below. + * + * For example: + * + * |[ + * vips_operation_block_set( "load", TRUE ); + * vips_operation_block_set( "jpegload_base", FALSE ); + * ]| + * + * Will block all load operations, except JPEG. + * + * Use `vips -l` at the command-line to see the class hierarchy. + * + * This call does nothing if the named operation is not found. + * + * See also: vips_block_untrusted_set(). + */ +void +vips_operation_block_set( const char *name, gboolean state ) +{ + GType base; + + if( (base = vips_type_find( "VipsOperation", name )) ) + vips_class_map_all( base, + (VipsClassMapFn) vips_operation_block_set_operation, + &state ); +} diff --git a/test/test_formats.sh b/test/test_formats.sh index 4d7b8319..77497beb 100755 --- a/test/test_formats.sh +++ b/test/test_formats.sh @@ -207,3 +207,16 @@ if test_supported dzsave; then test_saver copy $image .dz test_saver copy $image .dz[container=zip] fi + +# test blocked and untrusted +if test_supported magicksave; then + printf "testing VIPS_BLOCK_UNTRUSTED with imagemagick ... " + export VIPS_BLOCK_UNTRUSTED=1 + if vips magicksave $matlab $tmp/block.png; then + echo "failed to block imagemagick" + exit 1 + fi + echo "ok" + unset VIPS_BLOCK_UNTRUSTED +fi +