introspect: Split out DBusSenderChecker

Restricting callers to a list of allowed senders is useful for
other D-Bus services as well, so split out the existing code
into a reusable class.

https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/3943

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1970>
This commit is contained in:
Florian Müllner 2021-06-16 19:09:42 +02:00 committed by Marge Bot
parent d474781325
commit 2a3e297218
2 changed files with 60 additions and 27 deletions

View File

@ -9,6 +9,7 @@ const APP_ALLOWLIST = [
const INTROSPECT_DBUS_API_VERSION = 3; const INTROSPECT_DBUS_API_VERSION = 3;
const { loadInterfaceXML } = imports.misc.fileUtils; const { loadInterfaceXML } = imports.misc.fileUtils;
const { DBusSenderChecker } = imports.misc.util;
const IntrospectDBusIface = loadInterfaceXML('org.gnome.Shell.Introspect'); const IntrospectDBusIface = loadInterfaceXML('org.gnome.Shell.Introspect');
@ -43,14 +44,7 @@ var IntrospectService = class {
this._syncRunningApplications(); this._syncRunningApplications();
this._allowlistMap = new Map(); this._senderChecker = new DBusSenderChecker(APP_ALLOWLIST);
APP_ALLOWLIST.forEach(appName => {
Gio.DBus.watch_name(Gio.BusType.SESSION,
appName,
Gio.BusNameWatcherFlags.NONE,
(conn, name, owner) => this._allowlistMap.set(name, owner),
(conn, name) => this._allowlistMap.delete(name));
});
this._settings = St.Settings.get(); this._settings = St.Settings.get();
this._settings.connect('notify::enable-animations', this._settings.connect('notify::enable-animations',
@ -67,10 +61,6 @@ var IntrospectService = class {
return app.get_windows().some(w => w.transient_for == null); return app.get_windows().some(w => w.transient_for == null);
} }
_isSenderAllowed(sender) {
return [...this._allowlistMap.values()].includes(sender);
}
_getSandboxedAppId(app) { _getSandboxedAppId(app) {
let ids = app.get_windows().map(w => w.get_sandboxed_app_id()); let ids = app.get_windows().map(w => w.get_sandboxed_app_id());
return ids.find(id => id != null); return ids.find(id => id != null);
@ -127,21 +117,9 @@ var IntrospectService = class {
type == Meta.WindowType.UTILITY; type == Meta.WindowType.UTILITY;
} }
_checkInvocation(invocation) {
if (global.context.unsafe_mode)
return;
if (this._isSenderAllowed(invocation.get_sender()))
return;
throw new GLib.Error(Gio.DBusError,
Gio.DBusError.ACCESS_DENIED,
'App introspection not allowed');
}
GetRunningApplicationsAsync(params, invocation) { GetRunningApplicationsAsync(params, invocation) {
try { try {
this._checkInvocation(invocation); this._senderChecker.checkInvocation(invocation);
} catch (e) { } catch (e) {
invocation.return_gerror(e); invocation.return_gerror(e);
return; return;
@ -156,7 +134,7 @@ var IntrospectService = class {
let windowsList = {}; let windowsList = {};
try { try {
this._checkInvocation(invocation); this._senderChecker.checkInvocation(invocation);
} catch (e) { } catch (e) {
invocation.return_gerror(e); invocation.return_gerror(e);
return; return;

View File

@ -1,7 +1,8 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported findUrls, spawn, spawnCommandLine, spawnApp, trySpawnCommandLine, /* exported findUrls, spawn, spawnCommandLine, spawnApp, trySpawnCommandLine,
formatTime, formatTimeSpan, createTimeLabel, insertSorted, formatTime, formatTimeSpan, createTimeLabel, insertSorted,
ensureActorVisibleInScrollView, wiggle, lerp, GNOMEversionCompare */ ensureActorVisibleInScrollView, wiggle, lerp, GNOMEversionCompare,
DBusSenderChecker */
const { Clutter, Gio, GLib, Shell, St, GnomeDesktop } = imports.gi; const { Clutter, Gio, GLib, Shell, St, GnomeDesktop } = imports.gi;
const Gettext = imports.gettext; const Gettext = imports.gettext;
@ -477,3 +478,57 @@ function GNOMEversionCompare(version1, version2) {
return 0; return 0;
} }
var DBusSenderChecker = class {
/**
* @param {string[]} allowList - list of allowed well-known names
*/
constructor(allowList) {
this._allowlistMap = new Map();
this._watchList = allowList.map(name => {
return Gio.DBus.watch_name(Gio.BusType.SESSION,
name,
Gio.BusNameWatcherFlags.NONE,
(conn_, name_, owner) => this._allowlistMap.set(name, owner),
() => this._allowlistMap.delete(name));
});
}
/**
* @param {string} sender - the bus name that invoked the checked method
* @returns {bool}
*/
_isSenderAllowed(sender) {
return [...this._allowlistMap.values()].includes(sender);
}
/**
* Check whether the bus name that invoked @invocation maps
* to an entry in the allow list.
*
* @throws
* @param {Gio.DBusMethodInvocation} invocation - the invocation
* @returns {void}
*/
checkInvocation(invocation) {
if (global.context.unsafe_mode)
return;
if (this._isSenderAllowed(invocation.get_sender()))
return;
throw new GLib.Error(Gio.DBusError,
Gio.DBusError.ACCESS_DENIED,
'%s is not allowed'.format(invocation.get_method_name()));
}
/**
* @returns {void}
*/
destroy() {
for (const id in this._watchList)
Gio.DBus.unwatch_name(id);
this._watchList = [];
}
};