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 <msrb@suse.com>
Signed-off-by: Keith Packard <keithp@keithp.com>
Signed-off-by: Julien Cristau <jcristau@debian.org>
This commit is contained in:
Keith Packard 2017-07-27 10:08:32 -07:00 committed by Julien Cristau
parent eaf1f72ed8
commit 94f11ca5cf

View File

@ -47,23 +47,27 @@
/***====================================================================***/ /***====================================================================***/
#define BUFFER_SIZE 512 #define NUM_BUFFER 8
static struct textBuffer {
static char textBuffer[BUFFER_SIZE]; int size;
static int tbNext = 0; char *buffer;
} textBuffer[NUM_BUFFER];
static int textBufferIndex;
static char * static char *
tbGetBuffer(unsigned size) tbGetBuffer(unsigned size)
{ {
char *rtrn; struct textBuffer *tb;
if (size >= BUFFER_SIZE) tb = &textBuffer[textBufferIndex];
return NULL; textBufferIndex = (textBufferIndex + 1) % NUM_BUFFER;
if ((BUFFER_SIZE - tbNext) <= size)
tbNext = 0; if (size > tb->size) {
rtrn = &textBuffer[tbNext]; free(tb->buffer);
tbNext += size; tb->buffer = xnfalloc(size);
return rtrn; tb->size = size;
}
return tb->buffer;
} }
/***====================================================================***/ /***====================================================================***/
@ -79,8 +83,6 @@ XkbAtomText(Atom atm, unsigned format)
int len; int len;
len = strlen(atmstr) + 1; len = strlen(atmstr) + 1;
if (len > BUFFER_SIZE)
len = BUFFER_SIZE - 2;
rtrn = tbGetBuffer(len); rtrn = tbGetBuffer(len);
strlcpy(rtrn, atmstr, len); strlcpy(rtrn, atmstr, len);
} }
@ -128,8 +130,6 @@ XkbVModIndexText(XkbDescPtr xkb, unsigned ndx, unsigned format)
len = strlen(tmp) + 1; len = strlen(tmp) + 1;
if (format == XkbCFile) if (format == XkbCFile)
len += 4; len += 4;
if (len >= BUFFER_SIZE)
len = BUFFER_SIZE - 1;
rtrn = tbGetBuffer(len); rtrn = tbGetBuffer(len);
if (format == XkbCFile) { if (format == XkbCFile) {
strcpy(rtrn, "vmod_"); strcpy(rtrn, "vmod_");
@ -140,6 +140,8 @@ XkbVModIndexText(XkbDescPtr xkb, unsigned ndx, unsigned format)
return rtrn; return rtrn;
} }
#define VMOD_BUFFER_SIZE 512
char * char *
XkbVModMaskText(XkbDescPtr xkb, XkbVModMaskText(XkbDescPtr xkb,
unsigned modMask, unsigned mask, unsigned format) unsigned modMask, unsigned mask, unsigned format)
@ -147,7 +149,7 @@ XkbVModMaskText(XkbDescPtr xkb,
register int i, bit; register int i, bit;
int len; int len;
char *mm, *rtrn; char *mm, *rtrn;
char *str, buf[BUFFER_SIZE]; char *str, buf[VMOD_BUFFER_SIZE];
if ((modMask == 0) && (mask == 0)) { if ((modMask == 0) && (mask == 0)) {
rtrn = tbGetBuffer(5); rtrn = tbGetBuffer(5);
@ -173,7 +175,7 @@ XkbVModMaskText(XkbDescPtr xkb,
len = strlen(tmp) + 1 + (str == buf ? 0 : 1); len = strlen(tmp) + 1 + (str == buf ? 0 : 1);
if (format == XkbCFile) if (format == XkbCFile)
len += 4; len += 4;
if ((str - (buf + len)) <= BUFFER_SIZE) { if ((str - (buf + len)) <= VMOD_BUFFER_SIZE) {
if (str != buf) { if (str != buf) {
if (format == XkbCFile) if (format == XkbCFile)
*str++ = '|'; *str++ = '|';
@ -199,8 +201,6 @@ XkbVModMaskText(XkbDescPtr xkb,
len = 0; len = 0;
if (str) if (str)
len += strlen(str) + (mm == NULL ? 0 : 1); len += strlen(str) + (mm == NULL ? 0 : 1);
if (len >= BUFFER_SIZE)
len = BUFFER_SIZE - 1;
rtrn = tbGetBuffer(len + 1); rtrn = tbGetBuffer(len + 1);
rtrn[0] = '\0'; rtrn[0] = '\0';