[glib/sandboxed-dbus-activation] Make dbus activation sandbox-aware



commit d78e246de0fcbb47746f2083ce1c60ea1274c5a8
Author: Matthias Clasen <mclasen redhat com>
Date:   Sat May 6 14:22:38 2017 -0400

    Make dbus activation sandbox-aware
    
    When we call org.freedesktop.Application.Open to activate
    an application and pass file uris, the application may not
    be able to see the files due to a flatpak sandbox. Flatpak
    puts an X-Flatpak marker in desktop files that it exports,
    so we can easily recognize applications that may be affected
    by this. In this case, call the document portal to export
    the files and pass the resulting uri's instead of the original
    ones.

 gio/gdesktopappinfo.c |  203 +++++++++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 196 insertions(+), 7 deletions(-)
---
diff --git a/gio/gdesktopappinfo.c b/gio/gdesktopappinfo.c
index 81dff27..c35ed12 100644
--- a/gio/gdesktopappinfo.c
+++ b/gio/gdesktopappinfo.c
@@ -36,6 +36,7 @@
 #include "gdesktopappinfo.h"
 #ifdef G_OS_UNIX
 #include "glib-unix.h"
+#include "gunixfdlist.h"
 #endif
 #include "gfile.h"
 #include "gioerror.h"
@@ -2835,17 +2836,15 @@ g_desktop_app_info_make_platform_data (GDesktopAppInfo   *info,
   return g_variant_builder_end (&builder);
 }
 
-static gboolean
-g_desktop_app_info_launch_uris_with_dbus (GDesktopAppInfo    *info,
-                                          GDBusConnection    *session_bus,
-                                          GList              *uris,
-                                          GAppLaunchContext  *launch_context)
+static void
+launch_uris_with_dbus (GDesktopAppInfo    *info,
+                       GDBusConnection    *session_bus,
+                       GList              *uris,
+                       GAppLaunchContext  *launch_context)
 {
   GVariantBuilder builder;
   gchar *object_path;
 
-  g_return_val_if_fail (info != NULL, FALSE);
-
   g_variant_builder_init (&builder, G_VARIANT_TYPE_TUPLE);
 
   if (uris)
@@ -2865,10 +2864,200 @@ g_desktop_app_info_launch_uris_with_dbus (GDesktopAppInfo    *info,
    * This is what startup-notification's job is...
    */
   object_path = object_path_from_appid (info->app_id);
+
   g_dbus_connection_call (session_bus, info->app_id, object_path, "org.freedesktop.Application",
                           uris ? "Open" : "Activate", g_variant_builder_end (&builder),
                           NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
+
   g_free (object_path);
+}
+
+#ifdef G_OS_UNIX
+typedef struct {
+  GDesktopAppInfo *info;
+  GAppLaunchContext *context;
+  GList *uris;
+  gboolean *as_is;
+} LaunchData;
+
+static void
+free_launch_data (LaunchData *data)
+{
+  g_object_unref (data->info);
+  if (data->context)
+    g_object_unref (data->context);
+  g_list_free_full (data->uris, g_free);
+  g_free (data->as_is);
+  g_free (data);
+}
+
+static void
+rewrite_uris_done (GObject      *source,
+                   GAsyncResult *res,
+                   gpointer      data)
+{
+  GDBusConnection *session_bus = G_DBUS_CONNECTION (source);
+  LaunchData *ld = data;
+  g_autoptr(GVariant) ret = NULL;
+  g_autoptr(GError) error = NULL;
+  char *mountpoint;
+  char **doc_ids;
+  GList *l;
+  GList *ruris;
+  int i, j;
+  g_autoptr(GVariant) extra_out = NULL;
+
+  ret = g_dbus_connection_call_with_unix_fd_list_finish (session_bus, NULL, res, &error);
+  if (ret == NULL)
+    {
+      g_warning ("Failed to call AddFull: %s", error->message);
+      launch_uris_with_dbus (ld->info, session_bus, ld->uris, ld->context);
+      free_launch_data (ld);
+      return;
+    }
+
+  g_variant_get (ret, "(^a&s@a{sv})", &doc_ids, &extra_out);
+  if (!g_variant_lookup (extra_out, "mountpoint", "^ay", &mountpoint))
+    {
+      g_warning ("AddFull did not return mountpoint");
+      launch_uris_with_dbus (ld->info, session_bus, ld->uris, ld->context);
+      free_launch_data (ld);
+      return;
+    }
+
+  ruris = NULL;
+
+  for (l = ld->uris, i = 0, j = 0; l; l = l->next, i++)
+    {
+      char *uri = l->data;
+      char *ruri;
+
+      if (ld->as_is[i]) /* use as-is, not a file uri */
+        {
+          ruri = g_strdup (uri);
+        }
+      else if (strcmp (doc_ids[j], "") == 0) /* not rewritten */
+        {
+          ruri = g_strdup (uri);
+          j++;
+        }
+      else
+        {
+           char *basename = g_path_get_basename (uri + strlen ("file:"));
+           char *doc_path = g_build_filename (mountpoint, doc_ids[j], basename, NULL);
+           ruri = g_strconcat ("file:", doc_path, NULL);
+           g_free (basename);
+           g_free (doc_path);
+           j++;
+        }
+
+      ruris = g_list_append (ruris, ruri);
+    }
+
+  launch_uris_with_dbus (ld->info, session_bus, ruris, ld->context);
+  free_launch_data (ld);
+  g_list_free_full (ruris, g_free);
+}
+
+static void
+rewrite_uris_for_portal (GDesktopAppInfo   *info,
+                         GDBusConnection   *session_bus,
+                         GList             *uris,
+                         GAppLaunchContext *context)
+{
+  GVariantBuilder builder;
+  GUnixFDList *fd_list = NULL;
+  GList *l;
+  int i;
+  LaunchData *data;
+  const char *permissions[] = { "read", "write", NULL };
+
+  data = g_new (LaunchData, 1);
+  data->info = g_object_ref (info);
+  data->context = context ? g_object_ref (context) : NULL;
+  data->uris = g_list_copy_deep (uris, (GCopyFunc)g_strdup, NULL);
+  data->as_is = g_new0 (gboolean, g_list_length (uris));
+
+  g_variant_builder_init (&builder, G_VARIANT_TYPE_TUPLE);
+  g_variant_builder_open (&builder, G_VARIANT_TYPE ("ah"));
+
+  fd_list = g_unix_fd_list_new ();
+  for (l = uris, i = 0; l; l = l->next, i++)
+    {
+      const char *uri = l->data;
+      int idx = -1;
+
+      if (g_str_has_prefix (uri, "file://"))
+        {
+          const char *path;
+          int fd;
+
+          path = uri + strlen ("file://");
+
+          fd = open (path, O_CLOEXEC | O_PATH);
+          if (fd >= 0)
+            {
+              idx = g_unix_fd_list_append (fd_list, fd, NULL);
+              close (fd);
+            }
+        }
+
+      if (idx != -1)
+        g_variant_builder_add (&builder, "h", idx);
+      else
+        data->as_is[i] = TRUE;
+    }
+
+  g_variant_builder_close (&builder);
+
+  g_variant_builder_add (&builder, "u", 0);
+  g_variant_builder_add (&builder, "s", info->app_id);
+  g_variant_builder_add (&builder, "^as", permissions);
+
+  if (g_unix_fd_list_get_length (fd_list) > 0)
+    g_dbus_connection_call_with_unix_fd_list (session_bus,
+                                              "org.freedesktop.portal.Documents",
+                                              "/org/freedesktop/portal/documents",
+                                              "org.freedesktop.portal.Documents",
+                                              "AddFull",
+                                              g_variant_builder_end (&builder),
+                                              G_VARIANT_TYPE ("(asa{sv})"),
+                                              G_DBUS_CALL_FLAGS_NONE,
+                                              -1,
+                                              fd_list,
+                                              NULL,
+                                              rewrite_uris_done,
+                                              data);
+  else
+    {
+      launch_uris_with_dbus (info, session_bus, uris, context);
+      free_launch_data (data);
+    }
+
+  g_object_unref (fd_list);
+}
+
+static gboolean
+should_rewrite_uris_for_portal (GDesktopAppInfo *info)
+{
+  return g_desktop_app_info_get_boolean (info, "X-Flatpak");
+}
+#endif
+
+static gboolean
+g_desktop_app_info_launch_uris_with_dbus (GDesktopAppInfo    *info,
+                                          GDBusConnection    *session_bus,
+                                          GList              *uris,
+                                          GAppLaunchContext  *launch_context)
+{
+  g_return_val_if_fail (info != NULL, FALSE);
+
+#ifdef G_OS_UNIX
+  if (should_rewrite_uris_for_portal (info))
+    rewrite_uris_for_portal (info, session_bus, uris, launch_context);
+  else
+#endif
+    launch_uris_with_dbus (info, session_bus, uris, launch_context);
 
   return TRUE;
 }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]