[PATCH wayland 3/3] Add a version field to wl_resource and verify request versions before calling them

Jason Ekstrand jason at jlekstrand.net
Thu Jun 27 17:30:20 PDT 2013


DISCARD THIS PATCH.  NEW SERIES COMING

This patch breaks ABI too badly.  Specifically Mesa (and probably other EGL
implementations) use wl_client_add_object internally.
--Jason Ekstrand


On Wed, Jun 26, 2013 at 10:18 PM, Jason Ekstrand <jason at jlekstrand.net>wrote:

> 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,
>                                      &registry_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
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.freedesktop.org/archives/wayland-devel/attachments/20130627/d3332a32/attachment-0001.html>


More information about the wayland-devel mailing list