Blame SOURCES/restrict-dbus-callers.patch

c29f1c
From eb26ea5e1bb0c6fc978aae5db99ed3427b34175b Mon Sep 17 00:00:00 2001
c29f1c
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
c29f1c
Date: Fri, 1 Apr 2022 19:40:31 +0200
c29f1c
Subject: [PATCH 01/12] shell/global: Expose shim context property
c29f1c
c29f1c
Parts of the following commits rely on the ShellGlobal:context
c29f1c
property that was added in GNOME 41 to expose the MetaContext
c29f1c
(likewise a GNOME 41 addition).
c29f1c
c29f1c
To prepare for that, expose a small shim object as context
c29f1c
property that mimicks the expected upstream API.
c29f1c
---
c29f1c
 src/shell-global.c | 92 ++++++++++++++++++++++++++++++++++++++++++++++
c29f1c
 1 file changed, 92 insertions(+)
c29f1c
c29f1c
diff --git a/src/shell-global.c b/src/shell-global.c
c29f1c
index 24e771f52..805c73145 100644
c29f1c
--- a/src/shell-global.c
c29f1c
+++ b/src/shell-global.c
c29f1c
@@ -47,6 +47,9 @@
c29f1c
 
c29f1c
 static ShellGlobal *the_object = NULL;
c29f1c
 
c29f1c
+#define SHIM_TYPE_META_CONTEXT shim_meta_context_get_type ()
c29f1c
+G_DECLARE_FINAL_TYPE (ShimMetaContext, shim_meta_context, SHIM, META_CONTEXT, GObject)
c29f1c
+
c29f1c
 struct _ShellGlobal {
c29f1c
   GObject parent;
c29f1c
 
c29f1c
@@ -54,6 +57,7 @@ struct _ShellGlobal {
c29f1c
 
c29f1c
   MetaBackend *backend;
c29f1c
   MetaDisplay *meta_display;
c29f1c
+  ShimMetaContext *meta_context;
c29f1c
   MetaWorkspaceManager *workspace_manager;
c29f1c
   Display *xdisplay;
c29f1c
 
c29f1c
@@ -92,6 +96,7 @@ enum {
c29f1c
 
c29f1c
   PROP_SESSION_MODE,
c29f1c
   PROP_BACKEND,
c29f1c
+  PROP_CONTEXT,
c29f1c
   PROP_DISPLAY,
c29f1c
   PROP_WORKSPACE_MANAGER,
c29f1c
   PROP_SCREEN_WIDTH,
c29f1c
@@ -235,6 +240,9 @@ shell_global_get_property(GObject         *object,
c29f1c
     case PROP_BACKEND:
c29f1c
       g_value_set_object (value, global->backend);
c29f1c
       break;
c29f1c
+    case PROP_CONTEXT:
c29f1c
+      g_value_set_object (value, global->meta_context);
c29f1c
+      break;
c29f1c
     case PROP_DISPLAY:
c29f1c
       g_value_set_object (value, global->meta_display);
c29f1c
       break;
c29f1c
@@ -514,6 +522,13 @@ shell_global_class_init (ShellGlobalClass *klass)
c29f1c
                                                         "MetaBackend object",
c29f1c
                                                         META_TYPE_BACKEND,
c29f1c
                                                         G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
c29f1c
+  g_object_class_install_property (gobject_class,
c29f1c
+                                   PROP_CONTEXT,
c29f1c
+                                   g_param_spec_object ("context",
c29f1c
+                                                        "Context",
c29f1c
+                                                        "MetaContext object",
c29f1c
+                                                        G_TYPE_OBJECT,
c29f1c
+                                                        G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
c29f1c
   g_object_class_install_property (gobject_class,
c29f1c
                                    PROP_DISPLAY,
c29f1c
                                    g_param_spec_object ("display",
c29f1c
@@ -996,6 +1011,7 @@ _shell_global_set_plugin (ShellGlobal *global,
c29f1c
 
c29f1c
   display = meta_plugin_get_display (plugin);
c29f1c
   global->meta_display = display;
c29f1c
+  global->meta_context = g_object_new (SHIM_TYPE_META_CONTEXT, NULL);
c29f1c
   global->workspace_manager = meta_display_get_workspace_manager (display);
c29f1c
 
c29f1c
   global->stage = CLUTTER_STAGE (meta_get_stage_for_display (display));
c29f1c
@@ -1888,3 +1904,79 @@ _shell_global_locate_pointer (ShellGlobal *global)
c29f1c
 {
c29f1c
   g_signal_emit (global, shell_global_signals[LOCATE_POINTER], 0);
c29f1c
 }
c29f1c
+
c29f1c
+enum {
c29f1c
+  SHIM_PROP_0,
c29f1c
+
c29f1c
+  SHIM_PROP_UNSAFE_MODE,
c29f1c
+
c29f1c
+  N_SHIM_PROPS
c29f1c
+};
c29f1c
+
c29f1c
+static GParamSpec *shim_obj_props [N_SHIM_PROPS];
c29f1c
+
c29f1c
+struct _ShimMetaContext
c29f1c
+{
c29f1c
+  GObject parent_instance;
c29f1c
+};
c29f1c
+
c29f1c
+G_DEFINE_TYPE (ShimMetaContext, shim_meta_context, G_TYPE_OBJECT);
c29f1c
+
c29f1c
+static void
c29f1c
+shim_meta_context_get_property (GObject    *object,
c29f1c
+                                guint       prop_id,
c29f1c
+                                GValue     *value,
c29f1c
+                                GParamSpec *pspec)
c29f1c
+{
c29f1c
+  switch (prop_id)
c29f1c
+    {
c29f1c
+    case SHIM_PROP_UNSAFE_MODE:
c29f1c
+      {
c29f1c
+        gboolean unsafe_mode;
c29f1c
+
c29f1c
+        g_object_get (meta_get_backend (), "unsafe-mode", &unsafe_mode, NULL);
c29f1c
+        g_value_set_boolean (value, unsafe_mode);
c29f1c
+      }
c29f1c
+      break;
c29f1c
+    default:
c29f1c
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
c29f1c
+    }
c29f1c
+}
c29f1c
+
c29f1c
+static void
c29f1c
+shim_meta_context_set_property (GObject      *object,
c29f1c
+                                guint         prop_id,
c29f1c
+                                const GValue *value,
c29f1c
+                                GParamSpec   *pspec)
c29f1c
+{
c29f1c
+  switch (prop_id)
c29f1c
+    {
c29f1c
+    case SHIM_PROP_UNSAFE_MODE:
c29f1c
+      g_object_set_property (G_OBJECT (meta_get_backend ()), "unsafe-mode", value);
c29f1c
+      break;
c29f1c
+    default:
c29f1c
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
c29f1c
+    }
c29f1c
+}
c29f1c
+
c29f1c
+static void
c29f1c
+shim_meta_context_class_init (ShimMetaContextClass *klass)
c29f1c
+{
c29f1c
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
c29f1c
+
c29f1c
+  object_class->get_property = shim_meta_context_get_property;
c29f1c
+  object_class->set_property = shim_meta_context_set_property;
c29f1c
+
c29f1c
+  shim_obj_props[SHIM_PROP_UNSAFE_MODE] =
c29f1c
+    g_param_spec_boolean ("unsafe-mode",
c29f1c
+                          "unsafe mode",
c29f1c
+                          "Unsafe mode",
c29f1c
+                          FALSE,
c29f1c
+                          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
c29f1c
+  g_object_class_install_properties (object_class, N_SHIM_PROPS, shim_obj_props);
c29f1c
+}
c29f1c
+
c29f1c
+static void
c29f1c
+shim_meta_context_init (ShimMetaContext *self)
c29f1c
+{
c29f1c
+}
c29f1c
-- 
c29f1c
2.35.1
c29f1c
c29f1c
c29f1c
From 20fcc7bc78a3c227304e89deddc57266e560175c Mon Sep 17 00:00:00 2001
c29f1c
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
c29f1c
Date: Thu, 2 Sep 2021 17:15:36 +0200
c29f1c
Subject: [PATCH 02/12] panel: Show warning indicator when unsafe-mode is on
c29f1c
c29f1c
MetaContext added an unsafe-mode property, which we will use to restrict
c29f1c
a number of privileged operations unless it is enabled. It is meant to
c29f1c
only be enabled temporarily for development/debugging purposes, so add
c29f1c
a scary icon to the top bar as a reminder to turn it off again.
c29f1c
c29f1c
https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/3943
c29f1c
c29f1c
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1970>
c29f1c
---
c29f1c
 js/ui/panel.js | 16 ++++++++++++++++
c29f1c
 1 file changed, 16 insertions(+)
c29f1c
c29f1c
diff --git a/js/ui/panel.js b/js/ui/panel.js
c29f1c
index 380480744..c57c3ba8e 100644
c29f1c
--- a/js/ui/panel.js
c29f1c
+++ b/js/ui/panel.js
c29f1c
@@ -641,6 +641,20 @@ class PanelCorner extends St.DrawingArea {
c29f1c
     }
c29f1c
 });
c29f1c
 
c29f1c
+const UnsafeModeIndicator = GObject.registerClass(
c29f1c
+class UnsafeModeIndicator extends PanelMenu.SystemIndicator {
c29f1c
+    _init() {
c29f1c
+        super._init();
c29f1c
+
c29f1c
+        this._indicator = this._addIndicator();
c29f1c
+        this._indicator.icon_name = 'channel-insecure-symbolic';
c29f1c
+
c29f1c
+        global.context.bind_property('unsafe-mode',
c29f1c
+            this._indicator, 'visible',
c29f1c
+            GObject.BindingFlags.SYNC_CREATE);
c29f1c
+    }
c29f1c
+});
c29f1c
+
c29f1c
 var AggregateLayout = GObject.registerClass(
c29f1c
 class AggregateLayout extends Clutter.BoxLayout {
c29f1c
     _init(params = {}) {
c29f1c
@@ -702,6 +716,7 @@ class AggregateMenu extends PanelMenu.Button {
c29f1c
         this._location = new imports.ui.status.location.Indicator();
c29f1c
         this._nightLight = new imports.ui.status.nightLight.Indicator();
c29f1c
         this._thunderbolt = new imports.ui.status.thunderbolt.Indicator();
c29f1c
+        this._unsafeMode = new UnsafeModeIndicator();
c29f1c
 
c29f1c
         this._indicators.add_child(this._remoteAccess);
c29f1c
         this._indicators.add_child(this._thunderbolt);
c29f1c
@@ -713,6 +728,7 @@ class AggregateMenu extends PanelMenu.Button {
c29f1c
             this._indicators.add_child(this._bluetooth);
c29f1c
         this._indicators.add_child(this._rfkill);
c29f1c
         this._indicators.add_child(this._volume);
c29f1c
+        this._indicators.add_child(this._unsafeMode);
c29f1c
         this._indicators.add_child(this._power);
c29f1c
         this._indicators.add_child(this._powerProfiles);
c29f1c
 
c29f1c
-- 
c29f1c
2.35.1
c29f1c
c29f1c
c29f1c
From 158eeebc1d3a243e75de550cf5711e38a9f77f7f Mon Sep 17 00:00:00 2001
c29f1c
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
c29f1c
Date: Thu, 17 Jun 2021 01:50:50 +0200
c29f1c
Subject: [PATCH 03/12] shellDBus: Use MetaContext:unsafe-mode to restrict
c29f1c
 Eval()
c29f1c
c29f1c
The Eval() method is unarguably the most sensitive D-Bus method
c29f1c
we expose, since it allows running arbitrary code in the compositor.
c29f1c
c29f1c
It is currently tied to the `development-tools` settings that is
c29f1c
enabled by default. As users have become accustomed to the built-in
c29f1c
commands that are enabled by the same setting (restart, lg, ...),
c29f1c
that default cannot easily be changed.
c29f1c
c29f1c
In order to restrict the method without affecting the rather harmless
c29f1c
commands, guard it by the new MetaContext:unsafe-mode property instead
c29f1c
of the setting.
c29f1c
c29f1c
https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/3943
c29f1c
c29f1c
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1970>
c29f1c
---
c29f1c
 js/ui/shellDBus.js | 2 +-
c29f1c
 1 file changed, 1 insertion(+), 1 deletion(-)
c29f1c
c29f1c
diff --git a/js/ui/shellDBus.js b/js/ui/shellDBus.js
c29f1c
index 734ca4fc7..5a6edec74 100644
c29f1c
--- a/js/ui/shellDBus.js
c29f1c
+++ b/js/ui/shellDBus.js
c29f1c
@@ -54,7 +54,7 @@ var GnomeShell = class {
c29f1c
      *
c29f1c
      */
c29f1c
     Eval(code) {
c29f1c
-        if (!global.settings.get_boolean('development-tools'))
c29f1c
+        if (!global.context.unsafe_mode)
c29f1c
             return [false, ''];
c29f1c
 
c29f1c
         let returnValue;
c29f1c
-- 
c29f1c
2.35.1
c29f1c
c29f1c
c29f1c
From 0882e04a11fe8db7abf05a5d7c786664dc54ad4f Mon Sep 17 00:00:00 2001
c29f1c
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
c29f1c
Date: Thu, 2 Sep 2021 16:23:38 +0200
c29f1c
Subject: [PATCH 04/12] introspect: Make invocation check error-based
c29f1c
c29f1c
If we throw an error when the invocation isn't allowed instead of
c29f1c
returning false, we can simply return that error instead of duplicating
c29f1c
the error handling.
c29f1c
c29f1c
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1970>
c29f1c
---
c29f1c
 js/misc/introspect.js | 26 ++++++++++++++------------
c29f1c
 1 file changed, 14 insertions(+), 12 deletions(-)
c29f1c
c29f1c
diff --git a/js/misc/introspect.js b/js/misc/introspect.js
c29f1c
index e46a7e8c5..318955be2 100644
c29f1c
--- a/js/misc/introspect.js
c29f1c
+++ b/js/misc/introspect.js
c29f1c
@@ -134,21 +134,23 @@ var IntrospectService = class {
c29f1c
                 type == Meta.WindowType.UTILITY;
c29f1c
     }
c29f1c
 
c29f1c
-    _isInvocationAllowed(invocation) {
c29f1c
+    _checkInvocation(invocation) {
c29f1c
         if (this._isIntrospectEnabled())
c29f1c
-            return true;
c29f1c
+            return;
c29f1c
 
c29f1c
         if (this._isSenderAllowed(invocation.get_sender()))
c29f1c
-            return true;
c29f1c
+            return;
c29f1c
 
c29f1c
-        return false;
c29f1c
+        throw new GLib.Error(Gio.DBusError,
c29f1c
+            Gio.DBusError.ACCESS_DENIED,
c29f1c
+            'App introspection not allowed');
c29f1c
     }
c29f1c
 
c29f1c
     GetRunningApplicationsAsync(params, invocation) {
c29f1c
-        if (!this._isInvocationAllowed(invocation)) {
c29f1c
-            invocation.return_error_literal(Gio.DBusError,
c29f1c
-                                            Gio.DBusError.ACCESS_DENIED,
c29f1c
-                                            'App introspection not allowed');
c29f1c
+        try {
c29f1c
+            this._checkInvocation(invocation);
c29f1c
+        } catch (e) {
c29f1c
+            invocation.return_gerror(e);
c29f1c
             return;
c29f1c
         }
c29f1c
 
c29f1c
@@ -160,10 +162,10 @@ var IntrospectService = class {
c29f1c
         let apps = this._appSystem.get_running();
c29f1c
         let windowsList = {};
c29f1c
 
c29f1c
-        if (!this._isInvocationAllowed(invocation)) {
c29f1c
-            invocation.return_error_literal(Gio.DBusError,
c29f1c
-                                            Gio.DBusError.ACCESS_DENIED,
c29f1c
-                                            'App introspection not allowed');
c29f1c
+        try {
c29f1c
+            this._checkInvocation(invocation);
c29f1c
+        } catch (e) {
c29f1c
+            invocation.return_gerror(e);
c29f1c
             return;
c29f1c
         }
c29f1c
 
c29f1c
-- 
c29f1c
2.35.1
c29f1c
c29f1c
c29f1c
From 33c3c3846f62cc4737f0029455f9dcd838876bca Mon Sep 17 00:00:00 2001
c29f1c
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
c29f1c
Date: Wed, 1 Sep 2021 21:18:42 +0200
c29f1c
Subject: [PATCH 05/12] introspect: Use MetaContext:unsafe-mode instead of
c29f1c
 setting
c29f1c
c29f1c
The property was added precisely for this purpose, except that its
c29f1c
name isn't tied to the introspect API.
c29f1c
c29f1c
https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/3943
c29f1c
c29f1c
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1970>
c29f1c
---
c29f1c
 js/misc/introspect.js | 12 +-----------
c29f1c
 1 file changed, 1 insertion(+), 11 deletions(-)
c29f1c
c29f1c
diff --git a/js/misc/introspect.js b/js/misc/introspect.js
c29f1c
index 318955be2..967e7b830 100644
c29f1c
--- a/js/misc/introspect.js
c29f1c
+++ b/js/misc/introspect.js
c29f1c
@@ -1,8 +1,6 @@
c29f1c
 /* exported IntrospectService */
c29f1c
 const { Gio, GLib, Meta, Shell, St } = imports.gi;
c29f1c
 
c29f1c
-const INTROSPECT_SCHEMA = 'org.gnome.shell';
c29f1c
-const INTROSPECT_KEY = 'introspect';
c29f1c
 const APP_ALLOWLIST = ['org.freedesktop.impl.portal.desktop.gtk'];
c29f1c
 
c29f1c
 const INTROSPECT_DBUS_API_VERSION = 3;
c29f1c
@@ -33,10 +31,6 @@ var IntrospectService = class {
c29f1c
                                     this._syncRunningApplications();
c29f1c
                                 });
c29f1c
 
c29f1c
-        this._introspectSettings = new Gio.Settings({
c29f1c
-            schema_id: INTROSPECT_SCHEMA,
c29f1c
-        });
c29f1c
-
c29f1c
         let tracker = Shell.WindowTracker.get_default();
c29f1c
         tracker.connect('notify::focus-app',
c29f1c
                         () => {
c29f1c
@@ -70,10 +64,6 @@ var IntrospectService = class {
c29f1c
         return app.get_windows().some(w => w.transient_for == null);
c29f1c
     }
c29f1c
 
c29f1c
-    _isIntrospectEnabled() {
c29f1c
-        return this._introspectSettings.get_boolean(INTROSPECT_KEY);
c29f1c
-    }
c29f1c
-
c29f1c
     _isSenderAllowed(sender) {
c29f1c
         return [...this._allowlistMap.values()].includes(sender);
c29f1c
     }
c29f1c
@@ -135,7 +125,7 @@ var IntrospectService = class {
c29f1c
     }
c29f1c
 
c29f1c
     _checkInvocation(invocation) {
c29f1c
-        if (this._isIntrospectEnabled())
c29f1c
+        if (global.context.unsafe_mode)
c29f1c
             return;
c29f1c
 
c29f1c
         if (this._isSenderAllowed(invocation.get_sender()))
c29f1c
-- 
c29f1c
2.35.1
c29f1c
c29f1c
c29f1c
From 4238128ba403da2cc788b0b249ee34acbea5d743 Mon Sep 17 00:00:00 2001
c29f1c
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
c29f1c
Date: Wed, 1 Sep 2021 21:25:26 +0200
c29f1c
Subject: [PATCH 06/12] data: Remove now unused "introspect" setting
c29f1c
c29f1c
https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/3943
c29f1c
c29f1c
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1970>
c29f1c
---
c29f1c
 data/org.gnome.shell.gschema.xml.in | 8 --------
c29f1c
 1 file changed, 8 deletions(-)
c29f1c
c29f1c
diff --git a/data/org.gnome.shell.gschema.xml.in b/data/org.gnome.shell.gschema.xml.in
c29f1c
index d5ea1e35f..6f1c424ba 100644
c29f1c
--- a/data/org.gnome.shell.gschema.xml.in
c29f1c
+++ b/data/org.gnome.shell.gschema.xml.in
c29f1c
@@ -104,14 +104,6 @@
c29f1c
         number can be used to effectively disable the dialog.
c29f1c
       </description>
c29f1c
     </key>
c29f1c
-    <key name="introspect" type="b">
c29f1c
-      <default>false</default>
c29f1c
-      <summary>Enable introspection API</summary>
c29f1c
-      <description>
c29f1c
-        Enables a D-Bus API that allows to introspect the application state of
c29f1c
-        the shell.
c29f1c
-      </description>
c29f1c
-    </key>
c29f1c
     <key name="app-picker-layout" type="aa{sv}">
c29f1c
       <default>
c29f1c
         [{
c29f1c
-- 
c29f1c
2.35.1
c29f1c
c29f1c
c29f1c
From f6af47b55fa2a52c7cdfecf1bb7e83d7f435a6bd Mon Sep 17 00:00:00 2001
c29f1c
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
c29f1c
Date: Wed, 16 Jun 2021 19:09:42 +0200
c29f1c
Subject: [PATCH 07/12] introspect: Split out DBusSenderChecker
c29f1c
c29f1c
Restricting callers to a list of allowed senders is useful for
c29f1c
other D-Bus services as well, so split out the existing code
c29f1c
into a reusable class.
c29f1c
c29f1c
https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/3943
c29f1c
c29f1c
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1970>
c29f1c
---
c29f1c
 js/misc/introspect.js | 30 ++++-------------------
c29f1c
 js/misc/util.js       | 56 ++++++++++++++++++++++++++++++++++++++++++-
c29f1c
 2 files changed, 59 insertions(+), 27 deletions(-)
c29f1c
c29f1c
diff --git a/js/misc/introspect.js b/js/misc/introspect.js
c29f1c
index 967e7b830..e9d9260c0 100644
c29f1c
--- a/js/misc/introspect.js
c29f1c
+++ b/js/misc/introspect.js
c29f1c
@@ -6,6 +6,7 @@ const APP_ALLOWLIST = ['org.freedesktop.impl.portal.desktop.gtk'];
c29f1c
 const INTROSPECT_DBUS_API_VERSION = 3;
c29f1c
 
c29f1c
 const { loadInterfaceXML } = imports.misc.fileUtils;
c29f1c
+const { DBusSenderChecker } = imports.misc.util;
c29f1c
 
c29f1c
 const IntrospectDBusIface = loadInterfaceXML('org.gnome.Shell.Introspect');
c29f1c
 
c29f1c
@@ -40,14 +41,7 @@ var IntrospectService = class {
c29f1c
 
c29f1c
         this._syncRunningApplications();
c29f1c
 
c29f1c
-        this._allowlistMap = new Map();
c29f1c
-        APP_ALLOWLIST.forEach(appName => {
c29f1c
-            Gio.DBus.watch_name(Gio.BusType.SESSION,
c29f1c
-                appName,
c29f1c
-                Gio.BusNameWatcherFlags.NONE,
c29f1c
-                (conn, name, owner) => this._allowlistMap.set(name, owner),
c29f1c
-                (conn, name) => this._allowlistMap.delete(name));
c29f1c
-        });
c29f1c
+        this._senderChecker = new DBusSenderChecker(APP_ALLOWLIST);
c29f1c
 
c29f1c
         this._settings = St.Settings.get();
c29f1c
         this._settings.connect('notify::enable-animations',
c29f1c
@@ -64,10 +58,6 @@ var IntrospectService = class {
c29f1c
         return app.get_windows().some(w => w.transient_for == null);
c29f1c
     }
c29f1c
 
c29f1c
-    _isSenderAllowed(sender) {
c29f1c
-        return [...this._allowlistMap.values()].includes(sender);
c29f1c
-    }
c29f1c
-
c29f1c
     _getSandboxedAppId(app) {
c29f1c
         let ids = app.get_windows().map(w => w.get_sandboxed_app_id());
c29f1c
         return ids.find(id => id != null);
c29f1c
@@ -124,21 +114,9 @@ var IntrospectService = class {
c29f1c
                 type == Meta.WindowType.UTILITY;
c29f1c
     }
c29f1c
 
c29f1c
-    _checkInvocation(invocation) {
c29f1c
-        if (global.context.unsafe_mode)
c29f1c
-            return;
c29f1c
-
c29f1c
-        if (this._isSenderAllowed(invocation.get_sender()))
c29f1c
-            return;
c29f1c
-
c29f1c
-        throw new GLib.Error(Gio.DBusError,
c29f1c
-            Gio.DBusError.ACCESS_DENIED,
c29f1c
-            'App introspection not allowed');
c29f1c
-    }
c29f1c
-
c29f1c
     GetRunningApplicationsAsync(params, invocation) {
c29f1c
         try {
c29f1c
-            this._checkInvocation(invocation);
c29f1c
+            this._senderChecker.checkInvocation(invocation);
c29f1c
         } catch (e) {
c29f1c
             invocation.return_gerror(e);
c29f1c
             return;
c29f1c
@@ -153,7 +131,7 @@ var IntrospectService = class {
c29f1c
         let windowsList = {};
c29f1c
 
c29f1c
         try {
c29f1c
-            this._checkInvocation(invocation);
c29f1c
+            this._senderChecker.checkInvocation(invocation);
c29f1c
         } catch (e) {
c29f1c
             invocation.return_gerror(e);
c29f1c
             return;
c29f1c
diff --git a/js/misc/util.js b/js/misc/util.js
c29f1c
index 802398d18..e6c183fbf 100644
c29f1c
--- a/js/misc/util.js
c29f1c
+++ b/js/misc/util.js
c29f1c
@@ -2,7 +2,7 @@
c29f1c
 /* exported findUrls, spawn, spawnCommandLine, spawnApp, trySpawnCommandLine,
c29f1c
             formatTime, formatTimeSpan, createTimeLabel, insertSorted,
c29f1c
             ensureActorVisibleInScrollView, wiggle, lerp, GNOMEversionCompare,
c29f1c
-            Highlighter */
c29f1c
+            DBusSenderChecker, Highlighter */
c29f1c
 
c29f1c
 const { Clutter, Gio, GLib, Shell, St, GnomeDesktop } = imports.gi;
c29f1c
 const Gettext = imports.gettext;
c29f1c
@@ -479,6 +479,60 @@ function GNOMEversionCompare(version1, version2) {
c29f1c
     return 0;
c29f1c
 }
c29f1c
 
c29f1c
+var DBusSenderChecker = class {
c29f1c
+    /**
c29f1c
+     * @param {string[]} allowList - list of allowed well-known names
c29f1c
+     */
c29f1c
+    constructor(allowList) {
c29f1c
+        this._allowlistMap = new Map();
c29f1c
+
c29f1c
+        this._watchList = allowList.map(name => {
c29f1c
+            return Gio.DBus.watch_name(Gio.BusType.SESSION,
c29f1c
+                name,
c29f1c
+                Gio.BusNameWatcherFlags.NONE,
c29f1c
+                (conn_, name_, owner) => this._allowlistMap.set(name, owner),
c29f1c
+                () => this._allowlistMap.delete(name));
c29f1c
+        });
c29f1c
+    }
c29f1c
+
c29f1c
+    /**
c29f1c
+     * @param {string} sender - the bus name that invoked the checked method
c29f1c
+     * @returns {bool}
c29f1c
+     */
c29f1c
+    _isSenderAllowed(sender) {
c29f1c
+        return [...this._allowlistMap.values()].includes(sender);
c29f1c
+    }
c29f1c
+
c29f1c
+    /**
c29f1c
+     * Check whether the bus name that invoked @invocation maps
c29f1c
+     * to an entry in the allow list.
c29f1c
+     *
c29f1c
+     * @throws
c29f1c
+     * @param {Gio.DBusMethodInvocation} invocation - the invocation
c29f1c
+     * @returns {void}
c29f1c
+     */
c29f1c
+    checkInvocation(invocation) {
c29f1c
+        if (global.context.unsafe_mode)
c29f1c
+            return;
c29f1c
+
c29f1c
+        if (this._isSenderAllowed(invocation.get_sender()))
c29f1c
+            return;
c29f1c
+
c29f1c
+        throw new GLib.Error(Gio.DBusError,
c29f1c
+            Gio.DBusError.ACCESS_DENIED,
c29f1c
+            '%s is not allowed'.format(invocation.get_method_name()));
c29f1c
+    }
c29f1c
+
c29f1c
+    /**
c29f1c
+     * @returns {void}
c29f1c
+     */
c29f1c
+    destroy() {
c29f1c
+        for (const id in this._watchList)
c29f1c
+            Gio.DBus.unwatch_name(id);
c29f1c
+        this._watchList = [];
c29f1c
+    }
c29f1c
+};
c29f1c
+
c29f1c
 /* @class Highlighter Highlight given terms in text using markup. */
c29f1c
 var Highlighter = class {
c29f1c
     /**
c29f1c
-- 
c29f1c
2.35.1
c29f1c
c29f1c
c29f1c
From c6679a876a3c73c2c691333a5b987e27965231f3 Mon Sep 17 00:00:00 2001
c29f1c
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
c29f1c
Date: Thu, 17 Jun 2021 15:29:42 +0200
c29f1c
Subject: [PATCH 08/12] shellDBus: Implement all methods asynchronously
c29f1c
c29f1c
In order to restrict callers, we will need access to the invocation,
c29f1c
not just the unpacked method parameters.
c29f1c
c29f1c
https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/3943
c29f1c
c29f1c
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1970>
c29f1c
---
c29f1c
 js/ui/shellDBus.js | 31 ++++++++++++++++++++++++++++---
c29f1c
 1 file changed, 28 insertions(+), 3 deletions(-)
c29f1c
c29f1c
diff --git a/js/ui/shellDBus.js b/js/ui/shellDBus.js
c29f1c
index 5a6edec74..aa5b4dc3c 100644
c29f1c
--- a/js/ui/shellDBus.js
c29f1c
+++ b/js/ui/shellDBus.js
c29f1c
@@ -72,11 +72,26 @@ var GnomeShell = class {
c29f1c
         return [success, returnValue];
c29f1c
     }
c29f1c
 
c29f1c
-    FocusSearch() {
c29f1c
+    /**
c29f1c
+     * Focus the overview's search entry
c29f1c
+     *
c29f1c
+     * @param {...any} params - method parameters
c29f1c
+     * @param {Gio.DBusMethodInvocation} invocation - the invocation
c29f1c
+     * @returns {void}
c29f1c
+     */
c29f1c
+    FocusSearchAsync(params, invocation) {
c29f1c
         Main.overview.focusSearch();
c29f1c
+        invocation.return_value(null);
c29f1c
     }
c29f1c
 
c29f1c
-    ShowOSD(params) {
c29f1c
+    /**
c29f1c
+     * Show OSD with the specified parameters
c29f1c
+     *
c29f1c
+     * @param {...any} params - method parameters
c29f1c
+     * @param {Gio.DBusMethodInvocation} invocation - the invocation
c29f1c
+     * @returns {void}
c29f1c
+     */
c29f1c
+    ShowOSDAsync([params], invocation) {
c29f1c
         for (let param in params)
c29f1c
             params[param] = params[param].deep_unpack();
c29f1c
 
c29f1c
@@ -97,6 +112,7 @@ var GnomeShell = class {
c29f1c
             icon = Gio.Icon.new_for_string(serializedIcon);
c29f1c
 
c29f1c
         Main.osdWindowManager.show(monitorIndex, icon, label, level, maxLevel);
c29f1c
+        invocation.return_value(null);
c29f1c
     }
c29f1c
 
c29f1c
     /**
c29f1c
@@ -118,10 +134,19 @@ var GnomeShell = class {
c29f1c
         }
c29f1c
 
c29f1c
         Main.overview.selectApp(id);
c29f1c
+        invocation.return_value(null);
c29f1c
     }
c29f1c
 
c29f1c
-    ShowApplications() {
c29f1c
+    /**
c29f1c
+     * Show the overview's app grid
c29f1c
+     *
c29f1c
+     * @param {...any} params - method parameters
c29f1c
+     * @param {Gio.DBusMethodInvocation} invocation - the invocation
c29f1c
+     * @returns {void}
c29f1c
+     */
c29f1c
+    ShowApplicationsAsync(params, invocation) {
c29f1c
         Main.overview.show(ControlsState.APP_GRID);
c29f1c
+        invocation.return_value(null);
c29f1c
     }
c29f1c
 
c29f1c
     GrabAcceleratorAsync(params, invocation) {
c29f1c
-- 
c29f1c
2.35.1
c29f1c
c29f1c
c29f1c
From 3ad733997eecb069be543f1a4452d7a7916a0962 Mon Sep 17 00:00:00 2001
c29f1c
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
c29f1c
Date: Thu, 17 Jun 2021 15:29:42 +0200
c29f1c
Subject: [PATCH 09/12] shellDBus: Restrict callers
c29f1c
c29f1c
The org.gnome.Shell interface provides a private API to other core
c29f1c
components to implement desktop functionalities like Settings or
c29f1c
global keybindings. It is not meant as a public API, so limit it
c29f1c
to a set of expected callers.
c29f1c
c29f1c
https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/3943
c29f1c
c29f1c
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1970>
c29f1c
---
c29f1c
 js/ui/shellDBus.js | 76 ++++++++++++++++++++++++++++++++++++++++++++++
c29f1c
 1 file changed, 76 insertions(+)
c29f1c
c29f1c
diff --git a/js/ui/shellDBus.js b/js/ui/shellDBus.js
c29f1c
index aa5b4dc3c..c511314f9 100644
c29f1c
--- a/js/ui/shellDBus.js
c29f1c
+++ b/js/ui/shellDBus.js
c29f1c
@@ -10,6 +10,7 @@ const Main = imports.ui.main;
c29f1c
 const Screenshot = imports.ui.screenshot;
c29f1c
 
c29f1c
 const { loadInterfaceXML } = imports.misc.fileUtils;
c29f1c
+const { DBusSenderChecker } = imports.misc.util;
c29f1c
 const { ControlsState } = imports.ui.overviewControls;
c29f1c
 
c29f1c
 const GnomeShellIface = loadInterfaceXML('org.gnome.Shell');
c29f1c
@@ -20,6 +21,11 @@ var GnomeShell = class {
c29f1c
         this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(GnomeShellIface, this);
c29f1c
         this._dbusImpl.export(Gio.DBus.session, '/org/gnome/Shell');
c29f1c
 
c29f1c
+        this._senderChecker = new DBusSenderChecker([
c29f1c
+            'org.gnome.ControlCenter',
c29f1c
+            'org.gnome.SettingsDaemon.MediaKeys',
c29f1c
+        ]);
c29f1c
+
c29f1c
         this._extensionsService = new GnomeShellExtensions();
c29f1c
         this._screenshotService = new Screenshot.ScreenshotService();
c29f1c
 
c29f1c
@@ -80,6 +86,13 @@ var GnomeShell = class {
c29f1c
      * @returns {void}
c29f1c
      */
c29f1c
     FocusSearchAsync(params, invocation) {
c29f1c
+        try {
c29f1c
+            this._senderChecker.checkInvocation(invocation);
c29f1c
+        } catch (e) {
c29f1c
+            invocation.return_gerror(e);
c29f1c
+            return;
c29f1c
+        }
c29f1c
+
c29f1c
         Main.overview.focusSearch();
c29f1c
         invocation.return_value(null);
c29f1c
     }
c29f1c
@@ -92,6 +105,13 @@ var GnomeShell = class {
c29f1c
      * @returns {void}
c29f1c
      */
c29f1c
     ShowOSDAsync([params], invocation) {
c29f1c
+        try {
c29f1c
+            this._senderChecker.checkInvocation(invocation);
c29f1c
+        } catch (e) {
c29f1c
+            invocation.return_gerror(e);
c29f1c
+            return;
c29f1c
+        }
c29f1c
+
c29f1c
         for (let param in params)
c29f1c
             params[param] = params[param].deep_unpack();
c29f1c
 
c29f1c
@@ -124,6 +144,13 @@ var GnomeShell = class {
c29f1c
      * @returns {void}
c29f1c
      */
c29f1c
     FocusAppAsync([id], invocation) {
c29f1c
+        try {
c29f1c
+            this._senderChecker.checkInvocation(invocation);
c29f1c
+        } catch (e) {
c29f1c
+            invocation.return_gerror(e);
c29f1c
+            return;
c29f1c
+        }
c29f1c
+
c29f1c
         const appSys = Shell.AppSystem.get_default();
c29f1c
         if (appSys.lookup_app(id) === null) {
c29f1c
             invocation.return_error_literal(
c29f1c
@@ -145,11 +172,25 @@ var GnomeShell = class {
c29f1c
      * @returns {void}
c29f1c
      */
c29f1c
     ShowApplicationsAsync(params, invocation) {
c29f1c
+        try {
c29f1c
+            this._senderChecker.checkInvocation(invocation);
c29f1c
+        } catch (e) {
c29f1c
+            invocation.return_gerror(e);
c29f1c
+            return;
c29f1c
+        }
c29f1c
+
c29f1c
         Main.overview.show(ControlsState.APP_GRID);
c29f1c
         invocation.return_value(null);
c29f1c
     }
c29f1c
 
c29f1c
     GrabAcceleratorAsync(params, invocation) {
c29f1c
+        try {
c29f1c
+            this._senderChecker.checkInvocation(invocation);
c29f1c
+        } catch (e) {
c29f1c
+            invocation.return_gerror(e);
c29f1c
+            return;
c29f1c
+        }
c29f1c
+
c29f1c
         let [accel, modeFlags, grabFlags] = params;
c29f1c
         let sender = invocation.get_sender();
c29f1c
         let bindingAction = this._grabAcceleratorForSender(accel, modeFlags, grabFlags, sender);
c29f1c
@@ -157,6 +198,13 @@ var GnomeShell = class {
c29f1c
     }
c29f1c
 
c29f1c
     GrabAcceleratorsAsync(params, invocation) {
c29f1c
+        try {
c29f1c
+            this._senderChecker.checkInvocation(invocation);
c29f1c
+        } catch (e) {
c29f1c
+            invocation.return_gerror(e);
c29f1c
+            return;
c29f1c
+        }
c29f1c
+
c29f1c
         let [accels] = params;
c29f1c
         let sender = invocation.get_sender();
c29f1c
         let bindingActions = [];
c29f1c
@@ -168,6 +216,13 @@ var GnomeShell = class {
c29f1c
     }
c29f1c
 
c29f1c
     UngrabAcceleratorAsync(params, invocation) {
c29f1c
+        try {
c29f1c
+            this._senderChecker.checkInvocation(invocation);
c29f1c
+        } catch (e) {
c29f1c
+            invocation.return_gerror(e);
c29f1c
+            return;
c29f1c
+        }
c29f1c
+
c29f1c
         let [action] = params;
c29f1c
         let sender = invocation.get_sender();
c29f1c
         let ungrabSucceeded = this._ungrabAcceleratorForSender(action, sender);
c29f1c
@@ -176,6 +231,13 @@ var GnomeShell = class {
c29f1c
     }
c29f1c
 
c29f1c
     UngrabAcceleratorsAsync(params, invocation) {
c29f1c
+        try {
c29f1c
+            this._senderChecker.checkInvocation(invocation);
c29f1c
+        } catch (e) {
c29f1c
+            invocation.return_gerror(e);
c29f1c
+            return;
c29f1c
+        }
c29f1c
+
c29f1c
         let [actions] = params;
c29f1c
         let sender = invocation.get_sender();
c29f1c
         let ungrabSucceeded = true;
c29f1c
@@ -256,6 +318,13 @@ var GnomeShell = class {
c29f1c
     }
c29f1c
 
c29f1c
     ShowMonitorLabelsAsync(params, invocation) {
c29f1c
+        try {
c29f1c
+            this._senderChecker.checkInvocation(invocation);
c29f1c
+        } catch (e) {
c29f1c
+            invocation.return_gerror(e);
c29f1c
+            return;
c29f1c
+        }
c29f1c
+
c29f1c
         let sender = invocation.get_sender();
c29f1c
         let [dict] = params;
c29f1c
         Main.osdMonitorLabeler.show(sender, dict);
c29f1c
@@ -263,6 +332,13 @@ var GnomeShell = class {
c29f1c
     }
c29f1c
 
c29f1c
     HideMonitorLabelsAsync(params, invocation) {
c29f1c
+        try {
c29f1c
+            this._senderChecker.checkInvocation(invocation);
c29f1c
+        } catch (e) {
c29f1c
+            invocation.return_gerror(e);
c29f1c
+            return;
c29f1c
+        }
c29f1c
+
c29f1c
         let sender = invocation.get_sender();
c29f1c
         Main.osdMonitorLabeler.hide(sender);
c29f1c
         invocation.return_value(null);
c29f1c
-- 
c29f1c
2.35.1
c29f1c
c29f1c
c29f1c
From 5b87782b4950742b6ae1b29777e7812c93892ad7 Mon Sep 17 00:00:00 2001
c29f1c
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
c29f1c
Date: Wed, 16 Jun 2021 22:11:50 +0200
c29f1c
Subject: [PATCH 10/12] screenshot: Restrict callers
c29f1c
c29f1c
The shell D-Bus API was always meant as a private API for core
c29f1c
components, so enforce that by limiting caller to a list of
c29f1c
allowed well-known names.
c29f1c
c29f1c
Applications that want to request a screenshot can use the corresponding
c29f1c
desktop portal.
c29f1c
c29f1c
https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/3943
c29f1c
c29f1c
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1970>
c29f1c
---
c29f1c
 js/ui/screenshot.js | 28 ++++++++++++++++++++++++++++
c29f1c
 1 file changed, 28 insertions(+)
c29f1c
c29f1c
diff --git a/js/ui/screenshot.js b/js/ui/screenshot.js
c29f1c
index 81ab516b1..bf537b7d6 100644
c29f1c
--- a/js/ui/screenshot.js
c29f1c
+++ b/js/ui/screenshot.js
c29f1c
@@ -15,6 +15,7 @@ Gio._promisify(Shell.Screenshot.prototype,
c29f1c
     'screenshot_area', 'screenshot_area_finish');
c29f1c
 
c29f1c
 const { loadInterfaceXML } = imports.misc.fileUtils;
c29f1c
+const { DBusSenderChecker } = imports.misc.util;
c29f1c
 
c29f1c
 const ScreenshotIface = loadInterfaceXML('org.gnome.Shell.Screenshot');
c29f1c
 
c29f1c
@@ -24,6 +25,12 @@ var ScreenshotService = class {
c29f1c
         this._dbusImpl.export(Gio.DBus.session, '/org/gnome/Shell/Screenshot');
c29f1c
 
c29f1c
         this._screenShooter = new Map();
c29f1c
+        this._senderChecker = new DBusSenderChecker([
c29f1c
+            'org.gnome.SettingsDaemon.MediaKeys',
c29f1c
+            'org.freedesktop.impl.portal.desktop.gtk',
c29f1c
+            'org.freedesktop.impl.portal.desktop.gnome',
c29f1c
+            'org.gnome.Screenshot',
c29f1c
+        ]);
c29f1c
 
c29f1c
         this._lockdownSettings = new Gio.Settings({ schema_id: 'org.gnome.desktop.lockdown' });
c29f1c
 
c29f1c
@@ -46,6 +53,13 @@ var ScreenshotService = class {
c29f1c
                 Gio.IOErrorEnum, Gio.IOErrorEnum.PERMISSION_DENIED,
c29f1c
                 'Saving to disk is disabled');
c29f1c
             return null;
c29f1c
+        } else {
c29f1c
+            try {
c29f1c
+                this._senderChecker.checkInvocation(invocation);
c29f1c
+            } catch (e) {
c29f1c
+                invocation.return_gerror(e);
c29f1c
+                return null;
c29f1c
+            }
c29f1c
         }
c29f1c
 
c29f1c
         let shooter = new Shell.Screenshot();
c29f1c
@@ -254,6 +268,13 @@ var ScreenshotService = class {
c29f1c
     }
c29f1c
 
c29f1c
     async SelectAreaAsync(params, invocation) {
c29f1c
+        try {
c29f1c
+            this._senderChecker.checkInvocation(invocation);
c29f1c
+        } catch (e) {
c29f1c
+            invocation.return_gerror(e);
c29f1c
+            return;
c29f1c
+        }
c29f1c
+
c29f1c
         let selectArea = new SelectArea();
c29f1c
         try {
c29f1c
             let areaRectangle = await selectArea.selectAsync();
c29f1c
@@ -269,6 +290,13 @@ var ScreenshotService = class {
c29f1c
     }
c29f1c
 
c29f1c
     FlashAreaAsync(params, invocation) {
c29f1c
+        try {
c29f1c
+            this._senderChecker.checkInvocation(invocation);
c29f1c
+        } catch (e) {
c29f1c
+            invocation.return_gerror(e);
c29f1c
+            return;
c29f1c
+        }
c29f1c
+
c29f1c
         let [x, y, width, height] = params;
c29f1c
         [x, y, width, height] = this._scaleArea(x, y, width, height);
c29f1c
         if (!this._checkArea(x, y, width, height)) {
c29f1c
-- 
c29f1c
2.35.1
c29f1c
c29f1c
c29f1c
From b02e721663ed1481ff7b4cf40cae3a34d059d90c Mon Sep 17 00:00:00 2001
c29f1c
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
c29f1c
Date: Sat, 25 Sep 2021 14:15:32 +0200
c29f1c
Subject: [PATCH 11/12] screenshot: Unrestrict PickColor
c29f1c
c29f1c
Commit dd2cd6286cd3 restricted callers of the screenshot methods to
c29f1c
portal implementations, gnome-settings-daemon and gnome-screenshot.
c29f1c
c29f1c
That restriction does make sense for the actual screenshot methods,
c29f1c
but `PickColor` is actually used by GTK in its color picker (and
c29f1c
therefore may be called from arbitrary applications).
c29f1c
c29f1c
Fix this by unrestricting access to `PickColor` again. Considering that
c29f1c
the method is always interactive, it's not very privacy/security-sensitive
c29f1c
anyway.
c29f1c
c29f1c
https://gitlab.gnome.org/GNOME/gtk/-/issues/4283
c29f1c
c29f1c
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1990>
c29f1c
---
c29f1c
 js/ui/screenshot.js | 6 +++---
c29f1c
 1 file changed, 3 insertions(+), 3 deletions(-)
c29f1c
c29f1c
diff --git a/js/ui/screenshot.js b/js/ui/screenshot.js
c29f1c
index bf537b7d6..ae1156f47 100644
c29f1c
--- a/js/ui/screenshot.js
c29f1c
+++ b/js/ui/screenshot.js
c29f1c
@@ -37,7 +37,7 @@ var ScreenshotService = class {
c29f1c
         Gio.DBus.session.own_name('org.gnome.Shell.Screenshot', Gio.BusNameOwnerFlags.REPLACE, null, null);
c29f1c
     }
c29f1c
 
c29f1c
-    _createScreenshot(invocation, needsDisk = true) {
c29f1c
+    _createScreenshot(invocation, needsDisk = true, restrictCallers = true) {
c29f1c
         let lockedDown = false;
c29f1c
         if (needsDisk)
c29f1c
             lockedDown = this._lockdownSettings.get_boolean('disable-save-to-disk');
c29f1c
@@ -53,7 +53,7 @@ var ScreenshotService = class {
c29f1c
                 Gio.IOErrorEnum, Gio.IOErrorEnum.PERMISSION_DENIED,
c29f1c
                 'Saving to disk is disabled');
c29f1c
             return null;
c29f1c
-        } else {
c29f1c
+        } else if (restrictCallers) {
c29f1c
             try {
c29f1c
                 this._senderChecker.checkInvocation(invocation);
c29f1c
             } catch (e) {
c29f1c
@@ -311,7 +311,7 @@ var ScreenshotService = class {
c29f1c
     }
c29f1c
 
c29f1c
     async PickColorAsync(params, invocation) {
c29f1c
-        const screenshot = this._createScreenshot(invocation, false);
c29f1c
+        const screenshot = this._createScreenshot(invocation, false, false);
c29f1c
         if (!screenshot)
c29f1c
             return;
c29f1c
 
c29f1c
-- 
c29f1c
2.35.1
c29f1c
c29f1c
c29f1c
From 9e8073afbf30aaea87aefd8201fc5e04f94edaf8 Mon Sep 17 00:00:00 2001
c29f1c
From: Sebastian Keller <skeller@gnome.org>
c29f1c
Date: Tue, 23 Nov 2021 02:48:04 +0100
c29f1c
Subject: [PATCH 12/12] util: Wait for initial name owners in DBusSenderCheck
c29f1c
 before checking
c29f1c
c29f1c
Otherwise an allowed caller might get rejected if the call is right
c29f1c
after a gnome-shell restart and the watchers have not finished running
c29f1c
their callbacks yet.
c29f1c
c29f1c
Fixes: https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/4813
c29f1c
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/2048>
c29f1c
(cherry picked from commit 85609a232d4088b058f23f4922b9a993dea95199)
c29f1c
---
c29f1c
 js/misc/introspect.js |  8 ++++----
c29f1c
 js/misc/util.js       | 33 ++++++++++++++++++++++++++++-----
c29f1c
 js/ui/screenshot.js   | 18 +++++++++---------
c29f1c
 js/ui/shellDBus.js    | 43 +++++++++++++++++++++++--------------------
c29f1c
 4 files changed, 64 insertions(+), 38 deletions(-)
c29f1c
c29f1c
diff --git a/js/misc/introspect.js b/js/misc/introspect.js
c29f1c
index e9d9260c0..f3c938af9 100644
c29f1c
--- a/js/misc/introspect.js
c29f1c
+++ b/js/misc/introspect.js
c29f1c
@@ -114,9 +114,9 @@ var IntrospectService = class {
c29f1c
                 type == Meta.WindowType.UTILITY;
c29f1c
     }
c29f1c
 
c29f1c
-    GetRunningApplicationsAsync(params, invocation) {
c29f1c
+    async GetRunningApplicationsAsync(params, invocation) {
c29f1c
         try {
c29f1c
-            this._senderChecker.checkInvocation(invocation);
c29f1c
+            await this._senderChecker.checkInvocation(invocation);
c29f1c
         } catch (e) {
c29f1c
             invocation.return_gerror(e);
c29f1c
             return;
c29f1c
@@ -125,13 +125,13 @@ var IntrospectService = class {
c29f1c
         invocation.return_value(new GLib.Variant('(a{sa{sv}})', [this._runningApplications]));
c29f1c
     }
c29f1c
 
c29f1c
-    GetWindowsAsync(params, invocation) {
c29f1c
+    async GetWindowsAsync(params, invocation) {
c29f1c
         let focusWindow = global.display.get_focus_window();
c29f1c
         let apps = this._appSystem.get_running();
c29f1c
         let windowsList = {};
c29f1c
 
c29f1c
         try {
c29f1c
-            this._senderChecker.checkInvocation(invocation);
c29f1c
+            await this._senderChecker.checkInvocation(invocation);
c29f1c
         } catch (e) {
c29f1c
             invocation.return_gerror(e);
c29f1c
             return;
c29f1c
diff --git a/js/misc/util.js b/js/misc/util.js
c29f1c
index e6c183fbf..6a0f6f641 100644
c29f1c
--- a/js/misc/util.js
c29f1c
+++ b/js/misc/util.js
c29f1c
@@ -486,20 +486,42 @@ var DBusSenderChecker = class {
c29f1c
     constructor(allowList) {
c29f1c
         this._allowlistMap = new Map();
c29f1c
 
c29f1c
+        this._uninitializedNames = new Set(allowList);
c29f1c
+        this._initializedPromise = new Promise(resolve => {
c29f1c
+            this._resolveInitialized = resolve;
c29f1c
+        });
c29f1c
+
c29f1c
         this._watchList = allowList.map(name => {
c29f1c
             return Gio.DBus.watch_name(Gio.BusType.SESSION,
c29f1c
                 name,
c29f1c
                 Gio.BusNameWatcherFlags.NONE,
c29f1c
-                (conn_, name_, owner) => this._allowlistMap.set(name, owner),
c29f1c
-                () => this._allowlistMap.delete(name));
c29f1c
+                (conn_, name_, owner) => {
c29f1c
+                    this._allowlistMap.set(name, owner);
c29f1c
+                    this._checkAndResolveInitialized(name);
c29f1c
+                },
c29f1c
+                () => {
c29f1c
+                    this._allowlistMap.delete(name);
c29f1c
+                    this._checkAndResolveInitialized(name);
c29f1c
+                });
c29f1c
         });
c29f1c
     }
c29f1c
 
c29f1c
     /**
c29f1c
+     * @param {string} name - bus name for which the watcher got initialized
c29f1c
+     */
c29f1c
+    _checkAndResolveInitialized(name) {
c29f1c
+        if (this._uninitializedNames.delete(name) &&
c29f1c
+            this._uninitializedNames.size === 0)
c29f1c
+            this._resolveInitialized();
c29f1c
+    }
c29f1c
+
c29f1c
+    /**
c29f1c
+     * @async
c29f1c
      * @param {string} sender - the bus name that invoked the checked method
c29f1c
      * @returns {bool}
c29f1c
      */
c29f1c
-    _isSenderAllowed(sender) {
c29f1c
+    async _isSenderAllowed(sender) {
c29f1c
+        await this._initializedPromise;
c29f1c
         return [...this._allowlistMap.values()].includes(sender);
c29f1c
     }
c29f1c
 
c29f1c
@@ -507,15 +529,16 @@ var DBusSenderChecker = class {
c29f1c
      * Check whether the bus name that invoked @invocation maps
c29f1c
      * to an entry in the allow list.
c29f1c
      *
c29f1c
+     * @async
c29f1c
      * @throws
c29f1c
      * @param {Gio.DBusMethodInvocation} invocation - the invocation
c29f1c
      * @returns {void}
c29f1c
      */
c29f1c
-    checkInvocation(invocation) {
c29f1c
+    async checkInvocation(invocation) {
c29f1c
         if (global.context.unsafe_mode)
c29f1c
             return;
c29f1c
 
c29f1c
-        if (this._isSenderAllowed(invocation.get_sender()))
c29f1c
+        if (await this._isSenderAllowed(invocation.get_sender()))
c29f1c
             return;
c29f1c
 
c29f1c
         throw new GLib.Error(Gio.DBusError,
c29f1c
diff --git a/js/ui/screenshot.js b/js/ui/screenshot.js
c29f1c
index ae1156f47..97fcfacd0 100644
c29f1c
--- a/js/ui/screenshot.js
c29f1c
+++ b/js/ui/screenshot.js
c29f1c
@@ -37,7 +37,7 @@ var ScreenshotService = class {
c29f1c
         Gio.DBus.session.own_name('org.gnome.Shell.Screenshot', Gio.BusNameOwnerFlags.REPLACE, null, null);
c29f1c
     }
c29f1c
 
c29f1c
-    _createScreenshot(invocation, needsDisk = true, restrictCallers = true) {
c29f1c
+    async _createScreenshot(invocation, needsDisk = true, restrictCallers = true) {
c29f1c
         let lockedDown = false;
c29f1c
         if (needsDisk)
c29f1c
             lockedDown = this._lockdownSettings.get_boolean('disable-save-to-disk');
c29f1c
@@ -55,7 +55,7 @@ var ScreenshotService = class {
c29f1c
             return null;
c29f1c
         } else if (restrictCallers) {
c29f1c
             try {
c29f1c
-                this._senderChecker.checkInvocation(invocation);
c29f1c
+                await this._senderChecker.checkInvocation(invocation);
c29f1c
             } catch (e) {
c29f1c
                 invocation.return_gerror(e);
c29f1c
                 return null;
c29f1c
@@ -200,7 +200,7 @@ var ScreenshotService = class {
c29f1c
                                             "Invalid params");
c29f1c
             return;
c29f1c
         }
c29f1c
-        let screenshot = this._createScreenshot(invocation);
c29f1c
+        let screenshot = await this._createScreenshot(invocation);
c29f1c
         if (!screenshot)
c29f1c
             return;
c29f1c
 
c29f1c
@@ -223,7 +223,7 @@ var ScreenshotService = class {
c29f1c
 
c29f1c
     async ScreenshotWindowAsync(params, invocation) {
c29f1c
         let [includeFrame, includeCursor, flash, filename] = params;
c29f1c
-        let screenshot = this._createScreenshot(invocation);
c29f1c
+        let screenshot = await this._createScreenshot(invocation);
c29f1c
         if (!screenshot)
c29f1c
             return;
c29f1c
 
c29f1c
@@ -246,7 +246,7 @@ var ScreenshotService = class {
c29f1c
 
c29f1c
     async ScreenshotAsync(params, invocation) {
c29f1c
         let [includeCursor, flash, filename] = params;
c29f1c
-        let screenshot = this._createScreenshot(invocation);
c29f1c
+        let screenshot = await this._createScreenshot(invocation);
c29f1c
         if (!screenshot)
c29f1c
             return;
c29f1c
 
c29f1c
@@ -269,7 +269,7 @@ var ScreenshotService = class {
c29f1c
 
c29f1c
     async SelectAreaAsync(params, invocation) {
c29f1c
         try {
c29f1c
-            this._senderChecker.checkInvocation(invocation);
c29f1c
+            await this._senderChecker.checkInvocation(invocation);
c29f1c
         } catch (e) {
c29f1c
             invocation.return_gerror(e);
c29f1c
             return;
c29f1c
@@ -289,9 +289,9 @@ var ScreenshotService = class {
c29f1c
         }
c29f1c
     }
c29f1c
 
c29f1c
-    FlashAreaAsync(params, invocation) {
c29f1c
+    async FlashAreaAsync(params, invocation) {
c29f1c
         try {
c29f1c
-            this._senderChecker.checkInvocation(invocation);
c29f1c
+            await this._senderChecker.checkInvocation(invocation);
c29f1c
         } catch (e) {
c29f1c
             invocation.return_gerror(e);
c29f1c
             return;
c29f1c
@@ -311,7 +311,7 @@ var ScreenshotService = class {
c29f1c
     }
c29f1c
 
c29f1c
     async PickColorAsync(params, invocation) {
c29f1c
-        const screenshot = this._createScreenshot(invocation, false, false);
c29f1c
+        const screenshot = await this._createScreenshot(invocation, false, false);
c29f1c
         if (!screenshot)
c29f1c
             return;
c29f1c
 
c29f1c
diff --git a/js/ui/shellDBus.js b/js/ui/shellDBus.js
c29f1c
index c511314f9..39bba7aa3 100644
c29f1c
--- a/js/ui/shellDBus.js
c29f1c
+++ b/js/ui/shellDBus.js
c29f1c
@@ -81,13 +81,14 @@ var GnomeShell = class {
c29f1c
     /**
c29f1c
      * Focus the overview's search entry
c29f1c
      *
c29f1c
+     * @async
c29f1c
      * @param {...any} params - method parameters
c29f1c
      * @param {Gio.DBusMethodInvocation} invocation - the invocation
c29f1c
      * @returns {void}
c29f1c
      */
c29f1c
-    FocusSearchAsync(params, invocation) {
c29f1c
+    async FocusSearchAsync(params, invocation) {
c29f1c
         try {
c29f1c
-            this._senderChecker.checkInvocation(invocation);
c29f1c
+            await this._senderChecker.checkInvocation(invocation);
c29f1c
         } catch (e) {
c29f1c
             invocation.return_gerror(e);
c29f1c
             return;
c29f1c
@@ -100,13 +101,14 @@ var GnomeShell = class {
c29f1c
     /**
c29f1c
      * Show OSD with the specified parameters
c29f1c
      *
c29f1c
+     * @async
c29f1c
      * @param {...any} params - method parameters
c29f1c
      * @param {Gio.DBusMethodInvocation} invocation - the invocation
c29f1c
      * @returns {void}
c29f1c
      */
c29f1c
-    ShowOSDAsync([params], invocation) {
c29f1c
+    async ShowOSDAsync([params], invocation) {
c29f1c
         try {
c29f1c
-            this._senderChecker.checkInvocation(invocation);
c29f1c
+            await this._senderChecker.checkInvocation(invocation);
c29f1c
         } catch (e) {
c29f1c
             invocation.return_gerror(e);
c29f1c
             return;
c29f1c
@@ -143,9 +145,9 @@ var GnomeShell = class {
c29f1c
      * @param {Gio.DBusMethodInvocation} invocation - the invocation
c29f1c
      * @returns {void}
c29f1c
      */
c29f1c
-    FocusAppAsync([id], invocation) {
c29f1c
+    async FocusAppAsync([id], invocation) {
c29f1c
         try {
c29f1c
-            this._senderChecker.checkInvocation(invocation);
c29f1c
+            await this._senderChecker.checkInvocation(invocation);
c29f1c
         } catch (e) {
c29f1c
             invocation.return_gerror(e);
c29f1c
             return;
c29f1c
@@ -167,13 +169,14 @@ var GnomeShell = class {
c29f1c
     /**
c29f1c
      * Show the overview's app grid
c29f1c
      *
c29f1c
+     * @async
c29f1c
      * @param {...any} params - method parameters
c29f1c
      * @param {Gio.DBusMethodInvocation} invocation - the invocation
c29f1c
      * @returns {void}
c29f1c
      */
c29f1c
-    ShowApplicationsAsync(params, invocation) {
c29f1c
+    async ShowApplicationsAsync(params, invocation) {
c29f1c
         try {
c29f1c
-            this._senderChecker.checkInvocation(invocation);
c29f1c
+            await this._senderChecker.checkInvocation(invocation);
c29f1c
         } catch (e) {
c29f1c
             invocation.return_gerror(e);
c29f1c
             return;
c29f1c
@@ -183,9 +186,9 @@ var GnomeShell = class {
c29f1c
         invocation.return_value(null);
c29f1c
     }
c29f1c
 
c29f1c
-    GrabAcceleratorAsync(params, invocation) {
c29f1c
+    async GrabAcceleratorAsync(params, invocation) {
c29f1c
         try {
c29f1c
-            this._senderChecker.checkInvocation(invocation);
c29f1c
+            await this._senderChecker.checkInvocation(invocation);
c29f1c
         } catch (e) {
c29f1c
             invocation.return_gerror(e);
c29f1c
             return;
c29f1c
@@ -197,9 +200,9 @@ var GnomeShell = class {
c29f1c
         invocation.return_value(GLib.Variant.new('(u)', [bindingAction]));
c29f1c
     }
c29f1c
 
c29f1c
-    GrabAcceleratorsAsync(params, invocation) {
c29f1c
+    async GrabAcceleratorsAsync(params, invocation) {
c29f1c
         try {
c29f1c
-            this._senderChecker.checkInvocation(invocation);
c29f1c
+            await this._senderChecker.checkInvocation(invocation);
c29f1c
         } catch (e) {
c29f1c
             invocation.return_gerror(e);
c29f1c
             return;
c29f1c
@@ -215,9 +218,9 @@ var GnomeShell = class {
c29f1c
         invocation.return_value(GLib.Variant.new('(au)', [bindingActions]));
c29f1c
     }
c29f1c
 
c29f1c
-    UngrabAcceleratorAsync(params, invocation) {
c29f1c
+    async UngrabAcceleratorAsync(params, invocation) {
c29f1c
         try {
c29f1c
-            this._senderChecker.checkInvocation(invocation);
c29f1c
+            await this._senderChecker.checkInvocation(invocation);
c29f1c
         } catch (e) {
c29f1c
             invocation.return_gerror(e);
c29f1c
             return;
c29f1c
@@ -230,9 +233,9 @@ var GnomeShell = class {
c29f1c
         invocation.return_value(GLib.Variant.new('(b)', [ungrabSucceeded]));
c29f1c
     }
c29f1c
 
c29f1c
-    UngrabAcceleratorsAsync(params, invocation) {
c29f1c
+    async UngrabAcceleratorsAsync(params, invocation) {
c29f1c
         try {
c29f1c
-            this._senderChecker.checkInvocation(invocation);
c29f1c
+            await this._senderChecker.checkInvocation(invocation);
c29f1c
         } catch (e) {
c29f1c
             invocation.return_gerror(e);
c29f1c
             return;
c29f1c
@@ -317,9 +320,9 @@ var GnomeShell = class {
c29f1c
         this._grabbers.delete(name);
c29f1c
     }
c29f1c
 
c29f1c
-    ShowMonitorLabelsAsync(params, invocation) {
c29f1c
+    async ShowMonitorLabelsAsync(params, invocation) {
c29f1c
         try {
c29f1c
-            this._senderChecker.checkInvocation(invocation);
c29f1c
+            await this._senderChecker.checkInvocation(invocation);
c29f1c
         } catch (e) {
c29f1c
             invocation.return_gerror(e);
c29f1c
             return;
c29f1c
@@ -331,9 +334,9 @@ var GnomeShell = class {
c29f1c
         invocation.return_value(null);
c29f1c
     }
c29f1c
 
c29f1c
-    HideMonitorLabelsAsync(params, invocation) {
c29f1c
+    async HideMonitorLabelsAsync(params, invocation) {
c29f1c
         try {
c29f1c
-            this._senderChecker.checkInvocation(invocation);
c29f1c
+            await this._senderChecker.checkInvocation(invocation);
c29f1c
         } catch (e) {
c29f1c
             invocation.return_gerror(e);
c29f1c
             return;
c29f1c
-- 
c29f1c
2.35.1
c29f1c