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
This commit is contained in:
Consolatis 2024-12-02 03:44:57 +01:00 committed by Johan Malm
parent 9a9eaee5a1
commit f1e43762e0

View file

@ -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;