From c03bc789aed3fdf72af0bf0d2ec0d3cf073ecdf8 Mon Sep 17 00:00:00 2001 From: "Enrico Weigelt, metux IT consult" Date: Tue, 7 Jul 2026 13:29:20 +0200 Subject: [PATCH] dri2: fix off-by-one heap overflow in do_get_buffers() buffer array The buffers array was sized min(count, DRI2BufferHiz) + 1, but count is already capped at DRI2BufferHiz + 1 by the check above. The min() only changes anything at that exact boundary (count == DRI2BufferHiz + 1), where it throws away the array's '+1 slack' right when the main loop can legitimately fill all 'count' slots itself, leaving no room for a synthesized real/fake front buffer the client didn't explicitly request. Trigger: a DRI2-capable client sends DRI2GetBuffers/DRI2GetBuffersWithFormat with 11 attachment entries (the maximum allowed), none of them DRI2BufferFrontLeft but at least one DRI2BufferBackLeft (so need_real_front ends up set) -- the post-loop synthesis writes buffers[11], one past the 11-element allocation. Deterministic, no OOM required. Fix: allocate count + 1 slots unconditionally; count is already bounded, so this is never a meaningfully larger allocation. Found via a fleet-directed alloc-fail/UAF sweep of Xext/, not from a live crash report. Signed-off-by: Enrico Weigelt, metux IT consult --- Xext/dri2/dri2.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/Xext/dri2/dri2.c b/Xext/dri2/dri2.c index 5ba033fab1..62159070a3 100644 --- a/Xext/dri2/dri2.c +++ b/Xext/dri2/dri2.c @@ -540,9 +540,17 @@ do_get_buffers(DrawablePtr pDraw, int *width, int *height, && (pDraw->height == pPriv->height); /* Since we deduplicate attachments in the buffers array, there cannot be - * more entries than there are attachments. + * more entries than there are attachments, plus one slot for a + * synthesized real/fake front buffer the client didn't explicitly + * request. 'count' is already capped at DRI2BufferHiz + 1 by the check + * above, so this is never a large allocation; clamping it again via + * min(count, DRI2BufferHiz) is wrong at that exact boundary (count == + * DRI2BufferHiz + 1) -- it throws away the "+1" slack right when the + * loop below can legitimately use every one of the 'count' slots itself, + * leaving no room for the synthesized buffer and writing one past the + * end of this array. */ - DRI2BufferPtr *buffers = calloc((min(count, DRI2BufferHiz) + 1), sizeof(buffers[0])); + DRI2BufferPtr *buffers = calloc(count + 1, sizeof(buffers[0])); if (!buffers) goto err_out;