backends: Add D-Bus access control helper

Track unique DBus senders and allow only thse which own a (at least so far)
pre-defined set of well known DBus names.

Carlos Garnacho: Renamed to a more generic helper, use g_bus_watch_name().

Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/4217>
This commit is contained in:
Lukáš Tyrychtr 2025-02-10 16:26:49 +01:00 committed by Marge Bot
parent 20c9b8cf0c
commit 1c34794b13
6 changed files with 296 additions and 0 deletions

View File

@ -21,6 +21,7 @@
#include "config.h" #include "config.h"
#include "backends/meta-a11y-manager.h" #include "backends/meta-a11y-manager.h"
#include "backends/meta-dbus-access-checker.h"
#include "meta/meta-backend.h" #include "meta/meta-backend.h"
#include "meta/meta-context.h" #include "meta/meta-context.h"
#include "meta/util.h" #include "meta/util.h"
@ -78,6 +79,8 @@ typedef struct _MetaA11yManager
GList *key_grabbers; GList *key_grabbers;
GHashTable *grabbed_keypresses; GHashTable *grabbed_keypresses;
GHashTable *all_grabbed_modifiers; GHashTable *all_grabbed_modifiers;
MetaDbusAccessChecker *access_checker;
} MetaA11yManager; } MetaA11yManager;
G_DEFINE_TYPE (MetaA11yManager, meta_a11y_manager, G_TYPE_OBJECT) G_DEFINE_TYPE (MetaA11yManager, meta_a11y_manager, G_TYPE_OBJECT)
@ -182,6 +185,28 @@ ensure_key_grabber (MetaA11yManager *a11y_manager,
return grabber; return grabber;
} }
static gboolean
check_access (GDBusInterfaceSkeleton *skeleton,
GDBusMethodInvocation *invocation,
gpointer user_data)
{
MetaA11yManager *a11y_manager = META_A11Y_MANAGER (user_data);
const char *sender =
g_dbus_method_invocation_get_sender (invocation);
if (!meta_dbus_access_checker_is_sender_allowed (a11y_manager->access_checker,
sender))
{
g_dbus_method_invocation_return_error (invocation,
G_DBUS_ERROR,
G_DBUS_ERROR_ACCESS_DENIED,
"Access denied");
return FALSE;
}
return TRUE;
}
static gboolean static gboolean
handle_grab_keyboard (MetaDBusKeyboardMonitor *skeleton, handle_grab_keyboard (MetaDBusKeyboardMonitor *skeleton,
GDBusMethodInvocation *invocation, GDBusMethodInvocation *invocation,
@ -279,9 +304,12 @@ on_bus_acquired (GDBusConnection *connection,
gpointer user_data) gpointer user_data)
{ {
MetaA11yManager *manager = user_data; MetaA11yManager *manager = user_data;
MetaContext *context = meta_backend_get_context (manager->backend);
manager->keyboard_monitor_skeleton = meta_dbus_keyboard_monitor_skeleton_new (); manager->keyboard_monitor_skeleton = meta_dbus_keyboard_monitor_skeleton_new ();
g_signal_connect (manager->keyboard_monitor_skeleton, "g-authorize-method",
G_CALLBACK (check_access), manager);
g_signal_connect (manager->keyboard_monitor_skeleton, "handle-grab-keyboard", g_signal_connect (manager->keyboard_monitor_skeleton, "handle-grab-keyboard",
G_CALLBACK (handle_grab_keyboard), manager); G_CALLBACK (handle_grab_keyboard), manager);
g_signal_connect (manager->keyboard_monitor_skeleton, "handle-ungrab-keyboard", g_signal_connect (manager->keyboard_monitor_skeleton, "handle-ungrab-keyboard",
@ -297,6 +325,10 @@ on_bus_acquired (GDBusConnection *connection,
connection, connection,
"/org/freedesktop/a11y/Manager", "/org/freedesktop/a11y/Manager",
NULL); NULL);
manager->access_checker = meta_dbus_access_checker_new (connection, context);
meta_dbus_access_checker_allow_sender (manager->access_checker,
"org.gnome.Orca.KeyboardMonitor");
} }
static void static void
@ -323,6 +355,7 @@ meta_a11y_manager_finalize (GObject *object)
g_list_free_full (a11y_manager->key_grabbers, g_list_free_full (a11y_manager->key_grabbers,
(GDestroyNotify) key_grabber_free); (GDestroyNotify) key_grabber_free);
g_clear_object (&a11y_manager->keyboard_monitor_skeleton); g_clear_object (&a11y_manager->keyboard_monitor_skeleton);
g_clear_object (&a11y_manager->access_checker);
g_clear_pointer (&a11y_manager->grabbed_keypresses, g_hash_table_destroy); g_clear_pointer (&a11y_manager->grabbed_keypresses, g_hash_table_destroy);
g_clear_pointer (&a11y_manager->all_grabbed_modifiers, g_hash_table_destroy); g_clear_pointer (&a11y_manager->all_grabbed_modifiers, g_hash_table_destroy);
g_bus_unown_name (a11y_manager->dbus_name_id); g_bus_unown_name (a11y_manager->dbus_name_id);

View File

@ -0,0 +1,212 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright 2024 GNOME Foundation
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*
*/
#include "config.h"
#include "meta-dbus-access-checker.h"
#include "core/meta-context-private.h"
enum
{
PROP_0,
PROP_CONNECTION,
PROP_CONTEXT,
N_PROPS
};
static GParamSpec *props[N_PROPS];
typedef struct _AllowedSender AllowedSender;
struct _AllowedSender
{
char *name;
char *name_owner;
guint watch_id;
};
struct _MetaDbusAccessChecker
{
GObject parent_instance;
GDBusConnection *connection;
GPtrArray *allowed_senders;
MetaContext *context;
};
G_DEFINE_TYPE (MetaDbusAccessChecker, meta_dbus_access_checker, G_TYPE_OBJECT)
static void
name_appeared_cb (GDBusConnection *connection,
const char *name,
const char *name_owner,
gpointer user_data)
{
AllowedSender *allowed_sender = user_data;
allowed_sender->name_owner = g_strdup (name_owner);
}
static void
name_vanished_cb (GDBusConnection *connection,
const char *name,
gpointer user_data)
{
AllowedSender *allowed_sender = user_data;
g_clear_pointer (&allowed_sender->name_owner, g_free);
}
static AllowedSender *
allowed_sender_new (MetaDbusAccessChecker *self,
const char *name)
{
AllowedSender *allowed_sender;
allowed_sender = g_new0 (AllowedSender, 1);
allowed_sender->name = g_strdup (name);
allowed_sender->watch_id =
g_bus_watch_name_on_connection (self->connection,
name,
G_BUS_NAME_WATCHER_FLAGS_NONE,
name_appeared_cb,
name_vanished_cb,
allowed_sender,
NULL);
return allowed_sender;
}
static void
allowed_sender_free (AllowedSender *allowed_sender)
{
g_clear_pointer (&allowed_sender->name, g_free);
g_clear_pointer (&allowed_sender->name_owner, g_free);
g_bus_unwatch_name (allowed_sender->watch_id);
g_free (allowed_sender);
}
static void
meta_dbus_access_checker_init (MetaDbusAccessChecker *self)
{
self->allowed_senders =
g_ptr_array_new_with_free_func ((GDestroyNotify) allowed_sender_free);
}
static void
meta_dbus_access_checker_finalize (GObject *object)
{
MetaDbusAccessChecker *self =
META_DBUS_ACCESS_CHECKER (object);
g_clear_pointer (&self->allowed_senders, g_ptr_array_unref);
g_clear_object (&self->connection);
G_OBJECT_CLASS (meta_dbus_access_checker_parent_class)->finalize (object);
}
static void
meta_dbus_access_checker_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
MetaDbusAccessChecker *self = META_DBUS_ACCESS_CHECKER (object);
switch (prop_id)
{
case PROP_CONNECTION:
self->connection = g_value_dup_object (value);
break;
case PROP_CONTEXT:
self->context = g_value_get_object (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
meta_dbus_access_checker_class_init (MetaDbusAccessCheckerClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = meta_dbus_access_checker_finalize;
object_class->set_property = meta_dbus_access_checker_set_property;
props[PROP_CONNECTION] =
g_param_spec_object ("connection", NULL, NULL,
G_TYPE_DBUS_CONNECTION,
G_PARAM_WRITABLE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS);
props[PROP_CONTEXT] =
g_param_spec_object ("context", NULL, NULL,
META_TYPE_CONTEXT,
G_PARAM_WRITABLE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (object_class, N_PROPS, props);
}
MetaDbusAccessChecker *
meta_dbus_access_checker_new (GDBusConnection *connection,
MetaContext *context)
{
return g_object_new (META_TYPE_DBUS_ACCESS_CHECKER,
"connection", connection,
"context", context,
NULL);
}
void
meta_dbus_access_checker_allow_sender (MetaDbusAccessChecker *self,
const char *name)
{
AllowedSender *allowed_sender;
allowed_sender = allowed_sender_new (self, name);
g_ptr_array_add (self->allowed_senders, allowed_sender);
}
gboolean
meta_dbus_access_checker_is_sender_allowed (MetaDbusAccessChecker *self,
const char *sender_name)
{
int i;
if (meta_context_get_unsafe_mode (self->context))
return TRUE;
for (i = 0; i < self->allowed_senders->len; i++)
{
AllowedSender *allowed_sender;
allowed_sender = g_ptr_array_index (self->allowed_senders, i);
if (sender_name &&
g_strcmp0 (allowed_sender->name_owner, sender_name) == 0)
return TRUE;
}
return FALSE;
}

View File

@ -0,0 +1,39 @@
/*
* Copyright 2024 GNOME Foundation
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*
*/
#pragma once
#include <glib-object.h>
#include <gio/gio.h>
#include "meta/meta-context.h"
#define META_TYPE_DBUS_ACCESS_CHECKER (meta_dbus_access_checker_get_type())
G_DECLARE_FINAL_TYPE (MetaDbusAccessChecker,
meta_dbus_access_checker,
META, DBUS_ACCESS_CHECKER,
GObject)
MetaDbusAccessChecker * meta_dbus_access_checker_new (GDBusConnection *connection,
MetaContext *context);
void meta_dbus_access_checker_allow_sender (MetaDbusAccessChecker *self,
const char *name);
gboolean meta_dbus_access_checker_is_sender_allowed (MetaDbusAccessChecker *self,
const char *sender_name);

View File

@ -70,6 +70,8 @@ const char * meta_context_get_gnome_wm_keybindings (MetaContext *context);
void meta_context_set_unsafe_mode (MetaContext *context, void meta_context_set_unsafe_mode (MetaContext *context,
gboolean enable); gboolean enable);
gboolean meta_context_get_unsafe_mode (MetaContext *context);
#ifdef HAVE_WAYLAND #ifdef HAVE_WAYLAND
META_EXPORT_TEST META_EXPORT_TEST
MetaServiceChannel * meta_context_get_service_channel (MetaContext *context); MetaServiceChannel * meta_context_get_service_channel (MetaContext *context);

View File

@ -620,6 +620,14 @@ meta_context_destroy (MetaContext *context)
g_object_unref (context); g_object_unref (context);
} }
gboolean
meta_context_get_unsafe_mode (MetaContext *context)
{
MetaContextPrivate *priv = meta_context_get_instance_private (context);
return priv->unsafe_mode;
}
void void
meta_context_set_unsafe_mode (MetaContext *context, meta_context_set_unsafe_mode (MetaContext *context,
gboolean enable) gboolean enable)

View File

@ -213,6 +213,8 @@ mutter_sources = [
'backends/meta-cursor-sprite-xcursor.h', 'backends/meta-cursor-sprite-xcursor.h',
'backends/meta-cursor-tracker.c', 'backends/meta-cursor-tracker.c',
'backends/meta-cursor-tracker-private.h', 'backends/meta-cursor-tracker-private.h',
'backends/meta-dbus-access-checker.c',
'backends/meta-dbus-access-checker.h',
'backends/meta-dbus-session-manager.c', 'backends/meta-dbus-session-manager.c',
'backends/meta-dbus-session-manager.h', 'backends/meta-dbus-session-manager.h',
'backends/meta-dbus-session-watcher.c', 'backends/meta-dbus-session-watcher.c',