[PATCH wayland 3/3] Add a version field to wl_resource and verify request versions before calling them
Jason Ekstrand
jason at jlekstrand.net
Wed Jun 26 20:18:03 PDT 2013
This commit provides a layer of protection for the compositor in the form
of message version checking. Version information is provided to libwayland
as an aditional argument to wl_client_add_object and wl_client_new_object.
libwayland then uses this version information to verify that a request
exists in that protocol version before invoking it. This way libwayland
won't accidentally invoke a request that does not exist and thereby cause
the compositor to crash.
Signed-off-by: Jason Ekstrand <jason at jlekstrand.net>
---
src/wayland-server.c | 38 ++++++++++++++++++++++++++++++--------
src/wayland-server.h | 6 ++++--
src/wayland-shm.c | 8 ++++----
3 files changed, 38 insertions(+), 14 deletions(-)
diff --git a/src/wayland-server.c b/src/wayland-server.c
index 0c3fbc9..565392b 100644
--- a/src/wayland-server.c
+++ b/src/wayland-server.c
@@ -109,6 +109,7 @@ struct wl_resource {
struct wl_signal destroy_signal;
struct wl_client *client;
void *data;
+ int version;
};
static int wl_debug = 0;
@@ -210,6 +211,7 @@ wl_client_connection_data(int fd, uint32_t mask, void *data)
struct wl_closure *closure;
const struct wl_message *message;
uint32_t p[2];
+ uint32_t resource_flags;
int opcode, size;
int len;
@@ -246,6 +248,7 @@ wl_client_connection_data(int fd, uint32_t mask, void *data)
break;
resource = wl_map_lookup(&client->objects, p[0]);
+ resource_flags = wl_map_lookup_flags(&client->objects, p[0]);
if (resource == NULL) {
wl_resource_post_error(client->display_resource,
WL_DISPLAY_ERROR_INVALID_OBJECT,
@@ -265,6 +268,18 @@ wl_client_connection_data(int fd, uint32_t mask, void *data)
}
message = &object->interface->methods[opcode];
+ if (!(resource_flags & WL_MAP_ENTRY_LEGACY) &&
+ resource->version < wl_message_get_since(message)) {
+ wl_resource_post_error(client->display_resource,
+ WL_DISPLAY_ERROR_INVALID_METHOD,
+ "invalid method %d, object %s@%u",
+ opcode,
+ object->interface->name,
+ object->id);
+ break;
+ }
+
+
closure = wl_connection_demarshal(client->connection, size,
&client->objects, message);
len -= size;
@@ -510,6 +525,12 @@ wl_resource_get_user_data(struct wl_resource *resource)
return resource->data;
}
+WL_EXPORT int
+wl_resource_get_version(struct wl_resource *resource)
+{
+ return resource->version;
+}
+
WL_EXPORT void
wl_resource_set_destructor(struct wl_resource *resource,
wl_resource_destroy_func_t destroy)
@@ -603,8 +624,8 @@ display_sync(struct wl_client *client,
struct wl_resource *callback;
uint32_t serial;
- callback = wl_client_add_object(client,
- &wl_callback_interface, NULL, id, NULL);
+ callback = wl_client_add_object(client, &wl_callback_interface, 1,
+ NULL, id, NULL);
serial = wl_display_get_serial(client->display);
wl_callback_send_done(callback, serial);
wl_resource_destroy(callback);
@@ -626,7 +647,7 @@ display_get_registry(struct wl_client *client,
struct wl_global *global;
registry_resource =
- wl_client_add_object(client, &wl_registry_interface,
+ wl_client_add_object(client, &wl_registry_interface, 1,
®istry_interface, id, display);
registry_resource->destroy = unbind_resource;
@@ -660,7 +681,7 @@ bind_display(struct wl_client *client,
struct wl_display *display = data;
client->display_resource =
- wl_client_add_object(client, &wl_display_interface,
+ wl_client_add_object(client, &wl_display_interface, 1,
&display_interface, id, display);
if(client->display_resource)
@@ -997,7 +1018,7 @@ wl_display_get_destroy_listener(struct wl_display *display,
WL_EXPORT struct wl_resource *
wl_client_add_object(struct wl_client *client,
- const struct wl_interface *interface,
+ const struct wl_interface *interface, int version,
const void *implementation,
uint32_t id, void *data)
{
@@ -1018,6 +1039,7 @@ wl_client_add_object(struct wl_client *client,
resource->destroy = NULL;
resource->client = client;
resource->data = data;
+ resource->version = version;
if (wl_map_insert_at(&client->objects, 0, resource->object.id, resource) < 0) {
wl_resource_post_error(client->display_resource,
@@ -1033,14 +1055,14 @@ wl_client_add_object(struct wl_client *client,
WL_EXPORT struct wl_resource *
wl_client_new_object(struct wl_client *client,
- const struct wl_interface *interface,
+ const struct wl_interface *interface, int version,
const void *implementation, void *data)
{
uint32_t id;
id = wl_map_insert_new(&client->objects, 0, NULL);
- return wl_client_add_object(client,
- interface, implementation, id, data);
+ return wl_client_add_object(client, interface, version,
+ implementation, id, data);
}
diff --git a/src/wayland-server.h b/src/wayland-server.h
index 7c53cfc..8a72d40 100644
--- a/src/wayland-server.h
+++ b/src/wayland-server.h
@@ -128,11 +128,11 @@ struct wl_listener *wl_client_get_destroy_listener(struct wl_client *client,
struct wl_resource *
wl_client_add_object(struct wl_client *client,
- const struct wl_interface *interface,
+ const struct wl_interface *interface, int version,
const void *implementation, uint32_t id, void *data);
struct wl_resource *
wl_client_new_object(struct wl_client *client,
- const struct wl_interface *interface,
+ const struct wl_interface *interface, int version,
const void *implementation, void *data);
struct wl_resource *
wl_client_get_object(struct wl_client *client, uint32_t id);
@@ -258,6 +258,8 @@ void
wl_resource_set_user_data(struct wl_resource *resource, void *data);
void *
wl_resource_get_user_data(struct wl_resource *resource);
+int
+wl_resource_get_version(struct wl_resource *resource);
void
wl_resource_set_destructor(struct wl_resource *resource,
wl_resource_destroy_func_t destroy);
diff --git a/src/wayland-shm.c b/src/wayland-shm.c
index 8a10253..c53a884 100644
--- a/src/wayland-shm.c
+++ b/src/wayland-shm.c
@@ -127,7 +127,7 @@ shm_pool_create_buffer(struct wl_client *client, struct wl_resource *resource,
buffer->pool = pool;
pool->refcount++;
- buffer->resource = wl_client_add_object(client, &wl_buffer_interface,
+ buffer->resource = wl_client_add_object(client, &wl_buffer_interface, 1,
&shm_buffer_interface,
id, buffer);
wl_resource_set_destructor(buffer->resource, destroy_buffer);
@@ -204,7 +204,7 @@ shm_create_pool(struct wl_client *client, struct wl_resource *resource,
}
close(fd);
- pool->resource = wl_client_add_object(client, &wl_shm_pool_interface,
+ pool->resource = wl_client_add_object(client, &wl_shm_pool_interface, 1,
&shm_pool_interface, id, pool);
if (!pool->resource)
goto err_free;
@@ -229,7 +229,7 @@ bind_shm(struct wl_client *client,
{
struct wl_resource *resource;
- resource = wl_client_add_object(client, &wl_shm_interface,
+ resource = wl_client_add_object(client, &wl_shm_interface, 1,
&shm_interface, id, data);
wl_shm_send_format(resource, WL_SHM_FORMAT_ARGB8888);
@@ -272,7 +272,7 @@ wl_shm_buffer_create(struct wl_client *client,
buffer->pool = NULL;
- buffer->resource = wl_client_add_object(client, &wl_buffer_interface,
+ buffer->resource = wl_client_add_object(client, &wl_buffer_interface, 1,
&shm_buffer_interface,
id, buffer);
wl_resource_set_destructor(buffer->resource, destroy_buffer);
--
1.8.2.1
More information about the wayland-devel
mailing list