mirror of
https://github.com/flatpak/flatpak.git
synced 2026-05-14 03:24:50 -04:00
Limit the usage of WAYLAND_SOCKET to an opt-in feature
1. For security context creation, only relies on WAYLAND_DISPLAY, do not use WAYLAND_SOCKET since the file descriptor defined by WAYLAND_SOCKET can be only consumed once. 2. Due to the incompatiblity between WAYLAND_SOCKET and the security context, add a new permission --socket=inherit-wayland-socket to limit the usage of WAYLAND_SOCKET to an opt-in feature. Only when this flag is set, WAYLAND_SOCKET will be passed to the sandbox. 3. When WAYLAND_SOCKET is not inherited, set FD_CLOEXEC to avoid it to be leaked the to sandbox. Closes: #5614
This commit is contained in:
committed by
Simon McVittie
parent
6e3cc82af3
commit
0402e1614c
@@ -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 {
|
||||
|
||||
@@ -61,6 +61,7 @@ const char *flatpak_context_sockets[] = {
|
||||
"pcsc",
|
||||
"cups",
|
||||
"gpg-agent",
|
||||
"inherit-wayland-socket",
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
</para><para>
|
||||
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.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
@@ -149,7 +149,7 @@
|
||||
Expose a well-known socket to the application. This overrides to
|
||||
the Context section from the application metadata.
|
||||
<arg choice="plain">SOCKET</arg> 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.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
@@ -161,7 +161,7 @@
|
||||
Don't expose a well-known socket to the application. This overrides to
|
||||
the Context section from the application metadata.
|
||||
<arg choice="plain">SOCKET</arg> 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.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
@@ -152,7 +152,7 @@
|
||||
<listitem><para>
|
||||
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
|
||||
|
||||
@@ -137,7 +137,7 @@
|
||||
Expose a well-known socket to the application. This overrides to
|
||||
the Context section from the application metadata.
|
||||
<arg choice="plain">SOCKET</arg> 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.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
@@ -149,7 +149,7 @@
|
||||
Don't expose a well-known socket to the application. This overrides to
|
||||
the Context section from the application metadata.
|
||||
<arg choice="plain">SOCKET</arg> 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.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
@@ -308,7 +308,7 @@
|
||||
Expose a well known socket to the application. This overrides to
|
||||
the Context section from the application metadata.
|
||||
<arg choice="plain">SOCKET</arg> 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.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
@@ -320,7 +320,7 @@
|
||||
Don't expose a well known socket to the application. This overrides to
|
||||
the Context section from the application metadata.
|
||||
<arg choice="plain">SOCKET</arg> 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.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user