From dc27dd7e95329505a28eb194e3a49c603a195740 Mon Sep 17 00:00:00 2001 From: Derek Foreman Date: Fri, 10 Oct 2025 09:46:35 -0500 Subject: [PATCH] compositor: Validate buffer scale We're supposed to generate an INVALID_SIZE error if the buffer size isn't an integer multiple of the scale. Signed-off-by: Derek Foreman --- libweston/compositor.c | 53 ++++++++++++++++++++++++++++++---- libweston/libweston-internal.h | 20 +++++++++++++ libweston/surface-state.c | 12 ++++---- 3 files changed, 73 insertions(+), 12 deletions(-) diff --git a/libweston/compositor.c b/libweston/compositor.c index 5ffecf23e..80b186f87 100644 --- a/libweston/compositor.c +++ b/libweston/compositor.c @@ -4617,14 +4617,13 @@ weston_surface_is_pending_viewport_source_valid( if ((pend->status & WESTON_SURFACE_DIRTY_BUFFER) || (pend->status & WESTON_SURFACE_DIRTY_SIZE)) { if (pend->buffer_ref.buffer) { + bool size_ok; struct weston_buffer *buf = pend->buffer_ref.buffer; - convert_size_by_transform_scale(&width_from_buffer, - &height_from_buffer, - buf->width, - buf->height, - vp->buffer.transform, - vp->buffer.scale); + size_ok = convert_buffer_size_by_transform_scale(&width_from_buffer, + &height_from_buffer, + buf, vp); + weston_assert_true(surface->compositor, size_ok); } else { /* No buffer: viewport is irrelevant. */ return true; @@ -4686,6 +4685,48 @@ surface_commit(struct wl_client *client, struct wl_resource *resource) struct weston_surface *surface = wl_resource_get_user_data(resource); WESTON_TRACE_FUNC_FLOW(&surface->flow_id); enum weston_surface_status status; + struct weston_buffer *buffer; + int32_t tmp_w, tmp_h; + + buffer = surface->pending.buffer_ref.buffer; + if (buffer && + !convert_buffer_size_by_transform_scale(&tmp_w, &tmp_h, + buffer, + &surface->pending.buffer_viewport)) { + wl_resource_post_error(surface->resource, + WL_SURFACE_ERROR_INVALID_SIZE, + "surface size (%dx%d) was not an integer multiple of scale (%d)", + buffer->width, buffer->height, + surface->pending.buffer_viewport.buffer.scale); + return; + } + /* If there is no pending buffer, we could be trying to use new + * scale with an old buffer, so test surface->*_from_buffer against + * pending scale. The stored width/height have already been divided + * by the current scale, so multiply that back in before testing + * against the pending scale. We might actually be confusing width + * and height here, as we're losing transform information, but that + * has no impact on the test. + * + * If we've never had a buffer, we'll be testing 0 dimensions, which + * will just magically look ok. + */ + if (!buffer) { + int32_t old_buffer_width = surface->width_from_buffer * + surface->buffer_viewport.buffer.scale; + int32_t old_buffer_height = surface->height_from_buffer * + surface->buffer_viewport.buffer.scale; + + if (old_buffer_width % surface->pending.buffer_viewport.buffer.scale || + old_buffer_height % surface->pending.buffer_viewport.buffer.scale) { + wl_resource_post_error(surface->resource, + WL_SURFACE_ERROR_INVALID_SIZE, + "surface size (%dx%d) was not an integer multiple of scale (%d)", + surface->width_from_buffer, surface->height_from_buffer, + surface->pending.buffer_viewport.buffer.scale); + return; + } + } if (!weston_surface_is_pending_viewport_source_valid(surface)) { assert(surface->viewport_resource); diff --git a/libweston/libweston-internal.h b/libweston/libweston-internal.h index e14c6fbf1..a4d269ffd 100644 --- a/libweston/libweston-internal.h +++ b/libweston/libweston-internal.h @@ -805,6 +805,26 @@ convert_size_by_transform_scale(int32_t *width_out, int32_t *height_out, } } +static inline bool +convert_buffer_size_by_transform_scale(int32_t *width_out, int32_t *height_out, + const struct weston_buffer *buf, + const struct weston_buffer_viewport *vp) +{ + /* Buffer dimensions must be integer multiples of the scale */ + if (buf->width % vp->buffer.scale || + buf->height % vp->buffer.scale) + return false; + + convert_size_by_transform_scale(width_out, height_out, + buf->width, buf->height, + vp->buffer.transform, + vp->buffer.scale); + if (*width_out == 0 || *height_out == 0) + return false; + + return true; +} + /* User authentication for remote backends */ bool diff --git a/libweston/surface-state.c b/libweston/surface-state.c index 6264cd418..6432aad99 100644 --- a/libweston/surface-state.c +++ b/libweston/surface-state.c @@ -34,6 +34,7 @@ #include "backend.h" #include "pixel-formats.h" #include "shared/fd-util.h" +#include "shared/weston-assert.h" #include "timeline.h" #include "weston-trace.h" @@ -148,13 +149,12 @@ weston_surface_attach(struct weston_surface *surface, struct weston_buffer_viewport *vp = &state->buffer_viewport; int32_t old_width = surface->width_from_buffer; int32_t old_height = surface->height_from_buffer; + bool size_ok; - convert_size_by_transform_scale(&surface->width_from_buffer, - &surface->height_from_buffer, - buffer->width, - buffer->height, - vp->buffer.transform, - vp->buffer.scale); + size_ok = convert_buffer_size_by_transform_scale(&surface->width_from_buffer, + &surface->height_from_buffer, + buffer, vp); + weston_assert_true(surface->compositor, size_ok); if (surface->width_from_buffer != old_width || surface->height_from_buffer != old_height) {