<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>
                                     &registry_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>