diff --git a/ibus-CVE-2019-14822-GDBusServer-peer-authorization.patch b/ibus-CVE-2019-14822-GDBusServer-peer-authorization.patch new file mode 100644 index 0000000..6efb156 --- /dev/null +++ b/ibus-CVE-2019-14822-GDBusServer-peer-authorization.patch @@ -0,0 +1,471 @@ +From 3d442dbf936d197aa11ca0a71663c2bc61696151 Mon Sep 17 00:00:00 2001 +From: fujiwarat +Date: Fri, 13 Sep 2019 15:59:03 +0900 +Subject: [PATCH] bus: Implement GDBusAuthObserver callback + +ibus uses a GDBusServer with G_DBUS_SERVER_FLAGS_AUTHENTICATION_ALLOW_ANONYMOUS, +and doesn't set a GDBusAuthObserver, which allows anyone who can connect +to its AF_UNIX socket to authenticate and be authorized to send method calls. +It also seems to use an abstract AF_UNIX socket, which does not have +filesystem permissions, so the practical effect might be that a local +attacker can connect to another user's ibus service and make arbitrary +method calls. + +BUGS=rhbz#1717958 +--- + bus/server.c | 89 ++++++++++++++++++++++++++++++++++++++++++---------- + 1 file changed, 73 insertions(+), 16 deletions(-) + +diff --git a/bus/server.c b/bus/server.c +index 3a626230..2439de14 100644 +--- a/bus/server.c ++++ b/bus/server.c +@@ -2,7 +2,8 @@ + /* vim:set et sts=4: */ + /* bus - The Input Bus + * Copyright (C) 2008-2010 Peng Huang +- * Copyright (C) 2008-2010 Red Hat, Inc. ++ * Copyright (C) 2011-2019 Takao Fujiwara ++ * Copyright (C) 2008-2019 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public +@@ -69,17 +70,64 @@ _restart_server (void) + exit (-1); + } + ++/** ++ * bus_allow_mechanism_cb: ++ * @observer: A #GDBusAuthObserver. ++ * @mechanism: The name of the mechanism. ++ * @user_data: always %NULL. ++ * ++ * Check if @mechanism can be used to authenticate the other peer. ++ * Returns: %TRUE if the peer's mechanism is allowed. ++ */ ++static gboolean ++bus_allow_mechanism_cb (GDBusAuthObserver *observer, ++ const gchar *mechanism, ++ G_GNUC_UNUSED gpointer user_data) ++{ ++ if (g_strcmp0 (mechanism, "EXTERNAL") == 0) ++ return TRUE; ++ return FALSE; ++} ++ ++/** ++ * bus_authorize_authenticated_peer_cb: ++ * @observer: A #GDBusAuthObserver. ++ * @stream: A #GIOStream. ++ * @credentials: A #GCredentials. ++ * @user_data: always %NULL. ++ * ++ * Check if a peer who has already authenticated should be authorized. ++ * Returns: %TRUE if the peer's credential is authorized. ++ */ ++static gboolean ++bus_authorize_authenticated_peer_cb (GDBusAuthObserver *observer, ++ GIOStream *stream, ++ GCredentials *credentials, ++ G_GNUC_UNUSED gpointer user_data) ++{ ++ gboolean authorized = FALSE; ++ if (credentials) { ++ GCredentials *own_credentials = g_credentials_new (); ++ if (g_credentials_is_same_user (credentials, own_credentials, NULL)) ++ authorized = TRUE; ++ g_object_unref (own_credentials); ++ } ++ return authorized; ++} ++ + /** + * bus_new_connection_cb: +- * @user_data: always NULL. +- * @returns: TRUE when the function can handle the connection. ++ * @observer: A #GDBusAuthObserver. ++ * @dbus_connection: A #GDBusconnection. ++ * @user_data: always %NULL. + * + * Handle incoming connections. ++ * Returns: %TRUE when the function can handle the connection. + */ + static gboolean +-bus_new_connection_cb (GDBusServer *server, +- GDBusConnection *dbus_connection, +- gpointer user_data) ++bus_new_connection_cb (GDBusServer *server, ++ GDBusConnection *dbus_connection, ++ G_GNUC_UNUSED gpointer user_data) + { + BusConnection *connection = bus_connection_new (dbus_connection); + bus_dbus_impl_new_connection (dbus, connection); +@@ -94,9 +142,9 @@ bus_new_connection_cb (GDBusServer *server, + } + + static void +-_server_connect_start_portal_cb (GObject *source_object, +- GAsyncResult *res, +- gpointer user_data) ++_server_connect_start_portal_cb (GObject *source_object, ++ GAsyncResult *res, ++ G_GNUC_UNUSED gpointer user_data) + { + GVariant *result; + GError *error = NULL; +@@ -113,9 +161,9 @@ _server_connect_start_portal_cb (GObject *source_object, + } + + static void +-bus_acquired_handler (GDBusConnection *connection, +- const gchar *name, +- gpointer user_data) ++bus_acquired_handler (GDBusConnection *connection, ++ const gchar *name, ++ G_GNUC_UNUSED gpointer user_data) + { + g_dbus_connection_call (connection, + IBUS_SERVICE_PORTAL, +@@ -136,14 +184,17 @@ void + bus_server_init (void) + { + GError *error = NULL; ++ GDBusServerFlags flags = G_DBUS_SERVER_FLAGS_NONE; ++ gchar *guid; ++ GDBusAuthObserver *observer; + + dbus = bus_dbus_impl_get_default (); + ibus = bus_ibus_impl_get_default (); + bus_dbus_impl_register_object (dbus, (IBusService *)ibus); + + /* init server */ +- GDBusServerFlags flags = G_DBUS_SERVER_FLAGS_AUTHENTICATION_ALLOW_ANONYMOUS; +- gchar *guid = g_dbus_generate_guid (); ++ guid = g_dbus_generate_guid (); ++ observer = g_dbus_auth_observer_new (); + if (!g_str_has_prefix (g_address, "unix:tmpdir=") && + !g_str_has_prefix (g_address, "unix:path=")) { + g_error ("Your socket address does not have the format unix:tmpdir=$DIR " +@@ -152,7 +203,7 @@ bus_server_init (void) + server = g_dbus_server_new_sync ( + g_address, /* the place where the socket file lives, e.g. /tmp, abstract namespace, etc. */ + flags, guid, +- NULL /* observer */, ++ observer, + NULL /* cancellable */, + &error); + if (server == NULL) { +@@ -162,7 +213,13 @@ bus_server_init (void) + } + g_free (guid); + +- g_signal_connect (server, "new-connection", G_CALLBACK (bus_new_connection_cb), NULL); ++ g_signal_connect (observer, "allow-mechanism", ++ G_CALLBACK (bus_allow_mechanism_cb), NULL); ++ g_signal_connect (observer, "authorize-authenticated-peer", ++ G_CALLBACK (bus_authorize_authenticated_peer_cb), NULL); ++ g_object_unref (observer); ++ g_signal_connect (server, "new-connection", ++ G_CALLBACK (bus_new_connection_cb), NULL); + + g_dbus_server_start (server); + +-- +2.21.0 + + + +From 018a0f889d18c41e314f0b1297d1dc559603142b Mon Sep 17 00:00:00 2001 +From: fujiwarat +Date: Tue, 5 Feb 2019 18:36:04 +0900 +Subject: [PATCH] Fix SEGV in bus_panel_proxy_focus_in() + +rhbz#1349148, rhbz#1385349 +SEGV in BUS_IS_PANEL_PROXY() in bus_panel_proxy_focus_in() +Check if GDBusConnect is closed before bus_panel_proxy_new() is called. + +rhbz#1350291 SEGV in BUS_IS_CONNECTION(skip_connection) in +bus_dbus_impl_dispatch_message_by_rule() +check if dbus_connection is closed in bus_dbus_impl_connection_filter_cb(). + +rhbz#1406699 SEGV in new_owner!=NULL in bus_dbus_impl_name_owner_changed() +which is called by bus_name_service_remove_owner() +If bus_connection_get_unique_name()==NULL, set new_owner="" in +bus_name_service_remove_owner() + +rhbz#1432252 SEGV in old_owner!=NULL in bus_dbus_impl_name_owner_changed() +which is called by bus_name_service_set_primary_owner() +If bus_connection_get_unique_name()==NULL, set old_owner="" in +bus_name_service_set_primary_owner() + +rhbz#1601577 SEGV in ibus_engine_desc_get_layout() in +bus_engine_proxy_new_internal() +WIP: Added a GError to get the error message to check why the SEGV happened. + +rhbz#1663528 SEGV in g_mutex_clear() in bus_dbus_impl_destroy() +If the mutex is not unlocked, g_mutex_clear() causes assert. + +BUG=rhbz#1349148 +BUG=rhbz#1385349 +BUG=rhbz#1350291 +BUG=rhbz#1406699 +BUG=rhbz#1432252 +BUG=rhbz#1601577 +BUG=rhbz#1663528 +--- + bus/dbusimpl.c | 70 +++++++++++++++++++++++++++++++++++++++++------ + bus/engineproxy.c | 9 +++++- + bus/ibusimpl.c | 21 ++++++++++++-- + 3 files changed, 88 insertions(+), 12 deletions(-) + +diff --git a/bus/dbusimpl.c b/bus/dbusimpl.c +index b54ef817..fb38faf0 100644 +--- a/bus/dbusimpl.c ++++ b/bus/dbusimpl.c +@@ -2,7 +2,8 @@ + /* vim:set et sts=4: */ + /* ibus - The Input Bus + * Copyright (C) 2008-2013 Peng Huang +- * Copyright (C) 2008-2013 Red Hat, Inc. ++ * Copyright (C) 2015-2019 Takao Fujiwara ++ * Copyright (C) 2008-2019 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public +@@ -344,6 +345,8 @@ bus_name_service_set_primary_owner (BusNameService *service, + BusConnectionOwner *owner, + BusDBusImpl *dbus) + { ++ gboolean has_old_owner = FALSE; ++ + g_assert (service != NULL); + g_assert (owner != NULL); + g_assert (dbus != NULL); +@@ -351,6 +354,13 @@ bus_name_service_set_primary_owner (BusNameService *service, + BusConnectionOwner *old = service->owners != NULL ? + (BusConnectionOwner *)service->owners->data : NULL; + ++ /* rhbz#1432252 If bus_connection_get_unique_name() == NULL, ++ * "Hello" method is not received yet. ++ */ ++ if (old != NULL && bus_connection_get_unique_name (old->conn) != NULL) { ++ has_old_owner = TRUE; ++ } ++ + if (old != NULL) { + g_signal_emit (dbus, + dbus_signals[NAME_LOST], +@@ -370,7 +380,8 @@ bus_name_service_set_primary_owner (BusNameService *service, + 0, + owner->conn, + service->name, +- old != NULL ? bus_connection_get_unique_name (old->conn) : "", ++ has_old_owner ? bus_connection_get_unique_name (old->conn) : ++ "", + bus_connection_get_unique_name (owner->conn)); + + if (old != NULL && old->do_not_queue != 0) { +@@ -427,6 +438,7 @@ bus_name_service_remove_owner (BusNameService *service, + BusDBusImpl *dbus) + { + GSList *owners; ++ gboolean has_new_owner = FALSE; + + g_assert (service != NULL); + g_assert (owner != NULL); +@@ -439,6 +451,13 @@ bus_name_service_remove_owner (BusNameService *service, + BusConnectionOwner *_new = NULL; + if (owners->next != NULL) { + _new = (BusConnectionOwner *)owners->next->data; ++ /* rhbz#1406699 If bus_connection_get_unique_name() == NULL, ++ * "Hello" method is not received yet. ++ */ ++ if (_new != NULL && ++ bus_connection_get_unique_name (_new->conn) != NULL) { ++ has_new_owner = TRUE; ++ } + } + + if (dbus != NULL) { +@@ -447,7 +466,7 @@ bus_name_service_remove_owner (BusNameService *service, + 0, + owner->conn, + service->name); +- if (_new != NULL) { ++ if (has_new_owner) { + g_signal_emit (dbus, + dbus_signals[NAME_ACQUIRED], + 0, +@@ -460,7 +479,7 @@ bus_name_service_remove_owner (BusNameService *service, + _new != NULL ? _new->conn : NULL, + service->name, + bus_connection_get_unique_name (owner->conn), +- _new != NULL ? bus_connection_get_unique_name (_new->conn) : ""); ++ has_new_owner ? bus_connection_get_unique_name (_new->conn) : ""); + + } + } +@@ -591,6 +610,7 @@ static void + bus_dbus_impl_destroy (BusDBusImpl *dbus) + { + GList *p; ++ int i; + + for (p = dbus->objects; p != NULL; p = p->next) { + IBusService *object = (IBusService *) p->data; +@@ -628,12 +648,39 @@ bus_dbus_impl_destroy (BusDBusImpl *dbus) + dbus->unique_names = NULL; + dbus->names = NULL; + ++ for (i = 0; g_idle_remove_by_data (dbus); i++) { ++ if (i > 1000) { ++ g_warning ("Too many idle threads were generated by " \ ++ "bus_dbus_impl_forward_message_idle_cb and " \ ++ "bus_dbus_impl_dispatch_message_by_rule_idle_cb"); ++ break; ++ } ++ } + g_list_free_full (dbus->start_service_calls, + (GDestroyNotify) bus_method_call_free); + dbus->start_service_calls = NULL; + +- g_mutex_clear (&dbus->dispatch_lock); +- g_mutex_clear (&dbus->forward_lock); ++ /* rhbz#1663528 Call g_mutex_trylock() before g_mutex_clear() ++ * because if the mutex is not unlocked, g_mutex_clear() causes assert. ++ */ ++#define BUS_DBUS_MUTEX_SAFE_CLEAR(mtex) { \ ++ int count = 0; \ ++ while (!g_mutex_trylock ((mtex))) { \ ++ g_usleep (1); \ ++ if (count > 60) { \ ++ g_warning (#mtex " is dead lock"); \ ++ break; \ ++ } \ ++ ++count; \ ++ } \ ++ g_mutex_unlock ((mtex)); \ ++ g_mutex_clear ((mtex)); \ ++} ++ ++ BUS_DBUS_MUTEX_SAFE_CLEAR (&dbus->dispatch_lock); ++ BUS_DBUS_MUTEX_SAFE_CLEAR (&dbus->forward_lock); ++ ++#undef BUS_DBUS_MUTEX_SAFE_CLEAR + + /* FIXME destruct _lock and _queue members. */ + IBUS_OBJECT_CLASS(bus_dbus_impl_parent_class)->destroy ((IBusObject *) dbus); +@@ -1464,13 +1511,20 @@ bus_dbus_impl_connection_filter_cb (GDBusConnection *dbus_connection, + gboolean incoming, + gpointer user_data) + { ++ BusDBusImpl *dbus; ++ BusConnection *connection; ++ + g_assert (G_IS_DBUS_CONNECTION (dbus_connection)); + g_assert (G_IS_DBUS_MESSAGE (message)); + g_assert (BUS_IS_DBUS_IMPL (user_data)); + +- BusDBusImpl *dbus = (BusDBusImpl *) user_data; +- BusConnection *connection = bus_connection_lookup (dbus_connection); ++ if (g_dbus_connection_is_closed (dbus_connection)) ++ return NULL; ++ ++ dbus = (BusDBusImpl *) user_data; ++ connection = bus_connection_lookup (dbus_connection); + g_assert (connection != NULL); ++ g_assert (BUS_IS_CONNECTION (connection)); + + if (incoming) { + /* is incoming message */ +diff --git a/bus/engineproxy.c b/bus/engineproxy.c +index 2d98995c..2176e0c9 100644 +--- a/bus/engineproxy.c ++++ b/bus/engineproxy.c +@@ -665,6 +665,7 @@ bus_engine_proxy_new_internal (const gchar *path, + IBusEngineDesc *desc, + GDBusConnection *connection) + { ++ GError *error = NULL; + g_assert (path); + g_assert (IBUS_IS_ENGINE_DESC (desc)); + g_assert (G_IS_DBUS_CONNECTION (connection)); +@@ -673,7 +674,7 @@ bus_engine_proxy_new_internal (const gchar *path, + BusEngineProxy *engine = + (BusEngineProxy *) g_initable_new (BUS_TYPE_ENGINE_PROXY, + NULL, +- NULL, ++ &error, + "desc", desc, + "g-connection", connection, + "g-interface-name", IBUS_INTERFACE_ENGINE, +@@ -681,6 +682,12 @@ bus_engine_proxy_new_internal (const gchar *path, + "g-default-timeout", g_gdbus_timeout, + "g-flags", flags, + NULL); ++ /* FIXME: rhbz#1601577 */ ++ if (error) { ++ /* show abrt local variable */ ++ gchar *message = g_strdup (error->message); ++ g_error ("%s", message); ++ } + const gchar *layout = ibus_engine_desc_get_layout (desc); + if (layout != NULL && layout[0] != '\0') { + engine->keymap = ibus_keymap_get (layout); +diff --git a/bus/ibusimpl.c b/bus/ibusimpl.c +index bbbb5770..77fcf42f 100644 +--- a/bus/ibusimpl.c ++++ b/bus/ibusimpl.c +@@ -464,13 +464,16 @@ _dbus_name_owner_changed_cb (BusDBusImpl *dbus, + else if (!g_strcmp0 (name, IBUS_SERVICE_PANEL_EXTENSION_EMOJI)) + panel_type = PANEL_TYPE_EXTENSION_EMOJI; + +- if (panel_type != PANEL_TYPE_NONE) { ++ do { ++ if (panel_type == PANEL_TYPE_NONE) ++ break; + if (g_strcmp0 (new_name, "") != 0) { + /* a Panel process is started. */ + BusConnection *connection; + BusInputContext *context = NULL; + BusPanelProxy **panel = (panel_type == PANEL_TYPE_PANEL) ? + &ibus->panel : &ibus->emoji_extension; ++ GDBusConnection *dbus_connection = NULL; + + if (*panel != NULL) { + ibus_proxy_destroy ((IBusProxy *)(*panel)); +@@ -479,9 +482,21 @@ _dbus_name_owner_changed_cb (BusDBusImpl *dbus, + g_assert (*panel == NULL); + } + +- connection = bus_dbus_impl_get_connection_by_name (BUS_DEFAULT_DBUS, new_name); ++ connection = bus_dbus_impl_get_connection_by_name (BUS_DEFAULT_DBUS, ++ new_name); + g_return_if_fail (connection != NULL); + ++ dbus_connection = bus_connection_get_dbus_connection (connection); ++ /* rhbz#1349148 rhbz#1385349 ++ * Avoid SEGV of BUS_IS_PANEL_PROXY (ibus->panel) ++ * This function is called during destroying the connection ++ * in this case? */ ++ if (dbus_connection == NULL || ++ g_dbus_connection_is_closed (dbus_connection)) { ++ new_name = ""; ++ break; ++ } ++ + *panel = bus_panel_proxy_new (connection, panel_type); + if (panel_type == PANEL_TYPE_EXTENSION_EMOJI) + ibus->enable_emoji_extension = FALSE; +@@ -535,7 +550,7 @@ _dbus_name_owner_changed_cb (BusDBusImpl *dbus, + } + } + } +- } ++ } while (0); + + bus_ibus_impl_component_name_owner_changed (ibus, name, old_name, new_name); + } +-- +2.20.1 + diff --git a/ibus.changes b/ibus.changes index 447dc83..4661ec3 100644 --- a/ibus.changes +++ b/ibus.changes @@ -1,3 +1,9 @@ +------------------------------------------------------------------- +Tue Sep 17 21:51:08 UTC 2019 - Bjørn Lie + +- Add ibus-CVE-2019-14822-GDBusServer-peer-authorization.patch: + bus: Implement GDBusAuthObserver callback, fix CVE-2019-14822. + ------------------------------------------------------------------- Thu Sep 5 13:17:58 UTC 2019 - Fuminobu Takeyama diff --git a/ibus.spec b/ibus.spec index d5fde52..b2abe97 100644 --- a/ibus.spec +++ b/ibus.spec @@ -60,6 +60,9 @@ Patch11: setup-switch-im.patch # PATCH-FIX-SLE ibus-disable-engines-preload-in-GNOME.patch bnc#1036729 qzhao@suse.com # Disable ibus engines preload in GNOME for These works are handled by gnome-shell. Patch12: ibus-disable-engines-preload-in-GNOME.patch + +Patch13: ibus-CVE-2019-14822-GDBusServer-peer-authorization.patch + BuildRequires: dbus-1-glib-devel BuildRequires: dconf-devel >= 0.7.5 BuildRequires: fdupes @@ -190,6 +193,8 @@ cp -r %{SOURCE11} . %patch12 -p1 %endif +%patch13 -p1 + %build autoreconf -fi %configure --disable-static \