From 94f11ca5cf011ef123bd222cabeaef6f424d76ac Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 27 Jul 2017 10:08:32 -0700 Subject: xkb: Handle xkb formated string output safely (CVE-2017-13723) Generating strings for XKB data used a single shared static buffer, which offered several opportunities for errors. Use a ring of resizable buffers instead, to avoid problems when strings end up longer than anticipated. Reviewed-by: Michal Srb Signed-off-by: Keith Packard Signed-off-by: Julien Cristau diff --git a/xkb/xkbtext.c b/xkb/xkbtext.c index ead2b1a..d2a2567 100644 --- a/xkb/xkbtext.c +++ b/xkb/xkbtext.c @@ -47,23 +47,27 @@ /***====================================================================***/ -#define BUFFER_SIZE 512 - -static char textBuffer[BUFFER_SIZE]; -static int tbNext = 0; +#define NUM_BUFFER 8 +static struct textBuffer { + int size; + char *buffer; +} textBuffer[NUM_BUFFER]; +static int textBufferIndex; static char * tbGetBuffer(unsigned size) { - char *rtrn; + struct textBuffer *tb; - if (size >= BUFFER_SIZE) - return NULL; - if ((BUFFER_SIZE - tbNext) <= size) - tbNext = 0; - rtrn = &textBuffer[tbNext]; - tbNext += size; - return rtrn; + tb = &textBuffer[textBufferIndex]; + textBufferIndex = (textBufferIndex + 1) % NUM_BUFFER; + + if (size > tb->size) { + free(tb->buffer); + tb->buffer = xnfalloc(size); + tb->size = size; + } + return tb->buffer; } /***====================================================================***/ @@ -79,8 +83,6 @@ XkbAtomText(Atom atm, unsigned format) int len; len = strlen(atmstr) + 1; - if (len > BUFFER_SIZE) - len = BUFFER_SIZE - 2; rtrn = tbGetBuffer(len); strlcpy(rtrn, atmstr, len); } @@ -128,8 +130,6 @@ XkbVModIndexText(XkbDescPtr xkb, unsigned ndx, unsigned format) len = strlen(tmp) + 1; if (format == XkbCFile) len += 4; - if (len >= BUFFER_SIZE) - len = BUFFER_SIZE - 1; rtrn = tbGetBuffer(len); if (format == XkbCFile) { strcpy(rtrn, "vmod_"); @@ -140,6 +140,8 @@ XkbVModIndexText(XkbDescPtr xkb, unsigned ndx, unsigned format) return rtrn; } +#define VMOD_BUFFER_SIZE 512 + char * XkbVModMaskText(XkbDescPtr xkb, unsigned modMask, unsigned mask, unsigned format) @@ -147,7 +149,7 @@ XkbVModMaskText(XkbDescPtr xkb, register int i, bit; int len; char *mm, *rtrn; - char *str, buf[BUFFER_SIZE]; + char *str, buf[VMOD_BUFFER_SIZE]; if ((modMask == 0) && (mask == 0)) { rtrn = tbGetBuffer(5); @@ -173,7 +175,7 @@ XkbVModMaskText(XkbDescPtr xkb, len = strlen(tmp) + 1 + (str == buf ? 0 : 1); if (format == XkbCFile) len += 4; - if ((str - (buf + len)) <= BUFFER_SIZE) { + if ((str - (buf + len)) <= VMOD_BUFFER_SIZE) { if (str != buf) { if (format == XkbCFile) *str++ = '|'; @@ -199,8 +201,6 @@ XkbVModMaskText(XkbDescPtr xkb, len = 0; if (str) len += strlen(str) + (mm == NULL ? 0 : 1); - if (len >= BUFFER_SIZE) - len = BUFFER_SIZE - 1; rtrn = tbGetBuffer(len + 1); rtrn[0] = '\0'; -- cgit v0.10.2