From 589ea47920b85fcfdefad5b04cdff562e7f11360 Mon Sep 17 00:00:00 2001 From: Tobias Bengfort Date: Sat, 6 Sep 2025 10:43:26 +0200 Subject: [PATCH] implement permission infrastructure --- include/permissions.h | 11 ++++++ src/meson.build | 1 + src/permissions.c | 81 +++++++++++++++++++++++++++++++++++++++++++ src/server.c | 6 ++-- 4 files changed, 96 insertions(+), 3 deletions(-) create mode 100644 include/permissions.h create mode 100644 src/permissions.c diff --git a/include/permissions.h b/include/permissions.h new file mode 100644 index 00000000..77d46762 --- /dev/null +++ b/include/permissions.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef LABWC_PERMISSIONS_H +#define LABWC_PERMISSIONS_H + +#include +#include + +int permissions_context_create(struct wl_display *display, uint32_t permissions); +bool permissions_check(const struct wl_client *client, const struct wl_interface *iface); + +#endif diff --git a/src/meson.build b/src/meson.build index 40ec3170..27056552 100644 --- a/src/meson.build +++ b/src/meson.build @@ -1,6 +1,7 @@ labwc_sources = files( 'action.c', 'buffer.c', + 'permissions.c', 'debug.c', 'desktop.c', 'dnd.c', diff --git a/src/permissions.c b/src/permissions.c new file mode 100644 index 00000000..df7c3f50 --- /dev/null +++ b/src/permissions.c @@ -0,0 +1,81 @@ +// SPDX-License-Identifier: GPL-2.0-only +#define _POSIX_C_SOURCE 200809L +#include "permissions.h" +#include +#include +#include +#include +#include "common/mem.h" +#include "common/spawn.h" +#include "config/rcxml.h" + +struct permissions_context { + uint32_t permissions; + int fd; + struct wl_listener destroy; +}; + +static void +permissions_context_handle_destroy(struct wl_listener *listener, void *data) +{ + struct permissions_context *context = wl_container_of(listener, context, destroy); + close(context->fd); + zfree(context); +} + +static uint32_t +permissions_get(const struct wl_client *client) +{ + struct wl_listener *listener = wl_client_get_destroy_listener( + (struct wl_client *)client, permissions_context_handle_destroy); + if (!listener) { + return 0; + } + + struct permissions_context *context = wl_container_of(listener, context, destroy); + return context->permissions; +} + +int +permissions_context_create(struct wl_display *display, uint32_t permissions) +{ + if (permissions == 0) { + return -1; + } + + int sv[2]; + if (socketpair(AF_UNIX, SOCK_STREAM, 0, sv) != 0) { + wlr_log_errno(WLR_ERROR, "socketpair failed"); + return -1; + } + + if (!set_cloexec(sv[0])) { + close(sv[0]); + close(sv[1]); + return -1; + } + + struct wl_client *client = wl_client_create(display, sv[0]); + if (!client) { + wlr_log(WLR_ERROR, "failed to create client"); + close(sv[0]); + close(sv[1]); + return -1; + } + + struct permissions_context *context = znew(*context); + context->permissions = permissions; + context->fd = sv[0]; + context->destroy.notify = permissions_context_handle_destroy; + wl_client_add_destroy_listener(client, &context->destroy); + + return sv[1]; +} + +bool +permissions_check(const struct wl_client *client, const struct wl_interface *iface) +{ + uint32_t permissions = permissions_get(client) | rc.allowed_interfaces; + uint32_t required = parse_privileged_interface(iface->name); + return (permissions & required) == required; +} diff --git a/src/server.c b/src/server.c index e4b27026..767ca8d6 100644 --- a/src/server.c +++ b/src/server.c @@ -66,6 +66,7 @@ #include "menu/menu.h" #include "output.h" #include "output-virtual.h" +#include "permissions.h" #include "regions.h" #include "resize-indicator.h" #include "scaled-buffer/scaled-buffer.h" @@ -294,8 +295,7 @@ server_global_filter(const struct wl_client *client, const struct wl_global *glo } #endif - uint32_t iface_id = parse_privileged_interface(iface->name); - if (iface_id && !(iface_id & rc.allowed_interfaces)) { + if (!permissions_check(client, iface)) { return false; } @@ -318,7 +318,7 @@ server_global_filter(const struct wl_client *client, const struct wl_global *glo * This ensures that our lists are in sync with what * protocols labwc supports. */ - if (!allow && !iface_id) { + if (!allow && !parse_privileged_interface(iface->name)) { 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",