]> git.mdlowis.com Git - proto/labwc.git/commitdiff
server.c: block privileged protocols for sandboxed clients
authorConsolatis <35009135+Consolatis@users.noreply.github.com>
Mon, 2 Dec 2024 02:44:57 +0000 (03:44 +0100)
committerJohan Malm <johanmalm@users.noreply.github.com>
Tue, 3 Dec 2024 19:32:22 +0000 (19:32 +0000)
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

index b2077330c157ecb9dd9e75f42b6f1e9ffa01f99b..097269c5df6039de5cbc37305bf74a7544316e22 100644 (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;