[PATCH] wayland-server: Version check requests

Jason Ekstrand jason at jlekstrand.net
Thu May 23 13:58:08 PDT 2013


On Thu, May 23, 2013 at 3:20 PM, <alexl at redhat.com> wrote:

> From: Alexander Larsson <alexl at redhat.com>
>
> If an interface has any messages and its version is larger than 1
> then we emit a method counts array which lists the number of methods
> for each version of the interface. This can be used in addition
> to the normal method_count to reject requests that the
> server doesn't support. This allows the wayland server library
> to be upgraded and still safely run oler compositors that don't
> implement the new requests.
>
> Since there is no other space in the wm_interface we add the
> method count array at the end of the events array. We then
> add some warnings to the event sending code so that we never
> accidentally trigger these events.
>

Would it possibly be better to use the upper bits of method_count (or
method_count < 0) to signal that a method_counts array is appended to
methods?  This keeps methods with methods and also allows us to optionally
do the same thing with events client-side to protect clients from broken
newer-version compositors.


>
> Then we add code in the server to reject messages that are not
> supported by the server version of the object they are sent to.
> ---
>  src/scanner.c        | 54
> ++++++++++++++++++++++++++++++++++++++++++++++------
>  src/wayland-server.c | 34 +++++++++++++++++++++++++++++++--
>  2 files changed, 80 insertions(+), 8 deletions(-)
>
> diff --git a/src/scanner.c b/src/scanner.c
> index 9c14ad3..38e7909 100644
> --- a/src/scanner.c
> +++ b/src/scanner.c
> @@ -1019,12 +1019,13 @@ emit_types(struct protocol *protocol, struct
> wl_list *message_list)
>
>  static void
>  emit_messages(struct wl_list *message_list,
> -             struct interface *interface, const char *suffix)
> +             struct interface *interface, const char *suffix,
> +             int emit_method_counts)
>  {
>         struct message *m;
>         struct arg *a;
>
> -       if (wl_list_empty(message_list))
> +       if (wl_list_empty(message_list) && !emit_method_counts)
>                 return;
>
>         printf("static const struct wl_message "
> @@ -1070,13 +1071,52 @@ emit_messages(struct wl_list *message_list,
>                 printf("\", types + %d },\n", m->type_index);
>         }
>
> +       if (emit_method_counts) {
> +               printf("\t{ NULL, \"\", (void *)%s_method_counts },\n",
> interface->name);
> +       }
> +
> +       printf("};\n\n");
> +}
> +
> +static int
> +emit_method_counts(struct wl_list *message_list,
> +                  struct interface *interface)
> +{
> +       struct message *m;
> +       int version = 1;
> +       int count;
> +
> +       if (wl_list_empty(message_list) || interface->version == 1)
> +               return 0;
> +
> +       printf("static const uint32_t "
> +              "%s_method_counts[] = { ",
> +              interface->name);
> +
> +       count = 0;
> +       wl_list_for_each(m, message_list, link) {
> +               while (m->since != version) {
> +                       printf("%d,", count);
> +                       version++;
> +               }
> +               count++;
> +       }
> +
> +       while (version <= interface->version) {
> +               printf("%d, ", count);
> +               version++;
> +       }
> +
>         printf("};\n\n");
> +
> +       return 1;
>  }
>
>  static void
>  emit_code(struct protocol *protocol)
>  {
>         struct interface *i;
> +       int has_method_counts;
>
>         if (protocol->copyright)
>                 format_copyright(protocol->copyright);
> @@ -1101,8 +1141,10 @@ emit_code(struct protocol *protocol)
>
>         wl_list_for_each(i, &protocol->interface_list, link) {
>
> -               emit_messages(&i->request_list, i, "requests");
> -               emit_messages(&i->event_list, i, "events");
> +
> +               emit_messages(&i->request_list, i, "requests", 0);
> +               has_method_counts = emit_method_counts(&i->request_list,
> i);
> +               emit_messages(&i->event_list, i, "events",
> has_method_counts);
>
>                 printf("WL_EXPORT const struct wl_interface "
>                        "%s_interface = {\n"
> @@ -1115,9 +1157,9 @@ emit_code(struct protocol *protocol)
>                 else
>                         printf("\t0, NULL,\n");
>
> -               if (!wl_list_empty(&i->event_list))
> +               if (!wl_list_empty(&i->event_list) || has_method_counts)
>                         printf("\t%d, %s_events,\n",
> -                              wl_list_length(&i->event_list), i->name);
> +                              wl_list_length(&i->event_list) +
> has_method_counts, i->name);
>                 else
>                         printf("\t0, NULL,\n");
>
> diff --git a/src/wayland-server.c b/src/wayland-server.c
> index c808f6a..e94366b 100644
> --- a/src/wayland-server.c
> +++ b/src/wayland-server.c
> @@ -124,6 +124,12 @@ wl_resource_post_event(struct wl_resource *resource,
> uint32_t opcode, ...)
>         struct wl_object *object = &resource->object;
>         va_list ap;
>
> +       if (opcode >= (uint32_t)object->interface->event_count ||
> +           object->interface->events[opcode].name == NULL) {
> +               wl_log ("Trying to post unsupported event\n");
> +               return;
> +       }
> +
>         va_start(ap, opcode);
>         closure = wl_closure_vmarshal(object, opcode, ap,
>                                       &object->interface->events[opcode]);
> @@ -150,6 +156,12 @@ wl_resource_queue_event(struct wl_resource *resource,
> uint32_t opcode, ...)
>         struct wl_object *object = &resource->object;
>         va_list ap;
>
> +       if (opcode >= (uint32_t)object->interface->event_count ||
> +           object->interface->events[opcode].name == NULL) {
> +               wl_log ("Trying to queue unsupported event\n");
> +               return;
> +       }
> +
>         va_start(ap, opcode);
>         closure = wl_closure_vmarshal(object, opcode, ap,
>                                       &object->interface->events[opcode]);
> @@ -206,7 +218,8 @@ wl_client_connection_data(int fd, uint32_t mask, void
> *data)
>         struct wl_closure *closure;
>         const struct wl_message *message;
>         uint32_t p[2];
> -       int opcode, size;
> +       uint32_t opcode;
> +       int size;
>         int len;
>
>         if (mask & (WL_EVENT_ERROR | WL_EVENT_HANGUP)) {
> @@ -250,7 +263,7 @@ wl_client_connection_data(int fd, uint32_t mask, void
> *data)
>                 }
>
>                 object = &resource->object;
> -               if (opcode >= object->interface->method_count) {
> +               if (opcode >= (uint32_t)object->interface->method_count) {
>                         wl_resource_post_error(client->display_resource,
>
>  WL_DISPLAY_ERROR_INVALID_METHOD,
>                                                "invalid method %d, object
> %s@%u",
> @@ -260,6 +273,23 @@ wl_client_connection_data(int fd, uint32_t mask, void
> *data)
>                         break;
>                 }
>
> +               if (object->interface->event_count > 0 &&
> +
> object->interface->events[object->interface->event_count-1].name == NULL) {
> +                       uint32_t *method_counts = (uint32_t *)
> +
> object->interface->events[object->interface->event_count-1].types;
> +
> +                       if (opcode >=
> method_counts[wl_resource_get_version (resource)]) {
> +
> 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;
> +                       }
> +               }
> +
> +
>                 message = &object->interface->methods[opcode];
>                 closure = wl_connection_demarshal(client->connection, size,
>                                                   &client->objects,
> message);
> --
> 1.8.1.4
>
> _______________________________________________
> wayland-devel mailing list
> wayland-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/wayland-devel
>

Thanks,
--Jason Ekstrand
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.freedesktop.org/archives/wayland-devel/attachments/20130523/fa0319cd/attachment-0001.html>


More information about the wayland-devel mailing list