This commit is contained in:
Tobias Bengfort 2026-04-08 21:29:36 +00:00 committed by GitHub
commit 14f4dcbade
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 104 additions and 35 deletions

View file

@ -1445,6 +1445,52 @@ situation.
Whether to apply a bilinear filter to the magnified image, or
just to use nearest-neighbour. Default is true - bilinear filtered.
## PRIVILEGED INTERFACES
Labwc supports a small set of privileged wayland interfaces. All of these
interfaces are enabled by default for applications unless they are running
via a sandbox environment supporting the security-context-v1 protocol.
Security conscious users are suggested to use a sandbox framework to run
potentially untrusted applications as it additionally limits access to the
filesystem (including labwc configuration) and other services like dbus.
In addition to that, privileged protocols can be restricted for non-sandboxed
clients by defining a `<privilegedInterfaces>` block:
```
<privilegedInterfaces>
<allow>zwlr_layer_shell_v1</allow>
<allow>zwlr_virtual_pointer_manager_v1</allow>
</privilegedInterfaces>
```
*<privilegedInterfaces><allow>*
Name of the interface that should be allowed.
This is the full list of interfaces that can be controlled with this mechanism:
- `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`
- `ext_data_control_manager_v1`
- `zwlr_data_control_manager_v1`
- `wp_security_context_manager_v1`
- `ext_idle_notifier_v1`
- `zwlr_foreign_toplevel_manager_v1`
- `ext_foreign_toplevel_list_v1`
- `ext_session_lock_manager_v1`
- `zwlr_layer_shell_v1`
- `ext_workspace_manager_v1`
- `ext_image_copy_capture_manager_v1`
- `ext_output_image_capture_source_manager_v1`
## ENVIRONMENT VARIABLES
*XCURSOR_PATH*

View file

@ -76,6 +76,7 @@ struct rcxml {
enum tearing_mode allow_tearing;
bool auto_enable_outputs;
bool reuse_output_mode;
uint32_t allowed_interfaces;
bool xwayland_persistence;
bool primary_selection;
char *prompt_command;
@ -225,4 +226,6 @@ void rcxml_finish(void);
*/
void append_parsed_actions(xmlNode *node, struct wl_list *list);
uint32_t parse_privileged_interface(const char *name);
#endif /* LABWC_RCXML_H */

View file

@ -94,6 +94,43 @@ parse_window_type(const char *type)
}
}
uint32_t
parse_privileged_interface(const char *name)
{
static const char * const ifaces[] = {
"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",
"ext_data_control_manager_v1",
"zwlr_data_control_manager_v1",
"wp_security_context_manager_v1",
"ext_idle_notifier_v1",
"zwlr_foreign_toplevel_manager_v1",
"ext_foreign_toplevel_list_v1",
"ext_session_lock_manager_v1",
"zwlr_layer_shell_v1",
"ext_workspace_manager_v1",
"ext_image_copy_capture_manager_v1",
"ext_output_image_capture_source_manager_v1",
};
static_assert(ARRAY_SIZE(ifaces) <= 32,
"return type too small for amount of privileged protocols");
for (size_t i = 0; i < ARRAY_SIZE(ifaces); i++) {
if (!strcmp(name, ifaces[i])) {
return 1 << i;
}
}
return 0;
}
/*
* Openbox/labwc comparison
*
@ -1377,6 +1414,16 @@ entry(xmlNode *node, char *nodename, char *content)
rc.mag_increment = MAX(0, rc.mag_increment);
} else if (!strcasecmp(nodename, "useFilter.magnifier")) {
set_bool(content, &rc.mag_filter);
} else if (!strcasecmp(nodename, "privilegedInterfaces")) {
rc.allowed_interfaces = 0;
} else if (!strcasecmp(nodename, "allow.privilegedInterfaces")) {
uint32_t iface_id = parse_privileged_interface(content);
if (iface_id) {
rc.allowed_interfaces |= iface_id;
} else {
wlr_log(WLR_ERROR, "invalid value for "
"<privilegedInterfaces><allow>");
}
}
return false;
@ -1459,6 +1506,7 @@ rcxml_init(void)
rc.allow_tearing = LAB_TEARING_DISABLED;
rc.auto_enable_outputs = true;
rc.reuse_output_mode = false;
rc.allowed_interfaces = UINT32_MAX;
rc.xwayland_persistence = false;
rc.primary_selection = true;

View file

@ -210,39 +210,6 @@ handle_drm_lease_request(struct wl_listener *listener, void *data)
}
#endif
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",
"ext_data_control_manager_v1",
"zwlr_data_control_manager_v1",
"wp_security_context_manager_v1",
"ext_idle_notifier_v1",
"zwlr_foreign_toplevel_manager_v1",
"ext_foreign_toplevel_list_v1",
"ext_session_lock_manager_v1",
"zwlr_layer_shell_v1",
"ext_workspace_manager_v1",
"ext_image_copy_capture_manager_v1",
"ext_output_image_capture_source_manager_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)
@ -323,6 +290,11 @@ 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)) {
return false;
}
/* Do not allow security_context_manager_v1 to clients with a security context attached */
const struct wlr_security_context_v1_state *security_context =
wlr_security_context_manager_v1_lookup_client(
@ -338,11 +310,11 @@ server_global_filter(const struct wl_client *client, const struct wl_global *glo
/*
* TODO: The following call is basically useless right now
* and should be replaced with
* assert(allow || protocol_is_privileged(iface));
* assert(allow || iface_id);
* This ensures that our lists are in sync with what
* protocols labwc supports.
*/
if (!allow && !protocol_is_privileged(iface)) {
if (!allow && !iface_id) {
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",