diff --git a/WINGs/wview_wl.c b/WINGs/wview_wl.c index db98784..b0c065e 100644 --- a/WINGs/wview_wl.c +++ b/WINGs/wview_wl.c @@ -46,6 +46,7 @@ void (*W_DragIconHideFn)(void) = NULL; * cursor changes. accepted=True means the view accepts the drop. */ void (*W_DragCursorFeedbackFn)(Bool accepted) = NULL; void (*W_SetCursorImageFn)(const char *name) = NULL; +void (*W_ViewDestroyedFn)(struct W_View *view) = NULL; extern void wl_view_destroy_backing_impl(unsigned long id); @@ -487,6 +488,7 @@ static void wl_destroy(void *vctx, W_View *view) pixman_image_t *img = (pixman_image_t *)W_GetViewBacking(view->window); if (img) pixman_image_unref(img); + if (W_ViewDestroyedFn) W_ViewDestroyedFn(view); view_table_remove(view->window); } diff --git a/src/backend/wayland/wl_backend.c b/src/backend/wayland/wl_backend.c index 6683e1a..ab7ff2a 100644 --- a/src/backend/wayland/wl_backend.c +++ b/src/backend/wayland/wl_backend.c @@ -475,6 +475,10 @@ wl_display_open(const char *name) extern void wl_set_cursor_image(const char *name); W_SetCursorImageFn = wl_set_cursor_image; + extern void (*W_ViewDestroyedFn)(struct W_View *view); + extern void wl_view_destroyed_hook(struct W_View *v); + W_ViewDestroyedFn = wl_view_destroyed_hook; + extern int (*W_WLPointerGrabFn)(WNativeWindow, WNativeWindow, unsigned int, int, int, unsigned long); extern void (*W_WLPointerUngrabFn)(unsigned long); diff --git a/src/backend/wayland/wl_client.c b/src/backend/wayland/wl_client.c index 14e4437..a216c26 100644 --- a/src/backend/wayland/wl_client.c +++ b/src/backend/wayland/wl_client.c @@ -394,6 +394,11 @@ wl_view_scene_node_set_enabled(unsigned long id, int enabled) void wl_view_destroy_backing_impl(unsigned long id) { + /* NULL out last_hovered_view if it points to this dying view. + * Avoids UAF when the motion handler reads the stale pointer. */ + if (wl_state.last_hovered_view + && (unsigned long)wl_state.last_hovered_view->window == id) + wl_state.last_hovered_view = NULL; struct wl_frame_buf *fb = frame_buf_find((WNativeWindow)id); if (!fb) return; wl_list_remove(&fb->link); diff --git a/src/backend/wayland/wl_pointer_motion.c b/src/backend/wayland/wl_pointer_motion.c index f6dab3c..9a36d72 100644 --- a/src/backend/wayland/wl_pointer_motion.c +++ b/src/backend/wayland/wl_pointer_motion.c @@ -16,6 +16,12 @@ /* Forward declarations for functions defined in other wl_*.c files */ void W_WL_EnqueueEvent(struct W_Screen *scr, const WMEvent *ev, struct W_View *target); extern void (*W_SetCursorImageFn)(const char *name); + +void wl_view_destroyed_hook(struct W_View *v) +{ + if (wl_state.last_hovered_view == v) + wl_state.last_hovered_view = NULL; +} void wl_grab_apply_motion(void); void wl_update_pointer_focus(uint32_t time_msec); WMScreen *wl_get_wmscreen(void);