Skip to content
Commits on Source (8)
  • Marius Vlad's avatar
    libweston: Rename weston_surface_destroy() to weston_surface_unref() · 0d8e94af
    Marius Vlad authored
    
    
    Make it obvious that weston_surface has a reference counting happening
    and destruction of the weston_surface happens when the last
    weston_surface reference has been accounted for.
    
    Signed-off-by: default avatarMarius Vlad <marius.vlad@collabora.com>
    0d8e94af
  • Marius Vlad's avatar
    libweston: Assert if ref-count balance is wrong · d3ed2eb3
    Marius Vlad authored
    
    
    Calling weston_surface_unref() one time too many could be a sign we
    haven't correctly increased the ref count for it.
    
    Also, if we don't have a surface being passed, do no attempt to
    use it.
    
    Signed-off-by: default avatarMarius Vlad <marius.vlad@collabora.com>
    d3ed2eb3
  • Marius Vlad's avatar
    libweston, desktop-shell: Add a wrapper for weston_surface reference · bd831407
    Marius Vlad authored
    
    
    Similar to how we do it with drm_fb ref counts, increase a reference
    count and return the same object.
    
    Plug-in in desktop-shell when we map up the view in order to survive a
    weston_surface destruction.
    
    Astute readers will notice that this patch removes weston_view_destroy()
    while keeping the balance between removing and adding a
    weston_surface_unref() call in desktop_shell_destroy_surface().
    
    The reason is to let weston_surface_unref() handle destruction on its
    own. If multiple references are taken, then weston_surface_unref()
    doesn't destroy the view, it just decreases the reference, with
    a latter call to weston_surface_unref() to determine if the view
    should be destroyed as well.  This situation happens if we have
    close animation enabled, were we have more than one reference taken: one
    when mapping the view/surface and when when the surface itself was created,
    (what we call, a weak reference).
    
    If only a single reference is taken (for instance if we don't have close
    animations enabled) then this weston_surface_unref()
    call is inert as that reference is not set-up, leaving libweston to
    handle the view destruction.
    
    Following that with a weston_view_destroy() explicit call would cause a
    UAF as the view was previous destroyed by a weston_surface_unref() call.
    
    A side-effect of not keeping the weston_view_destroy() call would
    happen when tearing down the compositor. If close animations are enabled,
    weston_surface_unref() would not destroy the view, and because
    weston_view_destroy() no longer exists, we would still have the
    view in the other layers by the time we check-up if layers
    have views present.
    
    Signed-off-by: default avatarMarius Vlad <marius.vlad@collabora.com>
    bd831407
  • Marius Vlad's avatar
    desktop-shell: Create a distinct view for the fade-out close anim · 9cf60284
    Marius Vlad authored
    
    
    Creates a distinct view, separated from the one created by
    libweston-desktop, in order to avoid a potential ownership fight with
    libweston-desktop upon destroying the view. Upon weston_desktop_surface
    destruction, libweston-desktop inflicts damage on the view it creates,
    so we need the view to be alive at that time.
    
    This wasn't such an issue before because we had different destruction paths but
    with commit 'desktop-shell: Do not leave views in layers upon shell
    destruction' all of the destruction paths now land in the same spot
    + handle compositor tear down.
    
    Note as we still use the same weston_surface we'll keep the previous
    construct where we were taking a reference to keep it alive.
    
    The original view is destroyed when releasing the ownership, while for
    the view created in this patch we handle the destruction directly upon
    compositor tear down.
    
    Signed-off-by: default avatarMarius Vlad <marius.vlad@collabora.com>
    9cf60284
  • Marius Vlad's avatar
    desktop-shell: Rename destroy_layer functions · be5b6f9c
    Marius Vlad authored
    
    
    No functional change. Makes it obvious that we also call
    weston_layer_fini().
    
    Signed-off-by: default avatarMarius Vlad <marius.vlad@collabora.com>
    be5b6f9c
  • Marius Vlad's avatar
    desktop-shell: Migrate surface_unlink_view · c41cdcab
    Marius Vlad authored
    
    
    Moving weston_desktop_surface_unlink_view() to
    desktop_shell_destroy_surface() makes sure we don't leak the underlying
    weston_desktop_view when tearing/shutting down the compositor.
    
    Signed-off-by: default avatarMarius Vlad <marius.vlad@collabora.com>
    c41cdcab
  • Marius Vlad's avatar
    desktop-shell: Check for a valid desktop_surface · d03f0137
    Marius Vlad authored
    
    
    This patch fixes the following trace:
    
        #0 0x7f07d1bcecfa in weston_desktop_surface_get_surface ../libweston-desktop/surface.c:585
        #1 0x7f07d1bfc9b8 in move_grab_motion ../desktop-shell/shell.c:1499
        #2 0x7f07e539f841 in notify_motion ../libweston/input.c:1794
        #3 0x7f07e1e8ace4 in handle_pointer_motion ../libweston/libinput-device.c:132
        #4 0x7f07e1e8cad5 in evdev_device_process_event ../libweston/libinput-device.c:535
        #5 0x7f07e1e89311 in udev_input_process_event ../libweston/libinput-seat.c:208
        #6 0x7f07e1e8932f in process_event ../libweston/libinput-seat.c:218
        #7 0x7f07e1e8935f in process_events ../libweston/libinput-seat.c:228
        #8 0x7f07e1e8940a in udev_input_dispatch ../libweston/libinput-seat.c:239
        #9 0x7f07e1e89437 in libinput_source_dispatch ../libweston/libinput-seat.c:249
        #10 0x7f07e53122b1 in wl_event_loop_dispatch ../src/event-loop.c:1027
        #11 0x7f07e5310114 in wl_display_run ../src/wayland-server.c:1408
        #12 0x7f07e579c7ba in wet_main ../compositor/main.c:3589
        #13 0x555611d6b17d in main ../compositor/executable.c:33
        #14 0x7f07e55be7fc in __libc_start_main ../csu/libc-start.c:332
        #15 0x555611d6b099 in _start (/home/mvlad/install-amd64/bin/weston+0x1099)
    
    A highly unlikely, but still valid operation, is to close/destroy the
    window while still having it grabbed and moved around, basically having
    an in-flight destruction of grabbed moving window. Another situation
    would be that the client terminates abruptly (crashing for instance),
    while being dragged which might take down the compositor.
    
    This could happen for both touch/pointer grab operations and could cause
    a NULL pointer access while accessing desktop_surface when being used
    to retrieve the underlying weston_surface.
    
    With this patch we check for a valid desktop_surface and return early
    if that's not the case.
    
    Signed-off-by: default avatarMarius Vlad <marius.vlad@collabora.com>
    d03f0137
  • Marius Vlad's avatar
    desktop-shell: Clarify weston_view destruction at tear down · 299f87f0
    Marius Vlad authored
    
    
    This documents the fact that other views are handled implictly by
    libweston-desktop, and we shouldn't attempt to destroy indiscriminately
    views that aren't created by desktop-shell.
    
    Signed-off-by: default avatarMarius Vlad <marius.vlad@collabora.com>
    299f87f0
......@@ -101,6 +101,8 @@ struct shell_surface {
struct weston_desktop_surface *desktop_surface;
struct weston_view *view;
struct weston_surface *wsurface_anim_fade;
struct weston_view *wview_anim_fade;
int32_t last_width, last_height;
struct desktop_shell *shell;
......@@ -194,6 +196,10 @@ struct shell_seat {
};
static struct weston_view *
shell_fade_create_fade_out_view(struct shell_surface *shsurf,
struct weston_surface *surface);
static struct desktop_shell *
shell_surface_get_shell(struct shell_surface *shsurf);
......@@ -261,10 +267,11 @@ desktop_shell_destroy_surface(struct shell_surface *shsurf)
wl_list_init(&shsurf_child->children_link);
}
wl_list_remove(&shsurf->children_link);
weston_desktop_surface_unlink_view(shsurf->view);
wl_signal_emit(&shsurf->destroy_signal, shsurf);
weston_surface_unref(shsurf->wsurface_anim_fade);
weston_view_destroy(shsurf->view);
if (shsurf->output_destroy_listener.notify) {
wl_list_remove(&shsurf->output_destroy_listener.link);
shsurf->output_destroy_listener.notify = NULL;
......@@ -849,7 +856,7 @@ animate_focus_change(struct desktop_shell *shell, struct workspace *ws,
}
static void
desktop_shell_destroy_views_on_layer(struct weston_layer *layer);
desktop_shell_destroy_layer(struct weston_layer *layer);
static void
workspace_destroy(struct workspace *ws)
......@@ -864,7 +871,7 @@ workspace_destroy(struct workspace *ws)
if (ws->fsurf_back)
focus_surface_destroy(ws->fsurf_back);
desktop_shell_destroy_views_on_layer(&ws->layer);
desktop_shell_destroy_layer(&ws->layer);
free(ws);
}
......@@ -1353,7 +1360,7 @@ touch_move_grab_motion(struct weston_touch_grab *grab,
int dx = wl_fixed_to_int(grab->touch->grab_x + move->dx);
int dy = wl_fixed_to_int(grab->touch->grab_y + move->dy);
if (!shsurf || !move->active)
if (!shsurf || !shsurf->desktop_surface || !move->active)
return;
es = weston_desktop_surface_get_surface(shsurf->desktop_surface);
......@@ -1485,7 +1492,7 @@ move_grab_motion(struct weston_pointer_grab *grab,
int cx, cy;
weston_pointer_move(pointer, event);
if (!shsurf)
if (!shsurf || !shsurf->desktop_surface)
return;
surface = weston_desktop_surface_get_surface(shsurf->desktop_surface);
......@@ -2228,8 +2235,8 @@ fade_out_done(struct weston_view_animation *animation, void *data)
loop = wl_display_get_event_loop(shsurf->shell->compositor->wl_display);
if (weston_view_is_mapped(shsurf->view)) {
weston_view_unmap(shsurf->view);
if (weston_view_is_mapped(shsurf->wview_anim_fade)) {
weston_view_unmap(shsurf->wview_anim_fade);
wl_event_loop_add_idle(loop, fade_out_done_idle_cb, shsurf);
}
}
......@@ -2339,7 +2346,6 @@ desktop_surface_removed(struct weston_desktop_surface *desktop_surface,
weston_desktop_surface_set_user_data(shsurf->desktop_surface, NULL);
shsurf->desktop_surface = NULL;
weston_desktop_surface_unlink_view(shsurf->view);
if (weston_surface_is_mapped(surface) &&
shsurf->shell->win_close_animation_type == ANIMATION_FADE) {
......@@ -2348,11 +2354,26 @@ desktop_surface_removed(struct weston_desktop_surface *desktop_surface,
pixman_region32_init(&surface->pending.input);
pixman_region32_fini(&surface->input);
pixman_region32_init(&surface->input);
weston_fade_run(shsurf->view, 1.0, 0.0, 300.0,
/* its location might have changed, but also might've
* migrated to a different output, so re-compute this
* as the animation requires having the same output as
* the view */
weston_view_set_output(shsurf->wview_anim_fade,
shsurf->view->output);
weston_view_set_position(shsurf->wview_anim_fade,
shsurf->view->geometry.x,
shsurf->view->geometry.y);
weston_layer_entry_insert(&shsurf->view->layer_link,
&shsurf->wview_anim_fade->layer_link);
/* unmap the "original" view */
weston_view_unmap(shsurf->view);
weston_fade_run(shsurf->wview_anim_fade, 1.0, 0.0, 300.0,
fade_out_done, shsurf);
return;
} else {
weston_surface_destroy(surface);
}
}
......@@ -2475,8 +2496,15 @@ desktop_surface_committed(struct weston_desktop_surface *desktop_surface,
if (!weston_surface_is_mapped(surface)) {
map(shell, shsurf, sx, sy);
surface->is_mapped = true;
if (shsurf->shell->win_close_animation_type == ANIMATION_FADE)
++surface->ref_count;
/* as we need to survive the weston_surface destruction we'll
* need to take another reference */
if (shsurf->shell->win_close_animation_type == ANIMATION_FADE) {
shsurf->wsurface_anim_fade =
weston_surface_ref(surface);
shsurf->wview_anim_fade =
shell_fade_create_fade_out_view(shsurf, surface);
}
return;
}
......@@ -3899,6 +3927,29 @@ shell_fade_create_view_for_output(struct desktop_shell *shell,
return curtain;
}
static struct weston_view *
shell_fade_create_fade_out_view(struct shell_surface *shsurf,
struct weston_surface *surface)
{
struct weston_view *view;
struct weston_output *woutput;
view = weston_view_create(surface);
if (!view)
return NULL;
woutput = get_focused_output(surface->compositor);
/* set the initial position and output just in case we happen to not
* move it around and just destroy it */
weston_view_set_output(view, woutput);
weston_view_set_position(view,
shsurf->view->geometry.x,
shsurf->view->geometry.y);
view->is_mapped = true;
return view;
}
static void
shell_fade(struct desktop_shell *shell, enum fade_type type)
{
......@@ -4812,7 +4863,7 @@ setup_output_destroy_handler(struct weston_compositor *ec,
}
static void
desktop_shell_destroy_views_on_layer(struct weston_layer *layer)
desktop_shell_destroy_layer(struct weston_layer *layer)
{
struct weston_view *view, *view_next;
......@@ -4824,13 +4875,21 @@ desktop_shell_destroy_views_on_layer(struct weston_layer *layer)
* additional black_view created and added to its layer_link
* fullscreen view. See shell_ensure_fullscreen_black_view()
*
* As that black_view it is not a weston_desktop_surface
* we can't have a shsurf for it so we just destroy it like
* we do it in desktop_surface_removed() */
* Note that we do not choose to destroy all other potential
* views we find in the layer, but instead we explicitly verify
* if the view in question was explicitly created by
* desktop-shell, rather than libweston-desktop (in
* desktop_surface_added()).
*
* This is particularly important because libweston-desktop
* could create additional views, which are managed implicitly,
* but which are still being added to the layer list.
*
*/
if (shsurf)
desktop_shell_destroy_surface(shsurf);
else if (is_black_surface_view(view, NULL))
weston_surface_destroy(view->surface);
weston_surface_unref(view->surface);
}
weston_layer_fini(layer);
......@@ -4878,12 +4937,12 @@ shell_destroy(struct wl_listener *listener, void *data)
workspace_destroy(*ws);
wl_array_release(&shell->workspaces.array);
desktop_shell_destroy_views_on_layer(&shell->panel_layer);
desktop_shell_destroy_views_on_layer(&shell->background_layer);
desktop_shell_destroy_views_on_layer(&shell->lock_layer);
desktop_shell_destroy_views_on_layer(&shell->input_panel_layer);
desktop_shell_destroy_views_on_layer(&shell->minimized_layer);
desktop_shell_destroy_views_on_layer(&shell->fullscreen_layer);
desktop_shell_destroy_layer(&shell->panel_layer);
desktop_shell_destroy_layer(&shell->background_layer);
desktop_shell_destroy_layer(&shell->lock_layer);
desktop_shell_destroy_layer(&shell->input_panel_layer);
desktop_shell_destroy_layer(&shell->minimized_layer);
desktop_shell_destroy_layer(&shell->fullscreen_layer);
free(shell->client);
free(shell);
......
......@@ -2029,8 +2029,11 @@ struct weston_view_animation *
weston_slide_run(struct weston_view *view, float start, float stop,
weston_view_animation_done_func_t done, void *data);
struct weston_surface *
weston_surface_ref(struct weston_surface *surface);
void
weston_surface_destroy(struct weston_surface *surface);
weston_surface_unref(struct weston_surface *surface);
int
weston_output_mode_switch_to_temporary(struct weston_output *output,
......
......@@ -2295,14 +2295,28 @@ weston_view_destroy(struct weston_view *view)
free(view);
}
WL_EXPORT struct weston_surface *
weston_surface_ref(struct weston_surface *surface)
{
assert(surface->ref_count < INT32_MAX &&
surface->ref_count > 0);
surface->ref_count++;
return surface;
}
WL_EXPORT void
weston_surface_destroy(struct weston_surface *surface)
weston_surface_unref(struct weston_surface *surface)
{
struct wl_resource *cb, *next;
struct weston_view *ev, *nv;
struct weston_pointer_constraint *constraint, *next_constraint;
struct weston_paint_node *pnode, *pntmp;
if (!surface)
return;
assert(surface->ref_count > 0);
if (--surface->ref_count > 0)
return;
......@@ -2358,7 +2372,7 @@ destroy_surface(struct wl_resource *resource)
/* Set the resource to NULL, since we don't want to leave a
* dangling pointer if the surface was refcounted and survives
* the weston_surface_destroy() call. */
* the weston_surface_unref() call. */
surface->resource = NULL;
if (surface->viewport_resource)
......@@ -2369,7 +2383,7 @@ destroy_surface(struct wl_resource *resource)
NULL);
}
weston_surface_destroy(surface);
weston_surface_unref(surface);
}
static void
......@@ -4213,7 +4227,7 @@ compositor_create_surface(struct wl_client *client,
return;
err_res:
weston_surface_destroy(surface);
weston_surface_unref(surface);
err:
wl_resource_post_no_memory(resource);
}
......
......@@ -192,7 +192,7 @@ weston_curtain_create(struct weston_compositor *compositor,
err_view:
weston_view_destroy(view);
err_surface:
weston_surface_destroy(surface);
weston_surface_unref(surface);
err_curtain:
free(curtain);
err:
......@@ -206,7 +206,7 @@ weston_curtain_destroy(struct weston_curtain *curtain)
struct weston_surface *surface = curtain->view->surface;
weston_view_destroy(curtain->view);
weston_surface_destroy(surface);
weston_surface_unref(surface);
weston_buffer_destroy_solid(curtain->buffer_ref);
free(curtain);
}
......@@ -90,5 +90,5 @@ PLUGIN_TEST(surface_to_from_global)
assert(ix == 0 && iy == 0);
/* Destroys all views too. */
weston_surface_destroy(surface);
weston_surface_unref(surface);
}
......@@ -70,5 +70,5 @@ PLUGIN_TEST(surface_transform)
assert(x == 200 && y == 340);
/* Destroys all views too. */
weston_surface_destroy(surface);
weston_surface_unref(surface);
}