mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2024-12-24 14:36:13 +01:00
gmenuexporter: Fix a NULL pointer dereference on an error handling path
This latent bug wasn’t triggered until commit3f30ec86c
(or its cherry-pick onto `glib-2-80`,747e3af99
, which was first released in 2.80.1). That change means that `g_menu_exporter_free()` is now called on the registration failure path by `g_dbus_connection_register_object()` before it returns. The caller then tries to call `g_slice_free()` on the exporter again. The call to `g_menu_exporter_free()` tries to dereference/free members of the exporter which it expects to be initialised — but because this is happening in an error handling path, they are not initialised. If it were to get any further, the `g_slice_free()` would then be a double-free on the exporter allocation. Fix that by making `g_menu_exporter_free()` robust to some of the exporter members being `NULL`, and moving some of the initialisation code higher in `g_dbus_connection_export_menu_model()`, and removing the duplicate free code on the error handling path. This includes a unit test. Signed-off-by: Philip Withnall <pwithnall@gnome.org> Fixes: #3366
This commit is contained in:
parent
34626188aa
commit
df2c5d925a
@ -707,11 +707,9 @@ g_menu_exporter_create_group (GMenuExporter *exporter)
|
||||
}
|
||||
|
||||
static void
|
||||
g_menu_exporter_free (gpointer user_data)
|
||||
g_menu_exporter_free (GMenuExporter *exporter)
|
||||
{
|
||||
GMenuExporter *exporter = user_data;
|
||||
|
||||
g_menu_exporter_menu_free (exporter->root);
|
||||
g_clear_pointer (&exporter->root, g_menu_exporter_menu_free);
|
||||
g_clear_pointer (&exporter->peer_remote, g_menu_exporter_remote_free);
|
||||
g_hash_table_unref (exporter->remotes);
|
||||
g_hash_table_unref (exporter->groups);
|
||||
@ -794,21 +792,16 @@ g_dbus_connection_export_menu_model (GDBusConnection *connection,
|
||||
guint id;
|
||||
|
||||
exporter = g_slice_new0 (GMenuExporter);
|
||||
|
||||
id = g_dbus_connection_register_object (connection, object_path, org_gtk_Menus_get_interface (),
|
||||
&vtable, exporter, g_menu_exporter_free, error);
|
||||
|
||||
if (id == 0)
|
||||
{
|
||||
g_slice_free (GMenuExporter, exporter);
|
||||
return 0;
|
||||
}
|
||||
|
||||
exporter->connection = g_object_ref (connection);
|
||||
exporter->object_path = g_strdup (object_path);
|
||||
exporter->groups = g_hash_table_new (NULL, NULL);
|
||||
exporter->remotes = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_menu_exporter_remote_free);
|
||||
exporter->root = g_menu_exporter_group_add_menu (g_menu_exporter_create_group (exporter), menu);
|
||||
|
||||
id = g_dbus_connection_register_object (connection, object_path, org_gtk_Menus_get_interface (),
|
||||
&vtable, exporter, (GDestroyNotify) g_menu_exporter_free, error);
|
||||
|
||||
if (id != 0)
|
||||
exporter->root = g_menu_exporter_group_add_menu (g_menu_exporter_create_group (exporter), menu);
|
||||
|
||||
return id;
|
||||
}
|
||||
|
@ -1159,6 +1159,42 @@ test_dbus_peer_subscriptions (void)
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
test_dbus_export_error_handling (void)
|
||||
{
|
||||
GRand *rand = NULL;
|
||||
RandomMenu *menu = NULL;
|
||||
GDBusConnection *bus;
|
||||
GError *local_error = NULL;
|
||||
guint id1, id2;
|
||||
|
||||
g_test_summary ("Test that error handling of menu model export failure works");
|
||||
g_test_bug ("https://gitlab.gnome.org/GNOME/glib/-/issues/3366");
|
||||
|
||||
bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
|
||||
|
||||
rand = g_rand_new_with_seed (g_test_rand_int ());
|
||||
menu = random_menu_new (rand, 2);
|
||||
|
||||
id1 = g_dbus_connection_export_menu_model (bus, "/", G_MENU_MODEL (menu), &local_error);
|
||||
g_assert_no_error (local_error);
|
||||
g_assert_cmpuint (id1, !=, 0);
|
||||
|
||||
/* Trigger a failure by trying to export on a path which is already in use */
|
||||
id2 = g_dbus_connection_export_menu_model (bus, "/", G_MENU_MODEL (menu), &local_error);
|
||||
g_assert_error (local_error, G_IO_ERROR, G_IO_ERROR_EXISTS);
|
||||
g_assert_cmpuint (id2, ==, 0);
|
||||
g_clear_error (&local_error);
|
||||
|
||||
g_dbus_connection_unexport_menu_model (bus, id1);
|
||||
|
||||
while (g_main_context_iteration (NULL, FALSE));
|
||||
|
||||
g_clear_object (&menu);
|
||||
g_rand_free (rand);
|
||||
g_clear_object (&bus);
|
||||
}
|
||||
|
||||
static gpointer
|
||||
do_modify (gpointer data)
|
||||
{
|
||||
@ -1658,6 +1694,7 @@ main (int argc, char **argv)
|
||||
g_test_add_func ("/gmenu/dbus/threaded", test_dbus_threaded);
|
||||
g_test_add_func ("/gmenu/dbus/peer/roundtrip", test_dbus_peer_roundtrip);
|
||||
g_test_add_func ("/gmenu/dbus/peer/subscriptions", test_dbus_peer_subscriptions);
|
||||
g_test_add_func ("/gmenu/dbus/export/error-handling", test_dbus_export_error_handling);
|
||||
g_test_add_func ("/gmenu/attributes", test_attributes);
|
||||
g_test_add_func ("/gmenu/attributes/iterate", test_attribute_iter);
|
||||
g_test_add_func ("/gmenu/links", test_links);
|
||||
|
Loading…
Reference in New Issue
Block a user