diff --git a/common/flatpak-context-private.h b/common/flatpak-context-private.h
index 3d1b3418..5a9ebe4c 100644
--- a/common/flatpak-context-private.h
+++ b/common/flatpak-context-private.h
@@ -50,6 +50,7 @@ typedef enum {
FLATPAK_CONTEXT_SOCKET_PCSC = 1 << 7,
FLATPAK_CONTEXT_SOCKET_CUPS = 1 << 8,
FLATPAK_CONTEXT_SOCKET_GPG_AGENT = 1 << 9,
+ FLATPAK_CONTEXT_SOCKET_INHERIT_WAYLAND_SOCKET = 1 << 10,
} FlatpakContextSockets;
typedef enum {
diff --git a/common/flatpak-context.c b/common/flatpak-context.c
index 2d98d5c9..297a89ef 100644
--- a/common/flatpak-context.c
+++ b/common/flatpak-context.c
@@ -61,6 +61,7 @@ const char *flatpak_context_sockets[] = {
"pcsc",
"cups",
"gpg-agent",
+ "inherit-wayland-socket",
NULL
};
diff --git a/common/flatpak-run-sockets.c b/common/flatpak-run-sockets.c
index a20e9f34..be120f36 100644
--- a/common/flatpak-run-sockets.c
+++ b/common/flatpak-run-sockets.c
@@ -178,12 +178,15 @@ flatpak_run_add_socket_args_environment (FlatpakBwrap *bwrap,
{
gboolean has_wayland = FALSE;
gboolean allow_x11;
+ gboolean inherit_wayland_socket;
if (sockets & FLATPAK_CONTEXT_SOCKET_WAYLAND)
{
g_info ("Allowing wayland access");
g_assert (app_id && instance_id);
- has_wayland = flatpak_run_add_wayland_args (bwrap, app_id, instance_id);
+ inherit_wayland_socket = (sockets & FLATPAK_CONTEXT_SOCKET_INHERIT_WAYLAND_SOCKET) != 0;
+ has_wayland = flatpak_run_add_wayland_args (bwrap, app_id, instance_id,
+ inherit_wayland_socket);
}
if ((sockets & FLATPAK_CONTEXT_SOCKET_FALLBACK_X11) != 0)
diff --git a/common/flatpak-run-wayland-private.h b/common/flatpak-run-wayland-private.h
index 14389a91..ad00d234 100644
--- a/common/flatpak-run-wayland-private.h
+++ b/common/flatpak-run-wayland-private.h
@@ -31,6 +31,7 @@ G_BEGIN_DECLS
gboolean
flatpak_run_add_wayland_args (FlatpakBwrap *bwrap,
const char *app_id,
- const char *instance_id);
+ const char *instance_id,
+ gboolean inherit_wayland_socket);
G_END_DECLS
diff --git a/common/flatpak-run-wayland.c b/common/flatpak-run-wayland.c
index 0670ab68..1aafddbb 100644
--- a/common/flatpak-run-wayland.c
+++ b/common/flatpak-run-wayland.c
@@ -30,6 +30,38 @@
#include "flatpak-utils-private.h"
+static char *
+get_wayland_socket_path (void)
+{
+ g_autofree char *user_runtime_dir = flatpak_get_real_xdg_runtime_dir ();
+ const char *wayland_display;
+
+ wayland_display = g_getenv ("WAYLAND_DISPLAY");
+ if (!wayland_display)
+ wayland_display = "wayland-0";
+
+ if (wayland_display[0] == '/')
+ return g_strdup (wayland_display);
+
+ return g_build_filename (user_runtime_dir, wayland_display, NULL);
+}
+
+static int
+get_wayland_socket_fd (void)
+{
+ const char *wayland_socket_fd;
+ guint64 fd;
+
+ wayland_socket_fd = g_getenv ("WAYLAND_SOCKET");
+ if (!wayland_socket_fd)
+ return -1;
+
+ if (!g_ascii_string_to_unsigned (wayland_socket_fd, 10, 0, INT_MAX, &fd, NULL))
+ return -1;
+
+ return (int) fd;
+}
+
#ifdef ENABLE_WAYLAND_SECURITY_CONTEXT
static void registry_handle_global (void *data, struct wl_registry *registry,
@@ -57,6 +89,29 @@ static const struct wl_registry_listener registry_listener = {
.global_remove = registry_handle_global_remove,
};
+/* Similar to wl_display_connect (), but does not use WAYLAND_SOCKET,
+ * which can only be used once, and also does not unset environment
+ * variables, which would not be thread-safe. */
+static struct wl_display *
+connect_to_wayland_display (void)
+{
+ struct sockaddr_un sockaddr = {0};
+ g_autofree char *socket_path = NULL;
+ glnx_autofd int fd = -1;
+
+ socket_path = get_wayland_socket_path ();
+ fd = socket (AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
+ if (fd < 0)
+ return NULL;
+
+ sockaddr.sun_family = AF_UNIX;
+ snprintf (sockaddr.sun_path, sizeof (sockaddr.sun_path), "%s", socket_path);
+ if (connect (fd, (struct sockaddr *) &sockaddr, sizeof (sockaddr)) < 0)
+ return NULL;
+
+ return wl_display_connect_to_fd (g_steal_fd (&fd));
+}
+
static char *
create_wl_socket (char *template)
{
@@ -94,7 +149,17 @@ flatpak_run_add_wayland_security_context_args (FlatpakBwrap *bwrap,
*available_out = TRUE;
- display = wl_display_connect (NULL);
+ /* We don't use wl_display_connect () here, for two reasons:
+ * 1. It would unsetenv ("WAYLAND_SOCKET"), which is not thread-safe.
+ * 2. If the compositor has set WAYLAND_SOCKET to a special, higher-privileged
+ * socket, the application should be able to get those privileges for its first
+ * connection; but that fd can only be used once, so having flatpak itself
+ * do that first connection would defeat that mechanism.
+ *
+ * We still set up a security context for the second and subsequent connections
+ * to Wayland from within the sandbox.
+ */
+ display = connect_to_wayland_display ();
if (!display)
return FALSE;
@@ -171,14 +236,15 @@ out:
gboolean
flatpak_run_add_wayland_args (FlatpakBwrap *bwrap,
const char *app_id,
- const char *instance_id)
+ const char *instance_id,
+ gboolean inherit_wayland_socket)
{
const char *wayland_display;
- g_autofree char *user_runtime_dir = flatpak_get_real_xdg_runtime_dir ();
g_autofree char *wayland_socket = NULL;
g_autofree char *sandbox_wayland_socket = NULL;
gboolean res = FALSE;
struct stat statbuf;
+ int fd;
#ifdef ENABLE_WAYLAND_SECURITY_CONTEXT
gboolean security_context_available = FALSE;
@@ -194,10 +260,7 @@ flatpak_run_add_wayland_args (FlatpakBwrap *bwrap,
if (!wayland_display)
wayland_display = "wayland-0";
- if (wayland_display[0] == '/')
- wayland_socket = g_strdup (wayland_display);
- else
- wayland_socket = g_build_filename (user_runtime_dir, wayland_display, NULL);
+ wayland_socket = get_wayland_socket_path ();
if (!g_str_has_prefix (wayland_display, "wayland-") ||
strchr (wayland_display, '/') != NULL)
@@ -217,5 +280,29 @@ flatpak_run_add_wayland_args (FlatpakBwrap *bwrap,
NULL);
flatpak_bwrap_add_runtime_dir_member (bwrap, wayland_display);
}
+
+ /* If inherit-wayland-socket is not set, unset WAYLAND_SOCKET unconditionally
+ * without checking the validity of the value of WAYLAND_SOCKET. */
+ if (!inherit_wayland_socket)
+ flatpak_bwrap_unset_env (bwrap, "WAYLAND_SOCKET");
+
+ fd = get_wayland_socket_fd ();
+ if (fd >= 0)
+ {
+ if (inherit_wayland_socket)
+ {
+ flatpak_bwrap_add_fd (bwrap, fd);
+ }
+ else
+ {
+ /* Make sure the fd is close-on-execute so it won't be inherited by the
+ * application. We do this in preference to closing it, because if this function
+ * was somehow called twice, and the same fd number was reused for an
+ * unrelated purpose, we don't want to close the unrelated fd the
+ * second time. */
+ fcntl (fd, F_SETFD, FD_CLOEXEC);
+ }
+ }
+
return res;
}
diff --git a/doc/flatpak-build-finish.xml b/doc/flatpak-build-finish.xml
index 2c7a1393..50394baa 100644
--- a/doc/flatpak-build-finish.xml
+++ b/doc/flatpak-build-finish.xml
@@ -134,7 +134,7 @@
Expose a well-known socket to the application. This updates
the [Context] group in the metadata.
SOCKET must be one of: x11, wayland, fallback-x11, pulseaudio, system-bus, session-bus,
- ssh-auth, pcsc, cups, gpg-agent.
+ ssh-auth, pcsc, cups, gpg-agent, inherit-wayland-socket.
This option can be used multiple times.
The fallback-x11 option makes the X11 socket available only if
@@ -151,7 +151,7 @@
Don't expose a well known socket to the application. This updates
the [Context] group in the metadata.
SOCKET must be one of: x11, wayland, fallback-x11, pulseaudio, system-bus, session-bus,
- ssh-auth, pcsc, cups, gpg-agent.
+ ssh-auth, pcsc, cups, gpg-agent, inherit-wayland-socket.
This option can be used multiple times.
diff --git a/doc/flatpak-build.xml b/doc/flatpak-build.xml
index a9e29f5b..d197800f 100644
--- a/doc/flatpak-build.xml
+++ b/doc/flatpak-build.xml
@@ -149,7 +149,7 @@
Expose a well-known socket to the application. This overrides to
the Context section from the application metadata.
SOCKET must be one of: x11, wayland, fallback-x11, pulseaudio, system-bus, session-bus,
- ssh-auth, pcsc, cups, gpg-agent.
+ ssh-auth, pcsc, cups, gpg-agent, inherit-wayland-socket.
This option can be used multiple times.
@@ -161,7 +161,7 @@
Don't expose a well-known socket to the application. This overrides to
the Context section from the application metadata.
SOCKET must be one of: x11, wayland, fallback-x11, pulseaudio, system-bus, session-bus,
- ssh-auth, pcsc, cups, gpg-agent.
+ ssh-auth, pcsc, cups, gpg-agent, inherit-wayland-socket.
This option can be used multiple times.
diff --git a/doc/flatpak-metadata.xml b/doc/flatpak-metadata.xml
index a8ab2ee9..d847ed7a 100644
--- a/doc/flatpak-metadata.xml
+++ b/doc/flatpak-metadata.xml
@@ -152,7 +152,7 @@
List of well-known sockets to make available in the sandbox.
Possible sockets: x11, wayland, fallback-x11, pulseaudio, session-bus, system-bus,
- ssh-auth, pcsc, cups.
+ ssh-auth, pcsc, cups, gpg-agent, inherit-wayland-socket.
When making a socket available, flatpak also sets
well-known environment variables like DISPLAY or
DBUS_SYSTEM_BUS_ADDRESS to let the application
diff --git a/doc/flatpak-override.xml b/doc/flatpak-override.xml
index 352919da..a74b30f0 100644
--- a/doc/flatpak-override.xml
+++ b/doc/flatpak-override.xml
@@ -137,7 +137,7 @@
Expose a well-known socket to the application. This overrides to
the Context section from the application metadata.
SOCKET must be one of: x11, wayland, fallback-x11, pulseaudio, system-bus, session-bus,
- ssh-auth, pcsc, cups, gpg-agent.
+ ssh-auth, pcsc, cups, gpg-agent, inherit-wayland-socket.
This option can be used multiple times.
@@ -149,7 +149,7 @@
Don't expose a well-known socket to the application. This overrides to
the Context section from the application metadata.
SOCKET must be one of: x11, wayland, fallback-x11, pulseaudio, system-bus, session-bus,
- ssh-auth, pcsc, cups, gpg-agent.
+ ssh-auth, pcsc, cups, gpg-agent, inherit-wayland-socket.
This option can be used multiple times.
diff --git a/doc/flatpak-run.xml b/doc/flatpak-run.xml
index 7a9611cb..2cb46b20 100644
--- a/doc/flatpak-run.xml
+++ b/doc/flatpak-run.xml
@@ -308,7 +308,7 @@
Expose a well known socket to the application. This overrides to
the Context section from the application metadata.
SOCKET must be one of: x11, wayland, fallback-x11, pulseaudio, system-bus, session-bus,
- ssh-auth, pcsc, cups, gpg-agent.
+ ssh-auth, pcsc, cups, gpg-agent, inherit-wayland-socket.
This option can be used multiple times.
@@ -320,7 +320,7 @@
Don't expose a well known socket to the application. This overrides to
the Context section from the application metadata.
SOCKET must be one of: x11, wayland, fallback-x11, pulseaudio, system-bus, session-bus,
- ssh-auth, pcsc, cups, gpg-agent.
+ ssh-auth, pcsc, cups, gpg-agent, inherit-wayland-socket.
This option can be used multiple times.
diff --git a/tests/test-exports.c b/tests/test-exports.c
index 8a3a4cfe..a20ed0c9 100644
--- a/tests/test-exports.c
+++ b/tests/test-exports.c
@@ -226,7 +226,7 @@ test_full_context (void)
FLATPAK_METADATA_GROUP_CONTEXT,
FLATPAK_METADATA_KEY_SOCKETS,
"x11;wayland;pulseaudio;session-bus;system-bus;"
- "fallback-x11;ssh-auth;pcsc;cups;");
+ "fallback-x11;ssh-auth;pcsc;cups;inherit-wayland-socket;");
g_key_file_set_value (keyfile,
FLATPAK_METADATA_GROUP_CONTEXT,
FLATPAK_METADATA_KEY_DEVICES,
@@ -281,6 +281,7 @@ test_full_context (void)
g_assert_cmpuint (context->sockets, ==,
(FLATPAK_CONTEXT_SOCKET_X11 |
FLATPAK_CONTEXT_SOCKET_WAYLAND |
+ FLATPAK_CONTEXT_SOCKET_INHERIT_WAYLAND_SOCKET |
FLATPAK_CONTEXT_SOCKET_PULSEAUDIO |
FLATPAK_CONTEXT_SOCKET_SESSION_BUS |
FLATPAK_CONTEXT_SOCKET_SYSTEM_BUS |
@@ -375,6 +376,7 @@ test_full_context (void)
i = 0;
g_assert_cmpstr (strv[i++], ==, "cups");
g_assert_cmpstr (strv[i++], ==, "fallback-x11");
+ g_assert_cmpstr (strv[i++], ==, "inherit-wayland-socket");
g_assert_cmpstr (strv[i++], ==, "pcsc");
g_assert_cmpstr (strv[i++], ==, "pulseaudio");
g_assert_cmpstr (strv[i++], ==, "session-bus");