From a127fb49cbd90692afe294855a8a36bfeb2f6e8f Mon Sep 17 00:00:00 2001
From: Simon McVittie <smcv@collabora.com>
Date: Thu, 27 Mar 2025 19:24:26 +0000
Subject: [PATCH] wrap-setup: Bind-mount in the AT-SPI accessibility bus

AT-SPI has its own private D-Bus message bus, the "accessibility bus".
This is used to let applications export their window contents to
assistive technologies such as screen readers, and to let assistive
technologies send events to the applications. This avoids flooding the
session bus with AT-SPI traffic, which can be rather frequent.

If we want `steamwebhelper` to be accessible to assistive technologies,
it needs to be able to communicate with that bus. In older AT-SPI it
was an abstract AF_UNIX socket, which passes through "naturally",
but in newer AT-SPI it has been changed to be a filesystem-backed
AF_UNIX socket in order to allow sandboxing, therefore the socket needs
to be bind-mounted into our container.

As with the session bus, we can adapt Flatpak's code for this: Flatpak
would always use a proxy in order to impose a security boundary, but
pressure-vessel is specifically not a security boundary, so we can
simplify considerably.

steamrt/tasks#699

Signed-off-by: Simon McVittie <smcv@collabora.com>
---
 pressure-vessel/flatpak-run-dbus-private.h |  1 +
 pressure-vessel/flatpak-run-dbus.c         | 53 +++++++++++++++++++---
 pressure-vessel/wrap-setup.c               |  1 +
 3 files changed, 49 insertions(+), 6 deletions(-)

diff --git a/pressure-vessel/flatpak-run-dbus-private.h b/pressure-vessel/flatpak-run-dbus-private.h
index af950beb0..d78e4ffc3 100644
--- a/pressure-vessel/flatpak-run-dbus-private.h
+++ b/pressure-vessel/flatpak-run-dbus-private.h
@@ -56,6 +56,7 @@ gboolean flatpak_run_maybe_start_dbus_proxy (FlatpakBwrap *app_bwrap,
 /* Simplified interface for pressure-vessel */
 gboolean flatpak_run_add_session_dbus_args (FlatpakBwrap *app_bwrap);
 gboolean flatpak_run_add_system_dbus_args (FlatpakBwrap *app_bwrap);
+gboolean flatpak_run_add_a11y_dbus_args (FlatpakBwrap *app_bwrap);
 #endif
 
 G_END_DECLS
diff --git a/pressure-vessel/flatpak-run-dbus.c b/pressure-vessel/flatpak-run-dbus.c
index 4eed6dbed..34dcb60b8 100644
--- a/pressure-vessel/flatpak-run-dbus.c
+++ b/pressure-vessel/flatpak-run-dbus.c
@@ -404,12 +404,8 @@ flatpak_run_add_system_dbus_args (FlatpakBwrap   *app_bwrap)
   return FALSE;
 }
 
-#if 0
 gboolean
-flatpak_run_add_a11y_dbus_args (FlatpakBwrap   *app_bwrap,
-                                FlatpakBwrap   *proxy_arg_bwrap,
-                                FlatpakContext *context,
-                                FlatpakRunFlags flags)
+flatpak_run_add_a11y_dbus_args (FlatpakBwrap *app_bwrap)
 {
   static const char sandbox_socket_path[] = "/run/pressure-vessel/at-spi-bus";
   static const char sandbox_dbus_address[] = "unix:path=/run/pressure-vessel/at-spi-bus";
@@ -418,11 +414,15 @@ flatpak_run_add_a11y_dbus_args (FlatpakBwrap   *app_bwrap,
   g_autoptr(GError) local_error = NULL;
   g_autoptr(GDBusMessage) reply = NULL;
   g_autoptr(GDBusMessage) msg = NULL;
+#if 0
   g_autofree char *proxy_socket = NULL;
+#endif
   const char *value;
 
+#if 0
   if ((flags & FLATPAK_RUN_FLAG_NO_A11Y_BUS_PROXY) != 0)
     return FALSE;
+#endif
 
   session_bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
   if (session_bus == NULL)
@@ -470,6 +470,47 @@ flatpak_run_add_a11y_dbus_args (FlatpakBwrap   *app_bwrap,
         }
     }
 
+#if 1
+  /* Simplified from Flatpak: we don't restrict access or use a proxy,
+   * we just pass the socket through as-is */
+    {
+      g_autofree char *a11y_socket = NULL;
+      struct stat statbuf;
+
+      /* If AT-SPI is listening on an abstract AF_UNIX socket, then there
+       * is no socket to listen on, but that's fine because there is also
+       * no need to bind-mount anything: we don't unshare the network
+       * namespace, so the container will have access to all abstract
+       * sockets. In this case we can just return false and the right thing
+       * will happen. */
+
+      if (a11y_address != NULL)
+        a11y_socket = extract_unix_path_from_dbus_address (a11y_address);
+
+      if (a11y_socket == NULL)
+        {
+          g_autofree char *user_runtime_dir = flatpak_get_real_xdg_runtime_dir ();
+
+          /* Typical path on systemd systems */
+          a11y_socket = g_build_filename (user_runtime_dir, "at-spi", "bus", NULL);
+        }
+
+      if (a11y_socket == NULL
+          || stat (a11y_socket, &statbuf) < 0
+          || (statbuf.st_mode & S_IFMT) != S_IFSOCK
+          || statbuf.st_uid != getuid ())
+        return FALSE;
+
+      flatpak_bwrap_add_args (app_bwrap,
+                              "--ro-bind", a11y_socket, sandbox_socket_path,
+                              NULL);
+      flatpak_bwrap_set_env (app_bwrap, "AT_SPI_BUS_ADDRESS", sandbox_dbus_address, TRUE);
+      flatpak_bwrap_add_runtime_dir_member (app_bwrap, "at-spi-bus");
+    }
+
+#else
+  /* Original implementation from Flatpak */
+
   if (!a11y_address)
     return FALSE;
 
@@ -498,7 +539,7 @@ flatpak_run_add_a11y_dbus_args (FlatpakBwrap   *app_bwrap,
                           "--ro-bind", proxy_socket, sandbox_socket_path,
                           NULL);
   flatpak_bwrap_set_env (app_bwrap, "AT_SPI_BUS_ADDRESS", sandbox_dbus_address, TRUE);
+#endif
 
   return TRUE;
 }
-#endif
diff --git a/pressure-vessel/wrap-setup.c b/pressure-vessel/wrap-setup.c
index edda14e40..f0f5b48c6 100644
--- a/pressure-vessel/wrap-setup.c
+++ b/pressure-vessel/wrap-setup.c
@@ -205,6 +205,7 @@ pv_wrap_share_sockets (SrtEnvOverlay *container_env,
       flatpak_run_add_session_dbus_args (sharing_bwrap);
       flatpak_run_add_system_dbus_args (sharing_bwrap);
       flatpak_run_add_socket_args_late (sharing_bwrap, shares);
+      flatpak_run_add_a11y_dbus_args (sharing_bwrap);
       pv_wrap_add_pipewire_args (sharing_bwrap, container_env);
       pv_wrap_add_discord_args (sharing_bwrap);
     }
-- 
GitLab