180 lines
6.5 KiB
Diff
180 lines
6.5 KiB
Diff
|
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
|
||
|
---
|
||
|
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 <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,63 @@ _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.
|
||
|
+ * 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 *
|
||
|
}
|
||
|
|
||
|
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
|
||
|
}
|
||
|
|
||
|
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,22 +184,27 @@ 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 ();
|
||
|
- 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);
|
||
|
+ 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 "
|
||
|
+ "or unix:path=$FILE; %s", g_address);
|
||
|
+
|
||
|
}
|
||
|
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) {
|
||
|
@@ -161,7 +214,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
|
||
|
|