From f1e43762e042b5bbbdf05411303ea1a397fef722 Mon Sep 17 00:00:00 2001 From: Consolatis <35009135+Consolatis@users.noreply.github.com> Date: Mon, 2 Dec 2024 03:44:57 +0100 Subject: [PATCH] server.c: block privileged protocols for sandboxed clients In the longer term we want this to be user-configurable (and also depend on the sandbox engine, app_id and instance). But dropping privileged protocols for sandboxed clients in the meantime seems like a sensible thing to do and matches user expectations. Related: #2392 --- src/server.c | 102 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 101 insertions(+), 1 deletion(-) diff --git a/src/server.c b/src/server.c index b2077330..097269c5 100644 --- a/src/server.c +++ b/src/server.c @@ -26,6 +26,7 @@ #include "xwayland-shell-v1-protocol.h" #endif #include "drm-lease-v1-protocol.h" +#include "common/macros.h" #include "config/rcxml.h" #include "config/session.h" #include "decorations.h" @@ -193,6 +194,85 @@ handle_drm_lease_request(struct wl_listener *listener, void *data) } } +static bool +protocol_is_privileged(const struct wl_interface *iface) +{ + static const char * const rejected[] = { + "wp_drm_lease_device_v1", + "zwlr_gamma_control_manager_v1", + "zwlr_output_manager_v1", + "zwlr_output_power_manager_v1", + "zwp_input_method_manager_v2", + "zwlr_virtual_pointer_manager_v1", + "zwp_virtual_keyboard_manager_v1", + "zwlr_export_dmabuf_manager_v1", + "zwlr_screencopy_manager_v1", + "zwlr_data_control_manager_v1", + "wp_security_context_manager_v1", + "ext_idle_notifier_v1", + "zcosmic_workspace_manager_v1", + "zwlr_foreign_toplevel_manager_v1", + "ext_foreign_toplevel_list_v1", + "ext_session_lock_manager_v1", + "zwlr_layer_shell_v1", + }; + for (size_t i = 0; i < ARRAY_SIZE(rejected); i++) { + if (!strcmp(iface->name, rejected[i])) { + return true; + } + } + return false; +} + +static bool +allow_for_sandbox(const struct wlr_security_context_v1_state *security_state, + const struct wl_interface *iface) +{ + if (!strcmp(iface->name, "security_context_manager_v1")) { + return false; + } + + /* protocols are split into 3 blocks, from least privileges to highest privileges */ + static const char * const allowed_protocols[] = { + /* absolute base */ + "wl_shm", + "wl_compositor", + "wl_subcompositor", + "wl_data_device_manager", /* would be great if we could drop this one */ + "wl_seat", + "xdg_wm_base", + /* enhanced */ + "wl_output", + "wl_drm", + "zwp_linux_dmabuf_v1", + "zwp_primary_selection_device_manager_v1", + "zwp_text_input_manager_v3", + "zwp_pointer_gestures_v1", + "wp_cursor_shape_manager_v1", + "zwp_relative_pointer_manager_v1", + "xdg_activation_v1", + "org_kde_kwin_server_decoration_manager", + "zxdg_decoration_manager_v1", + "wp_presentation", + "wp_viewporter", + "wp_single_pixel_buffer_manager_v1", + "wp_fractional_scale_manager_v1", + "wp_tearing_control_manager_v1", + "zwp_tablet_manager_v2", + /* plus */ + "zwp_idle_inhibit_manager_v1", + "zwp_pointer_constraints_v1", + "zxdg_output_manager_v1", + }; + + for (size_t i = 0; i < ARRAY_SIZE(allowed_protocols); i++) { + if (!strcmp(iface->name, allowed_protocols[i])) { + return true; + } + } + return false; +} + static bool server_global_filter(const struct wl_client *client, const struct wl_global *global, void *data) { @@ -227,8 +307,28 @@ server_global_filter(const struct wl_client *client, const struct wl_global *glo wlr_security_context_manager_v1_lookup_client( server->security_context_manager_v1, (struct wl_client *)client); if (security_context && global == server->security_context_manager_v1->global) { - wlr_log(WLR_DEBUG, "blocking security_context_manager_v1 for the sandboxed client"); return false; + } else if (security_context) { + /* + * We are using an allow list for sandboxes to not + * accidentally leak a new privileged protocol. + */ + bool allow = allow_for_sandbox(security_context, iface); + /* + * TODO: The following call is basically useless right now + * and should be replaced with + * assert(allow || protocol_is_privileged(iface)); + * This ensures that our lists are in sync with what + * protocols labwc supports. + */ + if (!allow && !protocol_is_privileged(iface)) { + wlr_log(WLR_ERROR, "Blocking unknown protocol %s", iface->name); + } else if (!allow) { + wlr_log(WLR_DEBUG, "Blocking %s for security context %s->%s->%s", + iface->name, security_context->sandbox_engine, + security_context->app_id, security_context->instance_id); + } + return allow; } return true;