From 3d442dbf936d197aa11ca0a71663c2bc61696151 Mon Sep 17 00:00:00 2001 From: fujiwarat <takao.fujiwara1@gmail.com> 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 --- (daviddavid) Rebase for 1.5.16 --- bus/server.c | 89 ++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 73 insertions(+), 16 deletions(-) diff -Nrup a/bus/server.c b/bus/server.c --- a/bus/server.c 2017-05-15 09:14:44.000000000 +0200 +++ b/bus/server.c 2019-09-13 13:45:59.767014140 +0200 @@ -2,7 +2,8 @@ /* vim:set et sts=4: */ /* bus - The Input Bus * Copyright (C) 2008-2010 Peng Huang <shawn.p.huang@gmail.com> - * Copyright (C) 2008-2010 Red Hat, Inc. + * Copyright (C) 2011-2019 Takao Fujiwara <takao.fujiwara1@gmail.com> + * 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 @@ -70,16 +71,62 @@ _restart_server (void) } /** + * 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. */ 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); @@ -97,14 +144,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_error ("Your socket address does not have the format unix:tmpdir=$DIR; %s", g_address); @@ -112,7 +162,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) { @@ -122,7 +172,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);