From e0f239fa2828318e9eff6b68f7faafecd338914c Mon Sep 17 00:00:00 2001 From: Aleksei Bavshin Date: Fri, 16 Apr 2021 19:27:12 -0700 Subject: [PATCH] xwayland: query window PIDs via XResQueryClientIds `_NET_WM_PID` is unreliable: it is optional and even if set it may contain PIDs from sandbox namespaces or remote systems. Prefer XRes v1.2 QueryClientIds method which returns PIDs as seen by the Xwayland server. --- include/xwayland/xwm.h | 1 + xwayland/meson.build | 1 + xwayland/xwm.c | 63 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 65 insertions(+) diff --git a/include/xwayland/xwm.h b/include/xwayland/xwm.h index 587f136b..05d229ae 100644 --- a/include/xwayland/xwm.h +++ b/include/xwayland/xwm.h @@ -113,6 +113,7 @@ struct wlr_xwm { struct wlr_xwayland_surface *drag_focus; const xcb_query_extension_reply_t *xfixes; + const xcb_query_extension_reply_t *xres; #if HAS_XCB_ERRORS xcb_errors_context_t *errors_context; #endif diff --git a/xwayland/meson.build b/xwayland/meson.build index bbf96eac..b7bbcaf1 100644 --- a/xwayland/meson.build +++ b/xwayland/meson.build @@ -4,6 +4,7 @@ xwayland_required = [ 'xcb-composite', 'xcb-icccm', 'xcb-render', + 'xcb-res', 'xcb-xfixes', ] xwayland_optional = { diff --git a/xwayland/xwm.c b/xwayland/xwm.c index f380f8f1..9ac2773d 100644 --- a/xwayland/xwm.c +++ b/xwayland/xwm.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include "util/signal.h" @@ -510,6 +511,41 @@ static void read_surface_parent(struct wlr_xwm *xwm, wlr_signal_emit_safe(&xsurface->events.set_parent, xsurface); } +static void read_surface_client_id(struct wlr_xwm *xwm, + struct wlr_xwayland_surface *xsurface) { + xcb_res_client_id_spec_t spec = { + .client = xsurface->window_id, + .mask = XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID + }; + + xcb_res_query_client_ids_cookie_t cookie = xcb_res_query_client_ids( + xwm->xcb_conn, 1, &spec); + xcb_res_query_client_ids_reply_t *reply = xcb_res_query_client_ids_reply( + xwm->xcb_conn, cookie, NULL); + if (reply == NULL) { + return; + } + + uint32_t *pid = NULL; + xcb_res_client_id_value_iterator_t iter = + xcb_res_query_client_ids_ids_iterator(reply); + while (iter.rem > 0) { + if (iter.data->spec.mask & XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID && + xcb_res_client_id_value_value_length(iter.data) > 0) { + pid = xcb_res_client_id_value_value(iter.data); + break; + } + xcb_res_client_id_value_next(&iter); + } + if (pid == NULL) { + free(reply); + return; + } + xsurface->pid = *pid; + wlr_signal_emit_safe(&xsurface->events.set_pid, xsurface); + free(reply); +} + static void read_surface_pid(struct wlr_xwm *xwm, struct wlr_xwayland_surface *xsurface, xcb_get_property_reply_t *reply) { @@ -818,6 +854,9 @@ static void xwm_map_shell_surface(struct wlr_xwm *xwm, for (size_t i = 0; i < sizeof(props)/sizeof(xcb_atom_t); i++) { read_surface_property(xwm, xsurface, props[i]); } + if (xwm->xres) { + read_surface_client_id(xwm, xsurface); + } xsurface->surface_destroy.notify = handle_surface_destroy; wl_signal_add(&surface->events.destroy, &xsurface->surface_destroy); @@ -1621,6 +1660,7 @@ void xwm_destroy(struct wlr_xwm *xwm) { static void xwm_get_resources(struct wlr_xwm *xwm) { xcb_prefetch_extension_data(xwm->xcb_conn, &xcb_xfixes_id); xcb_prefetch_extension_data(xwm->xcb_conn, &xcb_composite_id); + xcb_prefetch_extension_data(xwm->xcb_conn, &xcb_res_id); size_t i; xcb_intern_atom_cookie_t cookies[ATOM_LAST]; @@ -1664,6 +1704,29 @@ static void xwm_get_resources(struct wlr_xwm *xwm) { xfixes_reply->major_version, xfixes_reply->minor_version); free(xfixes_reply); + + const xcb_query_extension_reply_t *xres = + xcb_get_extension_data(xwm->xcb_conn, &xcb_res_id); + if (!xres || !xres->present) { + return; + } + + xcb_res_query_version_cookie_t xres_cookie = + xcb_res_query_version(xwm->xcb_conn, XCB_RES_MAJOR_VERSION, + XCB_RES_MINOR_VERSION); + xcb_res_query_version_reply_t *xres_reply = + xcb_res_query_version_reply(xwm->xcb_conn, xres_cookie, NULL); + if (xres_reply == NULL) { + return; + } + + wlr_log(WLR_DEBUG, "xres version: %" PRIu32 ".%" PRIu32, + xres_reply->server_major, xres_reply->server_minor); + if (xres_reply->server_major > 1 || + (xres_reply->server_major == 1 && xres_reply->server_minor >= 2)) { + xwm->xres = xres; + } + free(xres_reply); } static void xwm_create_wm_window(struct wlr_xwm *xwm) {