summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOlivier Fourdan <ofourdan@redhat.com>2024-04-16 14:09:08 +0200
committerOlivier Fourdan <ofourdan@redhat.com>2024-05-03 10:33:44 +0200
commit67284dea0240668ff6a6a2093233f1796446e8c3 (patch)
tree72aa41d65b8362f4c78e17e27651b1b984bde521
parent2a391d6897e1a7121d61ef1cd77a30eeb21f1c6e (diff)
xwayland: Do not remove output on withdraw if leased
On DRM lease connector withdrawn event, Xwayland would free the corresponding xwl_output offered for lease. However, the pointer is still referenced from the rrLease->outputs[], meaning that trying to clean up the RANDR DRM leases as done with commit ef181265 (xwayland: Clean up drm lease when terminating) would cause a use after free and random crashes. To avoid that issue, on the connector withdraw event, set the connector withdrawn flag but do not to remove (i.e. free) the xwayland output if its is offered for lease. Then, once the lease is terminated, check for the xwl_outputs with a withdrawn connector and remove them (once we have no use for them anymore. Note that we cannot do that cleanup from xwl_randr_terminate_lease() as removing the xwl_output will free the RRcrtc resources, which checks for leases in XRANDR, and calls RRTerminateLease(), which chains back to xwl_randr_terminate_lease(). v2: Use a "withdrawn_connector" flag to mark outputs to remove (Xaver) Signed-off-by: Olivier Fourdan <ofourdan@redhat.com> Reviewed-by: Xaver Hugl <xaver.hugl@kde.org> fixes: ef181265 - xwayland: Clean up drm lease when terminating See-also: https://gitlab.freedesktop.org/xorg/xserver/-/issues/946 See-also: https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1130 (cherry picked from commit 4053782443f99761cf26e1acc31a9712253f4329) Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1515>
-rw-r--r--hw/xwayland/xwayland-drm-lease.c32
-rw-r--r--hw/xwayland/xwayland-output.h1
2 files changed, 31 insertions, 2 deletions
diff --git a/hw/xwayland/xwayland-drm-lease.c b/hw/xwayland/xwayland-drm-lease.c
index 9e29ebe09..2e27fc8ad 100644
--- a/hw/xwayland/xwayland-drm-lease.c
+++ b/hw/xwayland/xwayland-drm-lease.c
@@ -43,7 +43,24 @@ xwl_randr_lease_cleanup_outputs(RRLeasePtr rrLease)
for (i = 0; i < rrLease->numOutputs; ++i) {
output = rrLease->outputs[i]->devPrivate;
- output->lease = NULL;
+ if (output) {
+ output->lease = NULL;
+ }
+ }
+}
+
+static void
+xwl_randr_lease_free_outputs(RRLeasePtr rrLease)
+{
+ struct xwl_output *xwl_output;
+ int i;
+
+ for (i = 0; i < rrLease->numOutputs; ++i) {
+ xwl_output = rrLease->outputs[i]->devPrivate;
+ if (xwl_output && xwl_output->withdrawn_connector) {
+ rrLease->outputs[i]->devPrivate = NULL;
+ xwl_output_remove(xwl_output);
+ }
}
}
@@ -70,6 +87,9 @@ drm_lease_handle_finished(void *data,
AttendClient(lease->client);
xwl_randr_lease_cleanup_outputs(lease->rrLease);
}
+
+ /* Free the xwl_outputs that have been withdrawn while lease-able */
+ xwl_randr_lease_free_outputs(lease->rrLease);
}
static struct wp_drm_lease_v1_listener drm_lease_listener = {
@@ -319,7 +339,15 @@ static void
lease_connector_handle_withdrawn(void *data,
struct wp_drm_lease_connector_v1 *wp_drm_lease_connector_v1)
{
- xwl_output_remove(data);
+ struct xwl_output *xwl_output = data;
+
+ xwl_output->withdrawn_connector = TRUE;
+
+ /* Not removing the xwl_output if currently leased with Wayland */
+ if (xwl_output->lease)
+ return;
+
+ xwl_output_remove(xwl_output);
}
static const struct wp_drm_lease_connector_v1_listener lease_connector_listener = {
diff --git a/hw/xwayland/xwayland-output.h b/hw/xwayland/xwayland-output.h
index bcdf25bec..27b7729a5 100644
--- a/hw/xwayland/xwayland-output.h
+++ b/hw/xwayland/xwayland-output.h
@@ -62,6 +62,7 @@ struct xwl_output {
struct wp_drm_lease_connector_v1 *lease_connector;
struct xwl_drm_lease *lease;
struct xwl_drm_lease_device *lease_device;
+ Bool withdrawn_connector;
};
/* Per client per output emulated randr/vidmode resolution info. */