Skip to content

Commit

Permalink
common: add support for Wayland security context
Browse files Browse the repository at this point in the history
This exposes a reliable way for Wayland compositors to get
identifying information about a client. Compositors can then
apply security policies if desirable.

See: https://gitlab.freedesktop.org/wayland/wayland-protocols/-/merge_requests/68
  • Loading branch information
emersion committed Jun 15, 2023
1 parent f45307c commit 643e6fa
Show file tree
Hide file tree
Showing 11 changed files with 248 additions and 16 deletions.
7 changes: 4 additions & 3 deletions .github/workflows/check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ jobs:
-Db_sanitize=address,undefined \
-Dgir=disabled \
-Dgtkdoc=disabled \
-Dwayland_security_context=disabled \
-Dhttp_backend=curl \
-Dinternal_checks=true \
-Dsystem_dbus_proxy=xdg-dbus-proxy \
Expand Down Expand Up @@ -133,7 +134,7 @@ jobs:
run: |
mkdir _build
pushd _build
../configure --enable-internal-checks --enable-asan --disable-introspection --without-curl
../configure --enable-internal-checks --enable-asan --disable-introspection --without-curl --disable-wayland-security-context
popd
env:
CFLAGS: -O2 -Wp,-D_FORTIFY_SOURCE=2
Expand Down Expand Up @@ -201,7 +202,7 @@ jobs:
with:
submodules: true
- name: configure
run: ./autogen.sh
run: ./autogen.sh --disable-wayland-security-context
env:
CC: clang
CFLAGS: -Werror=unused-variable
Expand Down Expand Up @@ -239,7 +240,7 @@ jobs:
run: |
mkdir _build
pushd _build
../configure --enable-gtk-doc --enable-gtk-doc-html --enable-introspection
../configure --enable-gtk-doc --enable-gtk-doc-html --enable-introspection --disable-wayland-security-context
popd
env:
CFLAGS: -O2
Expand Down
15 changes: 15 additions & 0 deletions common/Makefile.am.inc
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,21 @@ common/flatpak-systemd-dbus-generated.c: data/org.freedesktop.systemd1.xml Makef
common/%-dbus-generated.h: common/%-dbus-generated.c
@true # Built as a side-effect of the rules for the .c

if ENABLE_WAYLAND_SECURITY_CONTEXT
wayland_built_sources = common/security-context-v1-protocol.c common/security-context-v1-protocol.h
endif

wl_security_context_xml = $(WAYLAND_PROTOCOLS_DATADIR)/staging/security-context/security-context-v1.xml

common/security-context-v1-protocol.c: $(wl_security_context_xml)
$(AM_V_GEN) $(WAYLAND_SCANNER) code $(wl_security_context_xml) $(builddir)/common/security-context-v1-protocol.c

common/security-context-v1-protocol.h: $(wl_security_context_xml)
$(AM_V_GEN) $(WAYLAND_SCANNER) client-header $(wl_security_context_xml) $(builddir)/common/security-context-v1-protocol.h

nodist_libflatpak_common_base_la_SOURCES = \
$(dbus_built_sources) \
$(wayland_built_sources) \
$(NULL)

BUILT_SOURCES += $(nodist_libflatpak_common_base_la_SOURCES)
Expand Down Expand Up @@ -219,6 +232,7 @@ libflatpak_common_la_CFLAGS = \
$(SOUP_CFLAGS) \
$(SYSTEMD_CFLAGS) \
$(XAUTH_CFLAGS) \
$(WAYLAND_CLIENT_CFLAGS) \
$(XML_CFLAGS) \
$(NULL)
libflatpak_common_la_LIBADD = \
Expand All @@ -237,6 +251,7 @@ libflatpak_common_la_LIBADD = \
$(SOUP_LIBS) \
$(SYSTEMD_LIBS) \
$(XAUTH_LIBS) \
$(WAYLAND_CLIENT_LIBS) \
$(XML_LIBS) \
$(NULL)
Expand Down
4 changes: 3 additions & 1 deletion common/flatpak-run-sockets-private.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@ G_BEGIN_DECLS

void flatpak_run_add_socket_args_environment (FlatpakBwrap *bwrap,
FlatpakContextShares shares,
FlatpakContextSockets sockets);
FlatpakContextSockets sockets,
const char *app_id,
const char *instance_id);
void flatpak_run_add_socket_args_late (FlatpakBwrap *bwrap,
FlatpakContextShares shares);

Expand Down
10 changes: 6 additions & 4 deletions common/flatpak-run-sockets.c
Original file line number Diff line number Diff line change
Expand Up @@ -170,17 +170,19 @@ flatpak_run_add_ssh_args (FlatpakBwrap *bwrap)
* use of a proxy.
*/
void
flatpak_run_add_socket_args_environment (FlatpakBwrap *bwrap,
FlatpakContextShares shares,
FlatpakContextSockets sockets)
flatpak_run_add_socket_args_environment (FlatpakBwrap *bwrap,
FlatpakContextShares shares,
FlatpakContextSockets sockets,
const char *app_id,
const char *instance_id)
{
gboolean has_wayland = FALSE;
gboolean allow_x11;

if (sockets & FLATPAK_CONTEXT_SOCKET_WAYLAND)
{
g_info ("Allowing wayland access");
has_wayland = flatpak_run_add_wayland_args (bwrap);
has_wayland = flatpak_run_add_wayland_args (bwrap, app_id, instance_id);
}

if ((sockets & FLATPAK_CONTEXT_SOCKET_FALLBACK_X11) != 0)
Expand Down
4 changes: 3 additions & 1 deletion common/flatpak-run-wayland-private.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
G_BEGIN_DECLS

gboolean
flatpak_run_add_wayland_args (FlatpakBwrap *bwrap);
flatpak_run_add_wayland_args (FlatpakBwrap *bwrap,
const char *app_id,
const char *instance_id);

G_END_DECLS
151 changes: 150 additions & 1 deletion common/flatpak-run-wayland.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,155 @@
#include "config.h"
#include "flatpak-run-wayland-private.h"

#ifdef ENABLE_WAYLAND_SECURITY_CONTEXT
#include <sys/socket.h>
#include <sys/un.h>
#include <wayland-client.h>
#include "security-context-v1-protocol.h"
#endif

#include "flatpak-utils-private.h"

#ifdef ENABLE_WAYLAND_SECURITY_CONTEXT

static void registry_handle_global (void *data, struct wl_registry *registry,
uint32_t name, const char *interface,
uint32_t version)
{
struct wp_security_context_manager_v1 **out = data;

if (strcmp (interface, wp_security_context_manager_v1_interface.name) == 0) {
*out = wl_registry_bind (registry, name,
&wp_security_context_manager_v1_interface, 1);
}
}

static void registry_handle_global_remove (void *data,
struct wl_registry *registry,
uint32_t name)
{
/* no-op */
}

static const struct wl_registry_listener registry_listener = {
.global = registry_handle_global,
.global_remove = registry_handle_global_remove,
};

static char *
create_wl_socket (char *template)
{
g_autofree char *user_runtime_dir = flatpak_get_real_xdg_runtime_dir ();
g_autofree char *proxy_socket_dir = g_build_filename (user_runtime_dir, ".flatpak/wl", NULL);
g_autofree char *proxy_socket = g_build_filename (proxy_socket_dir, template, NULL);
int fd;

if (!glnx_shutil_mkdir_p_at (AT_FDCWD, proxy_socket_dir, 0755, NULL, NULL))
return NULL;

fd = g_mkstemp (proxy_socket);
if (fd == -1)
return NULL;

close (fd);

return g_steal_pointer (&proxy_socket);
}

static gboolean
flatpak_run_add_wayland_security_context_args (FlatpakBwrap *bwrap,
const char *app_id,
const char *instance_id,
gboolean *available_out)
{
gboolean res = FALSE;
struct wl_display *display;
struct wl_registry *registry;
struct wp_security_context_manager_v1 *security_context_manager = NULL;
struct wp_security_context_v1 *security_context;
struct sockaddr_un sockaddr = {0};
g_autofree char *socket_path = NULL;
int listen_fd = -1, sync_fd, ret;

*available_out = TRUE;

display = wl_display_connect (NULL);
if (!display)
return FALSE;

registry = wl_display_get_registry (display);
wl_registry_add_listener (registry, &registry_listener,
&security_context_manager);
ret = wl_display_roundtrip (display);
wl_registry_destroy (registry);
if (ret < 0)
goto out;

if (!security_context_manager) {
*available_out = FALSE;
goto out;
}

socket_path = create_wl_socket ("wayland-XXXXXX");
if (!socket_path)
goto out;

listen_fd = socket (AF_UNIX, SOCK_STREAM, 0);
if (listen_fd < 0)
goto out;

unlink (socket_path);

sockaddr.sun_family = AF_UNIX;
snprintf (sockaddr.sun_path, sizeof(sockaddr.sun_path), "%s", socket_path);
if (bind (listen_fd, (struct sockaddr *) &sockaddr, sizeof (sockaddr)) != 0)
goto out;

if (listen (listen_fd, 0) != 0)
goto out;

sync_fd = flatpak_bwrap_add_sync_fd (bwrap);
if (sync_fd < 0)
goto out;

security_context = wp_security_context_manager_v1_create_listener (security_context_manager,
listen_fd,
sync_fd);
wp_security_context_v1_set_sandbox_engine (security_context, "flatpak");
wp_security_context_v1_set_app_id (security_context, app_id);
wp_security_context_v1_set_instance_id (security_context, instance_id);
wp_security_context_v1_commit (security_context);
wp_security_context_v1_destroy (security_context);
if (wl_display_roundtrip (display) < 0)
goto out;

flatpak_bwrap_add_args (bwrap,
"--ro-bind", socket_path, "/run/flatpak/wayland-0",
NULL);
flatpak_bwrap_set_env (bwrap, "WAYLAND_DISPLAY", "/run/flatpak/wayland-0", TRUE);

res = TRUE;

out:
if (listen_fd >= 0)
close (listen_fd);
if (security_context_manager)
wp_security_context_manager_v1_destroy (security_context_manager);
wl_display_disconnect (display);
return res;
}

#endif /* ENABLE_WAYLAND_SECURITY_CONTEXT */

/**
* flatpak_run_add_wayland_args:
*
* Returns: %TRUE if a Wayland socket was found.
*/
gboolean
flatpak_run_add_wayland_args (FlatpakBwrap *bwrap)
flatpak_run_add_wayland_args (FlatpakBwrap *bwrap,
const char *app_id,
const char *instance_id)
{
const char *wayland_display;
g_autofree char *user_runtime_dir = flatpak_get_real_xdg_runtime_dir ();
Expand All @@ -38,6 +178,15 @@ flatpak_run_add_wayland_args (FlatpakBwrap *bwrap)
gboolean res = FALSE;
struct stat statbuf;

#ifdef ENABLE_WAYLAND_SECURITY_CONTEXT
gboolean security_context_available = FALSE;
if (flatpak_run_add_wayland_security_context_args (bwrap, app_id, instance_id,
&security_context_available))
return TRUE;
if (security_context_available)
return FALSE;
#endif /* ENABLE_WAYLAND_SECURITY_CONTEXT */

wayland_display = g_getenv ("WAYLAND_DISPLAY");
if (!wayland_display)
wayland_display = "wayland-0";
Expand Down
2 changes: 1 addition & 1 deletion common/flatpak-run.c
Original file line number Diff line number Diff line change
Expand Up @@ -489,7 +489,7 @@ flatpak_run_add_environment_args (FlatpakBwrap *bwrap,
exports, xdg_dirs_conf, home_access);

if (instance_id)
flatpak_run_add_socket_args_environment (bwrap, context->shares, context->sockets);
flatpak_run_add_socket_args_environment (bwrap, context->shares, context->sockets, app_id, instance_id);
flatpak_run_add_session_dbus_args (bwrap, proxy_arg_bwrap, context, flags, app_id);
flatpak_run_add_system_dbus_args (bwrap, proxy_arg_bwrap, context, flags);
flatpak_run_add_a11y_dbus_args (bwrap, proxy_arg_bwrap, context, flags);
Expand Down
38 changes: 33 additions & 5 deletions common/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,13 @@ flatpak_variant = custom_target(
command : variant_schema_compiler_command,
)

libflatpak_common_base_deps = base_deps + [libglnx_dep]

libflatpak_common_base_sources = [
'flatpak-utils-base.c',
'flatpak-utils-base-private.h',
] + flatpak_gdbus + flatpak_document_gdbus

built_headers = [
enums[1],
flatpak_version_macros,
Expand All @@ -109,16 +116,37 @@ built_headers = [
flatpak_variant[1],
]

if build_wayland_security_context
wayland_scanner_prog = find_program(wayland_scanner.get_variable('wayland_scanner'))
wayland_protocols_dir = wayland_protocols.get_variable('pkgdatadir')
wl_security_context_xml = wayland_protocols_dir / 'staging/security-context/security-context-v1.xml'
wl_security_context = [
custom_target(
'security-context-v1-protocol.c',
input : wl_security_context_xml,
output : 'security-context-v1-protocol.c',
command : [wayland_scanner_prog, 'code', '@INPUT@', '@OUTPUT@'],
),
custom_target(
'security-context-v1-protocol.h',
input : wl_security_context_xml,
output : 'security-context-v1-protocol.h',
command : [wayland_scanner_prog, 'client-header', '@INPUT@', '@OUTPUT@'],
),
]

libflatpak_common_base_deps += [wayland_client]
libflatpak_common_base_sources += [wl_security_context]
built_headers += [wl_security_context[1]]
endif

libflatpak_common_base = static_library(
'flatpak-common-base',
dependencies : base_deps + [libglnx_dep],
dependencies : libflatpak_common_base_deps,
gnu_symbol_visibility : 'hidden',
include_directories : [common_include_directories],
install : false,
sources : [
'flatpak-utils-base.c',
'flatpak-utils-base-private.h',
] + flatpak_gdbus + flatpak_document_gdbus,
sources : libflatpak_common_base_sources,
)
libflatpak_common_base_dep = declare_dependency(
dependencies : base_deps + [libglnx_dep],
Expand Down
18 changes: 18 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,24 @@ if test "x$enable_xauth" = "xyes"; then
[Define if using xauth])
fi

AC_ARG_ENABLE([wayland-security-context],
AC_HELP_STRING([--disable-wayland-security-context],
[Disable Wayland security context use]),
[],
[enable_wayland_security_context=yes])
if test "x$enable_wayland_security_context" = "xyes"; then
PKG_CHECK_MODULES(WAYLAND_CLIENT, [wayland-client])
PKG_CHECK_MODULES(WAYLAND_SCANNER, [wayland-scanner],
[wayland_scanner=`$PKG_CONFIG --variable=wayland_scanner wayland-scanner`])
AC_SUBST(WAYLAND_SCANNER, $wayland_scanner)
PKG_CHECK_MODULES(WAYLAND_PROTOCOLS, [wayland-protocols >= 1.25],
[wayland_protocols_pkgdatadir=`$PKG_CONFIG --variable=pkgdatadir wayland-protocols`])
AC_SUBST(WAYLAND_PROTOCOLS_DATADIR, $wayland_protocols_pkgdatadir)
AC_DEFINE([ENABLE_WAYLAND_SECURITY_CONTEXT], [1],
[Define if using Wayland security context])
fi
AM_CONDITIONAL(ENABLE_WAYLAND_SECURITY_CONTEXT, test "x$enable_wayland_security_context" = "xyes")

AC_ARG_ENABLE([gdm-env-file],
[AC_HELP_STRING([--enable-gdm-env-file], [Install gdm env.d file (not needed if systemd generators work)])],
install_gdm_env_file=$enableval, install_gdm_env_file=no)
Expand Down

0 comments on commit 643e6fa

Please sign in to comment.