From 4550fc1bfacd36e4d9c6f375b366c2e88885af46 Mon Sep 17 00:00:00 2001 From: Jehan Date: Tue, 24 Dec 2019 01:22:13 +0100 Subject: [PATCH] Issue #4392: Gimp Segmentation Fault triggered by Glib GParamSpec... ... property name validation. GLib tightened its GParamSpec name validation, as it used to only check that the first letter was a letter, which triggered this issue, though the crash could have also happened with the former lax rules too (commit 30e630c9df792cf36cdb1cceb3daefbde1dc898a). I opened a merge request in GLib to make the validation code into a public function. In the meantime, let's just copy-paste the validation code into ours and when a plug-in attempts to create a procedure with invalid parameter or return value names, GIMP will just output an error and refuse to install the procedure instead of crashing. See: https://gitlab.gnome.org/GNOME/glib/merge_requests/1302 --- app/plug-in/gimpplugin-message.c | 77 +++++++++++++++++++++++++++----- 1 file changed, 67 insertions(+), 10 deletions(-) diff --git a/app/plug-in/gimpplugin-message.c b/app/plug-in/gimpplugin-message.c index fd2abcd904..a397f83adb 100644 --- a/app/plug-in/gimpplugin-message.c +++ b/app/plug-in/gimpplugin-message.c @@ -76,6 +76,7 @@ static void gimp_plug_in_handle_proc_uninstall (GimpPlugIn *plug_in, static void gimp_plug_in_handle_extension_ack (GimpPlugIn *plug_in); static void gimp_plug_in_handle_has_init (GimpPlugIn *plug_in); +static gboolean gimp_plug_in_is_valid_property_name (const gchar *name); /* public functions */ @@ -861,22 +862,48 @@ gimp_plug_in_handle_proc_install (GimpPlugIn *plug_in, for (i = 0; i < proc_install->nparams; i++) { - GParamSpec *pspec = - gimp_pdb_compat_param_spec (plug_in->manager->gimp, - proc_install->params[i].type, - proc_install->params[i].name, - proc_install->params[i].description); + GParamSpec *pspec; + + if (! gimp_plug_in_is_valid_property_name (proc_install->params[i].name)) + { + gimp_message (plug_in->manager->gimp, NULL, GIMP_MESSAGE_ERROR, + "Plug-in \"%s\"\n(%s)\n" + "attempted to install procedure \"%s\" with " + "invalid parameter name \"%s\".", + gimp_object_get_name (plug_in), + gimp_file_get_utf8_name (plug_in->file), + canonical, proc_install->params[i].name); + g_object_unref (procedure); + return; + } + pspec = gimp_pdb_compat_param_spec (plug_in->manager->gimp, + proc_install->params[i].type, + proc_install->params[i].name, + proc_install->params[i].description); gimp_procedure_add_argument (procedure, pspec); } for (i = 0; i < proc_install->nreturn_vals; i++) { - GParamSpec *pspec = - gimp_pdb_compat_param_spec (plug_in->manager->gimp, - proc_install->return_vals[i].type, - proc_install->return_vals[i].name, - proc_install->return_vals[i].description); + GParamSpec *pspec; + + if (! gimp_plug_in_is_valid_property_name (proc_install->return_vals[i].name)) + { + gimp_message (plug_in->manager->gimp, NULL, GIMP_MESSAGE_ERROR, + "Plug-in \"%s\"\n(%s)\n" + "attempted to install procedure \"%s\" with " + "invalid return value name \"%s\".", + gimp_object_get_name (plug_in), + gimp_file_get_utf8_name (plug_in->file), + canonical, proc_install->return_vals[i].name); + g_object_unref (procedure); + return; + } + pspec = gimp_pdb_compat_param_spec (plug_in->manager->gimp, + proc_install->return_vals[i].type, + proc_install->return_vals[i].name, + proc_install->return_vals[i].description); gimp_procedure_add_return_value (procedure, pspec); } @@ -979,3 +1006,33 @@ gimp_plug_in_handle_has_init (GimpPlugIn *plug_in) gimp_plug_in_close (plug_in, TRUE); } } + +/* + * XXX: this function should be removed when/if it becomes public in + * glib, i.e. when this patch is merged: + * https://gitlab.gnome.org/GNOME/glib/merge_requests/1302 + * See #4392. + */ +static gboolean +gimp_plug_in_is_valid_property_name (const gchar *name) +{ + const gchar *p; + + /* First character must be a letter. */ + if ((name[0] < 'A' || name[0] > 'Z') && + (name[0] < 'a' || name[0] > 'z')) + return FALSE; + + for (p = name; *p != 0; p++) + { + const gchar c = *p; + + if (c != '-' && c != '_' && + (c < '0' || c > '9') && + (c < 'A' || c > 'Z') && + (c < 'a' || c > 'z')) + return FALSE; + } + + return TRUE; +}