From 954969698ac87b05f30bf3eb3b7ae387b15c4145 Mon Sep 17 00:00:00 2001 From: Dominique Martinet Date: Mon, 25 Jun 2018 10:15:00 +0900 Subject: [PATCH 1/3] wlr_primary_selection: fix use-after-free when cancelling source seat->primary_election_source_destroy points to the source that just got freed by the cancel. ==7843==ERROR: AddressSanitizer: heap-use-after-free on address 0x60b0004269b0 at pc 0x7fb95bf4ccd0 bp 0x7ffd75013940 s p 0x7ffd75013930 WRITE of size 8 at 0x60b0004269b0 thread T0 #0 0x7fb95bf4cccf in wl_list_remove ../util/signal.c:55 #1 0x7fb95bf3f4c6 in wlr_seat_set_primary_selection ../types/wlr_primary_selection.c:238 #2 0x7fb95becb1a7 in xwm_handle_selection_event ../xwayland/selection/selection.c:124 #3 0x7fb95bed2e5d in x11_event_handler ../xwayland/xwm.c:1139 #4 0x7fb95c1bdf01 in wl_event_loop_dispatch src/event-loop.c:641 #5 0x7fb95c1bc601 in wl_display_run src/wayland-server.c:1260 #6 0x40a2f4 in main ../sway/main.c:433 #7 0x7fb95b69718a in __libc_start_main (/lib64/libc.so.6+0x2318a) #8 0x40b749 in _start (/opt/wayland/bin/sway+0x40b749) 0x60b0004269b0 is located 64 bytes inside of 112-byte region [0x60b000426970,0x60b0004269e0) freed by thread T0 here: #0 0x7fb95e0ad880 in __interceptor_free (/lib64/libasan.so.5+0xee880) #1 0x7fb95bf3f49e in wlr_seat_set_primary_selection ../types/wlr_primary_selection.c:236 #2 0x7fb95becb1a7 in xwm_handle_selection_event ../xwayland/selection/selection.c:124 #3 0x7fb95bed2e5d in x11_event_handler ../xwayland/xwm.c:1139 #4 0x7fb95c1bdf01 in wl_event_loop_dispatch src/event-loop.c:641 previously allocated by thread T0 here: #0 0x7fb95e0ade50 in calloc (/lib64/libasan.so.5+0xeee50) #1 0x7fb95bec7ad6 in xwm_selection_get_targets ../xwayland/selection/incoming.c:355 #2 0x7fb95bec7ad6 in xwm_handle_selection_notify ../xwayland/selection/incoming.c:402 #3 0x7fb95becb1a7 in xwm_handle_selection_event ../xwayland/selection/selection.c:124 #4 0x7fb95bed2e5d in x11_event_handler ../xwayland/xwm.c:1139 #5 0x7fb95c1bdf01 in wl_event_loop_dispatch src/event-loop.c:641 SUMMARY: AddressSanitizer: heap-use-after-free ../util/signal.c:55 in wl_list_remove Shadow bytes around the buggy address: 0x0c168007cce0: fd fd fd fa fa fa fa fa fa fa fa fa fd fd fd fd 0x0c168007ccf0: fd fd fd fd fd fd fd fd fd fa fa fa fa fa fa fa 0x0c168007cd00: fa fa fd fd fd fd fd fd fd fd fd fd fd fd fd fa 0x0c168007cd10: fa fa fa fa fa fa fa fa fd fd fd fd fd fd fd fd 0x0c168007cd20: fd fd fd fd fd fa fa fa fa fa fa fa fa fa fd fd =>0x0c168007cd30: fd fd fd fd fd fd[fd]fd fd fd fd fd fa fa fa fa 0x0c168007cd40: fa fa fa fa fd fd fd fd fd fd fd fd fd fd fd fd 0x0c168007cd50: fd fa fa fa fa fa fa fa fa fa fd fd fd fd fd fd 0x0c168007cd60: fd fd fd fd fd fd fd fa fa fa fa fa fa fa fa fa 0x0c168007cd70: fd fd fd fd fd fd fd fd fd fd fd fd fd fa fa fa 0x0c168007cd80: fa fa fa fa fa fa fd fd fd fd fd fd fd fd fd fd --- types/wlr_primary_selection.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/types/wlr_primary_selection.c b/types/wlr_primary_selection.c index b8f3094b..15452071 100644 --- a/types/wlr_primary_selection.c +++ b/types/wlr_primary_selection.c @@ -229,9 +229,9 @@ void wlr_seat_set_primary_selection(struct wlr_seat *seat, } if (seat->primary_selection_source) { + wl_list_remove(&seat->primary_selection_source_destroy.link); seat->primary_selection_source->cancel(seat->primary_selection_source); seat->primary_selection_source = NULL; - wl_list_remove(&seat->primary_selection_source_destroy.link); } seat->primary_selection_source = source; From 4a1c9a19257305abfbf8498a5405fe119049a322 Mon Sep 17 00:00:00 2001 From: Dominique Martinet Date: Mon, 25 Jun 2018 10:30:51 +0900 Subject: [PATCH 2/3] xwm: fix use-after-free involving parents/children Happens when e.g. closing gimp. ==24039==ERROR: AddressSanitizer: heap-use-after-free on address 0x6150001a7a78 at pc 0x7f09b09f1bb2 bp 0x7ffcf0237bf0 sp 0x7ffcf0237be0 WRITE of size 8 at 0x6150001a7a78 thread T0 #0 0x7f09b09f1bb1 in wl_list_remove ../util/signal.c:55 #1 0x7f09b094cf03 in xwayland_surface_destroy ../xwayland/xwm.c:295 #2 0x7f09b0950245 in xwm_handle_destroy_notify ../xwayland/xwm.c:717 #3 0x7f09b095304a in x11_event_handler ../xwayland/xwm.c:1149 #4 0x7f09b0c68f01 in wl_event_loop_dispatch src/event-loop.c:641 #5 0x7f09b0c67601 in wl_display_run src/wayland-server.c:1260 #6 0x40a2f4 in main ../sway/main.c:433 #7 0x7f09b011018a in __libc_start_main (/lib64/libc.so.6+0x2318a) #8 0x40b749 in _start (/opt/wayland/bin/sway+0x40b749) 0x6150001a7a78 is located 120 bytes inside of 496-byte region [0x6150001a7a00,0x6150001a7bf0) freed by thread T0 here: #0 0x7f09b2b58880 in __interceptor_free (/lib64/libasan.so.5+0xee880) #1 0x7f09b094d1a1 in xwayland_surface_destroy ../xwayland/xwm.c:315 #2 0x7f09b0950245 in xwm_handle_destroy_notify ../xwayland/xwm.c:717 #3 0x7f09b095304a in x11_event_handler ../xwayland/xwm.c:1149 #4 0x7f09b0c68f01 in wl_event_loop_dispatch src/event-loop.c:641 #5 0x7f09b0c67601 in wl_display_run src/wayland-server.c:1260 #6 0x40a2f4 in main ../sway/main.c:433 #7 0x7f09b011018a in __libc_start_main (/lib64/libc.so.6+0x2318a) #8 0x40b749 in _start (/opt/wayland/bin/sway+0x40b749) previously allocated by thread T0 here: #0 0x7f09b2b58e50 in calloc (/lib64/libasan.so.5+0xeee50) #1 0x7f09b094b585 in xwayland_surface_create ../xwayland/xwm.c:119 #2 0x7f09b0950151 in xwm_handle_create_notify ../xwayland/xwm.c:706 #3 0x7f09b0953032 in x11_event_handler ../xwayland/xwm.c:1146 #4 0x7f09b0c68f01 in wl_event_loop_dispatch src/event-loop.c:641 #5 0x7f09b0c67601 in wl_display_run src/wayland-server.c:1260 #6 0x40a2f4 in main ../sway/main.c:433 #7 0x7f09b011018a in __libc_start_main (/lib64/libc.so.6+0x2318a) #8 0x40b749 in _start (/opt/wayland/bin/sway+0x40b749) --- xwayland/xwm.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/xwayland/xwm.c b/xwayland/xwm.c index b397b1e8..66a85d05 100644 --- a/xwayland/xwm.c +++ b/xwayland/xwm.c @@ -294,6 +294,12 @@ static void xwayland_surface_destroy( wl_list_remove(&xsurface->link); wl_list_remove(&xsurface->parent_link); + struct wlr_xwayland_surface *child, *next; + wl_list_for_each_safe(child, next, &xsurface->children, parent_link) { + wl_list_remove(&child->parent_link); + wl_list_init(&child->parent_link); + } + if (xsurface->surface_id) { wl_list_remove(&xsurface->unpaired_link); } From ffd37b664f6fbb01d6be44411b3117c88ee61fe2 Mon Sep 17 00:00:00 2001 From: Dominique Martinet Date: Mon, 25 Jun 2018 07:35:13 +0900 Subject: [PATCH 3/3] xdg_shell: destroy children popups with parent surface popups have a link in parent's surface->popups list and needs to be freed before: ==6902==ERROR: AddressSanitizer: heap-use-after-free on address 0x6120001a0300 at pc 0x7fc1447acb50 bp 0x7fffd396e680 sp 0x7fffd396e670 WRITE of size 8 at 0x6120001a0300 thread T0 #0 0x7fc1447acb4f in wl_list_remove ../util/signal.c:55 #1 0x7fc14477d206 in destroy_xdg_popup_v6 ../types/xdg_shell_v6/wlr_xdg_popup_v6.c:162 #2 0x7fc1447816e0 in destroy_xdg_surface_v6 ../types/xdg_shell_v6/wlr_xdg_surface_v6.c:108 #3 0x7fc144a1c025 in destroy_resource src/wayland-server.c:688 #4 0x7fc144a1c091 in wl_resource_destroy src/wayland-server.c:705 #5 0x7fc14477fd6f in xdg_client_v6_handle_resource_destroy ../types/xdg_shell_v6/wlr_xdg_shell_v6.c:72 #6 0x7fc144a1c025 in destroy_resource src/wayland-server.c:688 #7 0x7fc144a20851 (/lib64/libwayland-server.so.0+0xc851) #8 0x7fc144a20d92 (/lib64/libwayland-server.so.0+0xcd92) #9 0x7fc144a1c140 in wl_client_destroy src/wayland-server.c:847 #10 0x7fc144a1c21c in destroy_client_with_error src/wayland-server.c:307 #11 0x7fc144a1c21c in wl_client_connection_data src/wayland-server.c:330 #12 0x7fc144a1df01 in wl_event_loop_dispatch src/event-loop.c:641 #13 0x7fc144a1c601 in wl_display_run src/wayland-server.c:1260 #14 0x40a2f4 in main ../sway/main.c:433 #15 0x7fc143ef718a in __libc_start_main ../csu/libc-start.c:308 #16 0x40b749 in _start (/opt/wayland/bin/sway+0x40b749) 0x6120001a0300 is located 64 bytes inside of 264-byte region [0x6120001a02c0,0x6120001a03c8) freed by thread T0 here: #0 0x7fc14690d880 in __interceptor_free (/lib64/libasan.so.5+0xee880) #1 0x7fc1447acce8 in wlr_signal_emit_safe ../util/signal.c:29 #2 0x7fc1447a3cac in surface_handle_resource_destroy ../types/wlr_surface.c:576 #3 0x7fc144a1c025 in destroy_resource src/wayland-server.c:688 previously allocated by thread T0 here: #0 0x7fc14690de50 in calloc (/lib64/libasan.so.5+0xeee50) #1 0x7fc144781d38 in create_xdg_surface_v6 ../types/xdg_shell_v6/wlr_xdg_surface_v6.c:415 #2 0x7fc14147503d in ffi_call_unix64 (/lib64/libffi.so.6+0x603d) Alternative would be to have popups listen to the parent's surface destroy event and remove themselves from the list at this point OR on their own destroy, whichever happens first, but that seems more complicated for little benefit. --- types/xdg_shell/wlr_xdg_surface.c | 6 ++++++ types/xdg_shell_v6/wlr_xdg_surface_v6.c | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/types/xdg_shell/wlr_xdg_surface.c b/types/xdg_shell/wlr_xdg_surface.c index c5d177b2..6931b92f 100644 --- a/types/xdg_shell/wlr_xdg_surface.c +++ b/types/xdg_shell/wlr_xdg_surface.c @@ -415,6 +415,12 @@ void destroy_xdg_surface(struct wlr_xdg_surface *surface) { wlr_signal_emit_safe(&surface->events.destroy, surface); + struct wlr_xdg_popup *popup_state, *next; + wl_list_for_each_safe(popup_state, next, &surface->popups, link) { + xdg_popup_send_popup_done(popup_state->resource); + destroy_xdg_popup(popup_state->base); + } + switch (surface->role) { case WLR_XDG_SURFACE_ROLE_TOPLEVEL: destroy_xdg_toplevel(surface); diff --git a/types/xdg_shell_v6/wlr_xdg_surface_v6.c b/types/xdg_shell_v6/wlr_xdg_surface_v6.c index e111adad..7343906f 100644 --- a/types/xdg_shell_v6/wlr_xdg_surface_v6.c +++ b/types/xdg_shell_v6/wlr_xdg_surface_v6.c @@ -100,6 +100,12 @@ void destroy_xdg_surface_v6(struct wlr_xdg_surface_v6 *surface) { wlr_signal_emit_safe(&surface->events.destroy, surface); + struct wlr_xdg_popup_v6 *popup_state, *next; + wl_list_for_each_safe(popup_state, next, &surface->popups, link) { + zxdg_popup_v6_send_popup_done(popup_state->resource); + destroy_xdg_popup_v6(popup_state->base); + } + switch (surface->role) { case WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL: destroy_xdg_toplevel_v6(surface);