[PATCH v5 1/3] wayland-server: Add API to control globals visibility
Olivier Fourdan
ofourdan at redhat.com
Tue Oct 18 14:23:39 UTC 2016
Add a new API to let compositor decide whether or not a wl_global
should be advertised to the clients via wl_registry_bind() or
display_get_registry()
By using its own filter, the compositor can decide which wl_global would
be listed to clients.
Compositors can use this mechanism to hide their own private interfaces
that regular clients should not use.
- Hiding interfaces that expose compositor implementation details
makes it harder for clients to identify the compositor. Therefore
clients are a little less likely to develop compositor-specific
workarounds instead of reporting problems upstream.
- Hiding can be used to diminish the problems from missing namespacing:
if two compositors happen to use the same named global with
different interfaces for their special-purpose clients, the client
expecting the different interface would probably never see it
advertised.
Signed-off-by: Olivier Fourdan <ofourdan at redhat.com>
Reviewed-by: Jonas Ã…dahl <jadahl at gmail.com>
Reviewed-by: Yong Bakos <ybakos at humanoriented.com>
Acked-by: Pekka Paalanen <pekka.paalanen at collabora.co.uk>
---
v2: Follow-up on Jonas' comments on v1:
Add global's data as user data in callback filter function
Pass wl_global instead of wl_interface in callback filter function
Add wl_global_get_interface() to retrieve the wl_interface from the
given wl_global
Post an error if a client tries to bind a global which is filtered
out.
v3: Follow-up on Jonas' comments on v2:
Separate from the other wl_global and test additions
Add its own user data to the global filter
Rephrase the API doc
Other few small changes
v4: Follow-up on Yong's comments on v3:
Rename wl_display_filter_global_func_t as wl_display_global_filter_func_t
Document wl_display_global_filter_func_t
Rename wl_display_set_filter_global as wl_display_set_global_filter
Rename filter_global() as wl_global_is_visible() and add a short
explanation in the code
v5: Rebase against current git master, amend commit message as per
Pekka's comment and add Pekka's acked-by
src/wayland-server-core.h | 25 ++++++++++++++++++
src/wayland-server.c | 67 +++++++++++++++++++++++++++++++++++++++++++----
2 files changed, 87 insertions(+), 5 deletions(-)
diff --git a/src/wayland-server-core.h b/src/wayland-server-core.h
index 2c215e4..9ae51dc 100644
--- a/src/wayland-server-core.h
+++ b/src/wayland-server-core.h
@@ -28,6 +28,7 @@
#include <sys/types.h>
#include <stdint.h>
+#include <stdbool.h>
#include "wayland-util.h"
#include "wayland-version.h"
@@ -168,6 +169,30 @@ wl_global_create(struct wl_display *display,
void
wl_global_destroy(struct wl_global *global);
+/** A filter function for wl_global objects
+ *
+ * \param client The client object
+ * \param global The global object to show or hide
+ * \param data The user data pointer
+ *
+ * A filter function enables the server to decide which globals to
+ * advertise to each client.
+ *
+ * When a wl_global filter is set, the given callback funtion will be
+ * called during wl_global advertisment and binding.
+ *
+ * This function should return true if the global object should be made
+ * visible to the client or false otherwise.
+ */
+typedef bool (*wl_display_global_filter_func_t)(const struct wl_client *client,
+ const struct wl_global *global,
+ void *data);
+
+void
+wl_display_set_global_filter(struct wl_display *display,
+ wl_display_global_filter_func_t filter,
+ void *data);
+
struct wl_client *
wl_client_create(struct wl_display *display, int fd);
diff --git a/src/wayland-server.c b/src/wayland-server.c
index 9d7d9c1..893bb56 100644
--- a/src/wayland-server.c
+++ b/src/wayland-server.c
@@ -101,6 +101,9 @@ struct wl_display {
struct wl_signal create_client_signal;
struct wl_array additional_shm_formats;
+
+ wl_display_global_filter_func_t global_filter;
+ void *global_filter_data;
};
struct wl_global {
@@ -769,6 +772,21 @@ wl_client_destroy(struct wl_client *client)
free(client);
}
+/* Check if a global filter is registered and use it if any.
+ *
+ * If no wl_global filter has been registered, this funtion will
+ * return true, allowing the wl_global to be visible to the wl_client
+ */
+static bool
+wl_global_is_visible(const struct wl_client *client,
+ const struct wl_global *global)
+{
+ struct wl_display *display = client->display;
+
+ return (display->global_filter == NULL ||
+ display->global_filter(client, global, display->global_filter_data));
+}
+
static void
registry_bind(struct wl_client *client,
struct wl_resource *resource, uint32_t name,
@@ -795,6 +813,10 @@ registry_bind(struct wl_client *client,
WL_DISPLAY_ERROR_INVALID_OBJECT,
"invalid version for global %s (%d): have %d, wanted %d",
interface, name, global->version, version);
+ else if (!wl_global_is_visible(client, global))
+ wl_resource_post_error(resource,
+ WL_DISPLAY_ERROR_INVALID_OBJECT,
+ "invalid global %s (%d)", interface, name);
else
global->bind(client, global->data, version, id);
}
@@ -850,11 +872,12 @@ display_get_registry(struct wl_client *client,
®istry_resource->link);
wl_list_for_each(global, &display->global_list, link)
- wl_resource_post_event(registry_resource,
- WL_REGISTRY_GLOBAL,
- global->name,
- global->interface->name,
- global->version);
+ if (wl_global_is_visible(client, global))
+ wl_resource_post_event(registry_resource,
+ WL_REGISTRY_GLOBAL,
+ global->name,
+ global->interface->name,
+ global->version);
}
static const struct wl_display_interface display_interface = {
@@ -925,6 +948,9 @@ wl_display_create(void)
display->id = 1;
display->serial = 0;
+ display->global_filter = NULL;
+ display->global_filter_data = NULL;
+
wl_array_init(&display->additional_shm_formats);
return display;
@@ -999,6 +1025,37 @@ wl_display_destroy(struct wl_display *display)
free(display);
}
+/** Set a filter function for global objects
+ *
+ * \param display The Wayland display object.
+ * \param filter The global filter funtion.
+ * \param data User data to be associated with the global filter.
+ * \return None.
+ *
+ * Set a filter for the wl_display to advertise or hide global objects
+ * to clients.
+ * The set filter will be used during wl_global advertisment to
+ * determine whether a global object should be advertised to a
+ * given client, and during wl_global binding to determine whether
+ * a given client should be allowed to bind to a global.
+ *
+ * Clients that try to bind to a global that was filtered out will
+ * have an error raised.
+ *
+ * Setting the filter NULL will result in all globals being
+ * advertised to all clients. The default is no filter.
+ *
+ * \memberof wl_display
+ */
+WL_EXPORT void
+wl_display_set_global_filter(struct wl_display *display,
+ wl_display_global_filter_func_t filter,
+ void *data)
+{
+ display->global_filter = filter;
+ display->global_filter_data = data;
+}
+
WL_EXPORT struct wl_global *
wl_global_create(struct wl_display *display,
const struct wl_interface *interface, int version,
--
2.9.3
More information about the wayland-devel
mailing list