<div dir="ltr"><br><br><div class="gmail_quote"><div dir="ltr">On Tue, Apr 11, 2017 at 11:39 AM Derek Foreman <<a href="mailto:derekf@osg.samsung.com">derekf@osg.samsung.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">On 07/04/17 03:27 PM, Derek Foreman wrote:<br class="gmail_msg">
> Using the singleton zombie object doesn't allow us to posthumously retain<br class="gmail_msg">
> object interface information, which makes it difficult to properly inter<br class="gmail_msg">
> future events destined for the recently deceased proxy.<br class="gmail_msg">
><br class="gmail_msg">
> Notably, this makes it impossible for zombie proxy destined file<br class="gmail_msg">
> descriptors to be properly consumed.<br class="gmail_msg">
><br class="gmail_msg">
> Instead of having a singleton zombie object, we add a new wl_map flag<br class="gmail_msg">
> (valid only on the client side where zombies roam - the existing<br class="gmail_msg">
> "legacy" flag was only ever used on the server side) to indicate that a<br class="gmail_msg">
> map entry is now a zombie.<br class="gmail_msg">
><br class="gmail_msg">
> We still have to refcount and potentially free the proxy immediately or<br class="gmail_msg">
> we're left with situations where it can be leaked forever.  If we clean<br class="gmail_msg">
> up on delete_id, for example, a forced disconnect will result in a leaked<br class="gmail_msg">
> proxy (breaking much of the test suite).<br class="gmail_msg">
><br class="gmail_msg">
> So, since we must free the zombied proxy immediately, we store just the<br class="gmail_msg">
> interface for it in its previous map location, so signature information<br class="gmail_msg">
> can be retained for zombie-destined events.<br class="gmail_msg">
<br class="gmail_msg">
So even with this in place it's still possible for a malicious<br class="gmail_msg">
application to consume 1000fds (the number of fds that fit in fds_in)<br class="gmail_msg"></blockquote><div><br></div><div>ITYM 1024 but I understood what you meant</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
and go to sleep and hold them - on client disconnect they should be<br class="gmail_msg">
freed.  I don't really see a way to prevent that sort of crap anyway - a<br class="gmail_msg">
client could use sendmsg directly, send a single byte of regular data<br class="gmail_msg">
(ie: not enough to trigger demarshalling, the server will assume there's<br class="gmail_msg">
more to come), and a buffer's worth of file descriptors, then never<br class="gmail_msg">
speak again.<br class="gmail_msg">
<br class="gmail_msg">
This appears indistinguishable from reasonable behaviour?<br class="gmail_msg">
<br class="gmail_msg">
There's also an interesting side effect to this patch that I noticed<br class="gmail_msg">
yesterday - it places a requirement on the client to keep the<br class="gmail_msg">
wl_interfaces around in memory long after it destroys the proxy - up<br class="gmail_msg">
until the delete_id occurs.  We have no way to hook delete_id in the<br class="gmail_msg">
client.  This turned into a crash in EFL clients using the text input<br class="gmail_msg">
protocol, as the input method code in EFL is a module that's unloaded on<br class="gmail_msg">
shutdown.  It was easily fixed in EFL, but I'd like some input - is a<br class="gmail_msg">
client allowed to unmap the memory that a wl_interface is stored in at<br class="gmail_msg">
the moment it deletes the relevant proxy?<br class="gmail_msg">
<br class="gmail_msg">
This isn't terribly difficult to fix, but I won't bother if the<br class="gmail_msg">
behaviour is universally concluded to be a client bug. :)<br class="gmail_msg">
<br class="gmail_msg">
Oh, and I just noticed wl_map_set_flags() is in this patch - that's a<br class="gmail_msg">
remnant of a previous attempt to close this leak, and will be removed<br class="gmail_msg">
for v2.<br class="gmail_msg">
<br class="gmail_msg">
Thanks,<br class="gmail_msg">
Derek<br class="gmail_msg">
<br class="gmail_msg">
> Signed-off-by: Derek Foreman <<a href="mailto:derekf@osg.samsung.com" class="gmail_msg" target="_blank">derekf@osg.samsung.com</a>><br class="gmail_msg">
> ---<br class="gmail_msg">
>  src/connection.c      | 20 +++++++++++++++++++-<br class="gmail_msg">
>  src/wayland-client.c  | 10 ++++++----<br class="gmail_msg">
>  src/wayland-private.h | 12 ++++++++----<br class="gmail_msg">
>  src/wayland-util.c    | 22 ++++++++++++++++++++--<br class="gmail_msg">
>  4 files changed, 53 insertions(+), 11 deletions(-)<br class="gmail_msg">
><br class="gmail_msg">
> diff --git a/src/connection.c b/src/connection.c<br class="gmail_msg">
> index f2ebe06..84f5d79 100644<br class="gmail_msg">
> --- a/src/connection.c<br class="gmail_msg">
> +++ b/src/connection.c<br class="gmail_msg">
> @@ -809,6 +809,24 @@ wl_connection_demarshal(struct wl_connection *connection,<br class="gmail_msg">
>       return NULL;<br class="gmail_msg">
>  }<br class="gmail_msg">
><br class="gmail_msg">
> +bool<br class="gmail_msg">
> +wl_object_is_zombie(struct wl_map *map, uint32_t id)<br class="gmail_msg">
> +{<br class="gmail_msg">
> +     uint32_t flags;<br class="gmail_msg">
> +<br class="gmail_msg">
> +     if (map->side == WL_MAP_SERVER_SIDE)<br class="gmail_msg">
> +             return false;<br class="gmail_msg">
> +<br class="gmail_msg">
> +     if (id >= WL_SERVER_ID_START)<br class="gmail_msg">
> +             return false;<br class="gmail_msg">
> +<br class="gmail_msg">
> +     flags = wl_map_lookup_flags(map, id);<br class="gmail_msg">
> +     if (flags & WL_MAP_ENTRY_ZOMBIE)<br class="gmail_msg">
> +             return true;<br class="gmail_msg">
> +<br class="gmail_msg">
> +     return false;<br class="gmail_msg">
> +}<br class="gmail_msg">
> +<br class="gmail_msg">
>  int<br class="gmail_msg">
>  wl_closure_lookup_objects(struct wl_closure *closure, struct wl_map *objects)<br class="gmail_msg">
>  {<br class="gmail_msg">
> @@ -830,7 +848,7 @@ wl_closure_lookup_objects(struct wl_closure *closure, struct wl_map *objects)<br class="gmail_msg">
>                       closure->args[i].o = NULL;<br class="gmail_msg">
><br class="gmail_msg">
>                       object = wl_map_lookup(objects, id);<br class="gmail_msg">
> -                     if (object == WL_ZOMBIE_OBJECT) {<br class="gmail_msg">
> +                     if (wl_object_is_zombie(objects, id)) {<br class="gmail_msg">
>                               /* references object we've already<br class="gmail_msg">
>                                * destroyed client side */<br class="gmail_msg">
>                               object = NULL;<br class="gmail_msg">
> diff --git a/src/wayland-client.c b/src/wayland-client.c<br class="gmail_msg">
> index 7243d3d..2cd713d 100644<br class="gmail_msg">
> --- a/src/wayland-client.c<br class="gmail_msg">
> +++ b/src/wayland-client.c<br class="gmail_msg">
> @@ -408,8 +408,10 @@ proxy_destroy(struct wl_proxy *proxy)<br class="gmail_msg">
>       if (proxy->flags & WL_PROXY_FLAG_ID_DELETED)<br class="gmail_msg">
>               wl_map_remove(&proxy->display->objects, proxy-><a href="http://object.id" rel="noreferrer" class="gmail_msg" target="_blank">object.id</a>);<br class="gmail_msg">
>       else if (proxy-><a href="http://object.id" rel="noreferrer" class="gmail_msg" target="_blank">object.id</a> < WL_SERVER_ID_START)<br class="gmail_msg">
> -             wl_map_insert_at(&proxy->display->objects, 0,<br class="gmail_msg">
> -                              proxy-><a href="http://object.id" rel="noreferrer" class="gmail_msg" target="_blank">object.id</a>, WL_ZOMBIE_OBJECT);<br class="gmail_msg">
> +             wl_map_insert_at(&proxy->display->objects,<br class="gmail_msg">
> +                              WL_MAP_ENTRY_ZOMBIE,<br class="gmail_msg">
> +                              proxy-><a href="http://object.id" rel="noreferrer" class="gmail_msg" target="_blank">object.id</a>,<br class="gmail_msg">
> +                              (void *)proxy->object.interface);<br class="gmail_msg">
>       else<br class="gmail_msg">
>               wl_map_insert_at(&proxy->display->objects, 0,<br class="gmail_msg">
>                                proxy-><a href="http://object.id" rel="noreferrer" class="gmail_msg" target="_blank">object.id</a>, NULL);<br class="gmail_msg">
> @@ -837,7 +839,7 @@ display_handle_delete_id(void *data, struct wl_display *display, uint32_t id)<br class="gmail_msg">
>       if (!proxy)<br class="gmail_msg">
>               wl_log("error: received delete_id for unknown id (%u)\n", id);<br class="gmail_msg">
><br class="gmail_msg">
> -     if (proxy && proxy != WL_ZOMBIE_OBJECT)<br class="gmail_msg">
> +     if (proxy && !wl_object_is_zombie(&display->objects, id))<br class="gmail_msg">
>               proxy->flags |= WL_PROXY_FLAG_ID_DELETED;<br class="gmail_msg">
>       else<br class="gmail_msg">
>               wl_map_remove(&display->objects, id);<br class="gmail_msg">
> @@ -1228,7 +1230,7 @@ queue_event(struct wl_display *display, int len)<br class="gmail_msg">
>               return 0;<br class="gmail_msg">
><br class="gmail_msg">
>       proxy = wl_map_lookup(&display->objects, id);<br class="gmail_msg">
> -     if (!proxy || proxy == WL_ZOMBIE_OBJECT) {<br class="gmail_msg">
> +     if (!proxy || wl_object_is_zombie(&display->objects, id)) {<br class="gmail_msg">
>               wl_connection_consume(display->connection, size);<br class="gmail_msg">
>               return size;<br class="gmail_msg">
>       }<br class="gmail_msg">
> diff --git a/src/wayland-private.h b/src/wayland-private.h<br class="gmail_msg">
> index d906a6f..2acd2d4 100644<br class="gmail_msg">
> --- a/src/wayland-private.h<br class="gmail_msg">
> +++ b/src/wayland-private.h<br class="gmail_msg">
> @@ -57,9 +57,6 @@ struct wl_object {<br class="gmail_msg">
>       uint32_t id;<br class="gmail_msg">
>  };<br class="gmail_msg">
><br class="gmail_msg">
> -extern struct wl_object global_zombie_object;<br class="gmail_msg">
> -#define WL_ZOMBIE_OBJECT ((void*)&global_zombie_object)<br class="gmail_msg">
> -<br class="gmail_msg">
>  int<br class="gmail_msg">
>  wl_interface_equal(const struct wl_interface *iface1,<br class="gmail_msg">
>                  const struct wl_interface *iface2);<br class="gmail_msg">
> @@ -69,7 +66,8 @@ wl_interface_equal(const struct wl_interface *iface1,<br class="gmail_msg">
>   * flags.  If more flags are ever added, the implementation of wl_map will have<br class="gmail_msg">
>   * to change to allow for new flags */<br class="gmail_msg">
>  enum wl_map_entry_flags {<br class="gmail_msg">
> -     WL_MAP_ENTRY_LEGACY = (1 << 0)<br class="gmail_msg">
> +     WL_MAP_ENTRY_LEGACY = (1 << 0), /* Server side only */<br class="gmail_msg">
> +     WL_MAP_ENTRY_ZOMBIE = (1 << 0) /* Client side only */<br class="gmail_msg">
>  };<br class="gmail_msg">
><br class="gmail_msg">
>  struct wl_map {<br class="gmail_msg">
> @@ -107,6 +105,9 @@ uint32_t<br class="gmail_msg">
>  wl_map_lookup_flags(struct wl_map *map, uint32_t i);<br class="gmail_msg">
><br class="gmail_msg">
>  void<br class="gmail_msg">
> +wl_map_set_flags(struct wl_map *map, uint32_t i, uint32_t flags);<br class="gmail_msg">
> +<br class="gmail_msg">
> +void<br class="gmail_msg">
>  wl_map_for_each(struct wl_map *map, wl_iterator_func_t func, void *data);<br class="gmail_msg">
><br class="gmail_msg">
>  struct wl_connection *<br class="gmail_msg">
> @@ -189,6 +190,9 @@ wl_connection_demarshal(struct wl_connection *connection,<br class="gmail_msg">
>                       struct wl_map *objects,<br class="gmail_msg">
>                       const struct wl_message *message);<br class="gmail_msg">
><br class="gmail_msg">
> +bool<br class="gmail_msg">
> +wl_object_is_zombie(struct wl_map *map, uint32_t id);<br class="gmail_msg">
> +<br class="gmail_msg">
>  int<br class="gmail_msg">
>  wl_closure_lookup_objects(struct wl_closure *closure, struct wl_map *objects);<br class="gmail_msg">
><br class="gmail_msg">
> diff --git a/src/wayland-util.c b/src/wayland-util.c<br class="gmail_msg">
> index cab7fc5..71abb2e 100644<br class="gmail_msg">
> --- a/src/wayland-util.c<br class="gmail_msg">
> +++ b/src/wayland-util.c<br class="gmail_msg">
> @@ -153,8 +153,6 @@ wl_array_copy(struct wl_array *array, struct wl_array *source)<br class="gmail_msg">
><br class="gmail_msg">
>  /** \cond */<br class="gmail_msg">
><br class="gmail_msg">
> -struct wl_object global_zombie_object;<br class="gmail_msg">
> -<br class="gmail_msg">
>  int<br class="gmail_msg">
>  wl_interface_equal(const struct wl_interface *a, const struct wl_interface *b)<br class="gmail_msg">
>  {<br class="gmail_msg">
> @@ -360,6 +358,26 @@ wl_map_lookup_flags(struct wl_map *map, uint32_t i)<br class="gmail_msg">
>       return 0;<br class="gmail_msg">
>  }<br class="gmail_msg">
><br class="gmail_msg">
> +void<br class="gmail_msg">
> +wl_map_set_flags(struct wl_map *map, uint32_t i, uint32_t flags)<br class="gmail_msg">
> +{<br class="gmail_msg">
> +     union map_entry *start;<br class="gmail_msg">
> +     uint32_t count;<br class="gmail_msg">
> +     struct wl_array *entries;<br class="gmail_msg">
> +<br class="gmail_msg">
> +     if (i < WL_SERVER_ID_START) {<br class="gmail_msg">
> +             entries = &map->client_entries;<br class="gmail_msg">
> +     } else {<br class="gmail_msg">
> +             entries = &map->server_entries;<br class="gmail_msg">
> +             i -= WL_SERVER_ID_START;<br class="gmail_msg">
> +     }<br class="gmail_msg">
> +<br class="gmail_msg">
> +     start = entries->data;<br class="gmail_msg">
> +     count = entries->size / sizeof *start;<br class="gmail_msg">
> +     if (i < count && !map_entry_is_free(start[i]))<br class="gmail_msg">
> +             start[i].next |= (flags & 0x1) << 1;<br class="gmail_msg">
> +}<br class="gmail_msg">
> +<br class="gmail_msg">
>  static enum wl_iterator_result<br class="gmail_msg">
>  for_each_helper(struct wl_array *entries, wl_iterator_func_t func, void *data)<br class="gmail_msg">
>  {<br class="gmail_msg">
><br class="gmail_msg">
<br class="gmail_msg">
_______________________________________________<br class="gmail_msg">
wayland-devel mailing list<br class="gmail_msg">
<a href="mailto:wayland-devel@lists.freedesktop.org" class="gmail_msg" target="_blank">wayland-devel@lists.freedesktop.org</a><br class="gmail_msg">
<a href="https://lists.freedesktop.org/mailman/listinfo/wayland-devel" rel="noreferrer" class="gmail_msg" target="_blank">https://lists.freedesktop.org/mailman/listinfo/wayland-devel</a><br class="gmail_msg">
</blockquote></div></div>