Add a way to disable less well tested operations (#2636)

* quick proposal

warn on startup if untrusted operations might run

use vips_block_untrusted_set() to block untrusted operations, set an env
var or make a file to stop the warning

* mark fits, nifti and svg as untrusted

* remove the annoying "untrusted" warning message

better to warn on the download page

leave vips_block_untrusted_set() since it's obviously useful

* separate UNTRUSTED and BLOCKED

* typos

* add VIPS_BLOCK_UNTRUSTED env var

* move BLOCK_UNTRUSTED after plugin load

obviously, ooops

* add a test, disable *magick

although *magick is fuzzed, it's probably safer to disable it in
untrusted environments

* mark some more operations as untrusted
This commit is contained in:
John Cupitt 2022-04-11 11:32:32 +01:00 committed by GitHub
parent 6eae6fcf4b
commit eba9ec0dd7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
30 changed files with 285 additions and 22 deletions

View File

@ -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]

View File

@ -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.

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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.
*/

View File

@ -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.
*/

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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.

View File

@ -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;

View File

@ -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 );

View File

@ -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.

View File

@ -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;

View File

@ -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" );

View File

@ -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;

View File

@ -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.
*/

View File

@ -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;

View File

@ -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;

View File

@ -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*/

View File

@ -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 );

View File

@ -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}
};

View File

@ -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 );
}

View File

@ -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 );
}

View File

@ -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