Skip to content
Permalink
Browse files

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
  • Loading branch information...
fujiwarat committed Sep 13, 2019
1 parent 48a8d7e commit 3d442dbf936d197aa11ca0a71663c2bc61696151
Showing with 73 additions and 16 deletions.
  1. +73 −16 bus/server.c
@@ -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
@@ -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);

1 comment on commit 3d442db

@kirotawa

This comment has been minimized.

Copy link

commented on 3d442db Sep 23, 2019

Seems that this fix caused a regression https://bugs.launchpad.net/ubuntu/+source/ibus/+bug/1844853

Please sign in to comment.
You can’t perform that action at this time.