From 84081451bc4344efa0d85ec0cf2dc7f256ee579c Mon Sep 17 00:00:00 2001 From: stefan11111 Date: Thu, 7 Aug 2025 01:11:13 +0300 Subject: [PATCH] os: fix OutputBufferMakeRoom and rename it to OutputBufferMakeRoomAndFlush This function was badly broken, among other things doing a use after free, a NULL-pointer dereferrence, and not doing what it was supposed to do. Signed-off-by: stefan11111 --- os/io.c | 57 ++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 36 insertions(+), 21 deletions(-) diff --git a/os/io.c b/os/io.c index 7f22d71a74..9c53cc7e6f 100644 --- a/os/io.c +++ b/os/io.c @@ -62,6 +62,7 @@ SOFTWARE. #endif #include #include +#include #include "os/Xtrans.h" #include #include @@ -691,36 +692,54 @@ static bool OutputEnsureBuffer(ClientPtr who, OsCommPtr oc) return false; } +static inline int +memcpy_and_flush(ClientPtr who, OsCommPtr oc, const void* extra_buf, size_t extra_size, size_t padsize) +{ + ConnectionOutputPtr oco = oc->output; + + memcpy(oco->buf + oco->count, extra_buf, extra_size); + oco->count += extra_size; + memset(oco->buf + oco->count, 0, padsize); + oco->count += padsize; + return (FlushClient(who, oc) == -1) ? -1 : extra_size; /* return the requested size, or fail */ +} + /* * try to make room in the output buffer: * if not enough room, try to flush first. - * if that's not giving enough room, increase the buffer size + * if that's not giving enough room, increase the buffer size. */ -static bool OutputBufferMakeRoom(ClientPtr who, OsCommPtr oc, size_t sz) +static int +OutputBufferMakeRoomAndFlush(ClientPtr who, OsCommPtr oc, const void* extra_buf, size_t extra_size) { - const size_t padsize = padding_for_int32(sz); - const size_t needed = sz + padsize; + const size_t padsize = padding_for_int32(extra_size); + const size_t needed = extra_size + padsize; if (oc->output) { /* check whether it already fits into buffer */ - if (oc->output->count + needed <= oc->output->size) - return true; + if (oc->output->count + needed <= oc->output->size) { + return memcpy_and_flush(who, oc, extra_buf, extra_size, padsize); + } /* try flushing the buffer */ - int ret = FlushClient(who, oc); - if (ret == -1) /* client was aborted */ - return false; + if (FlushClient(who, oc) == -1) { + /* client was aborted */ + return -1; + } } - if (!OutputEnsureBuffer(who, oc)) - return false; + if (!OutputEnsureBuffer(who, oc)) { + return -1; + } ConnectionOutputPtr oco = oc->output; /* does it fit this time ? */ - if (oco->count + needed <= oco->size) - return true; + if (oco->count + needed <= oco->size) { + return memcpy_and_flush(who, oc, extra_buf, extra_size, padsize); + } + /* still not enough */ /* try to resize the buffer */ const int newsize = oco->count + (((needed / BUFSIZE)+1)*BUFSIZE); @@ -729,12 +748,13 @@ static bool OutputBufferMakeRoom(ClientPtr who, OsCommPtr oc, size_t sz) AbortClient(who); dixMarkClientException(who); oco->count = 0; - return false; + return -1; } oco->buf = newbuf; oco->size = newsize; - return true; + + return memcpy_and_flush(who, oc, extra_buf, extra_size, padsize); } /***************** @@ -859,14 +879,9 @@ WriteToClient(ClientPtr who, int count, const void *__buf) CriticalOutputPending = FALSE; NewOutputPending = FALSE; } + return OutputBufferMakeRoomAndFlush(who, oc, buf, count); } - /* if we fail to make room, the client will be aborted */ - if (!OutputBufferMakeRoom(who, oc, count)) - return -1; - - oco = oc->output; - NewOutputPending = TRUE; output_pending_mark(who); memmove((char *) oco->buf + oco->count, buf, count);