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 <info@metux.net>
This commit is contained in:
Enrico Weigelt, metux IT consult 2026-07-07 13:29:20 +02:00 • committed by Enrico Weigelt
commit c03bc789ae

View file

@ -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;