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