configure.ac | 2 +- src/CrDatFrI.c | 34 +++++++++++++++++++++++++--------- src/RdFToBuf.c | 4 ++++ src/WrFFrBuf.c | 2 +- src/create.c | 11 ++++++----- src/parse.c | 40 ++++++++++++++++++++++++++++++++-------- 6 files changed, 69 insertions(+), 24 deletions(-)
New commits: commit 1fab5e81fd761f628fb68d22934615536dbd0220 Author: Matthieu Herrb <[email protected]> Date: Mon Dec 12 23:09:52 2016 +0100 libXpm 3.5.12 Signed-off-by: Matthieu Herrb <[email protected]> diff --git a/configure.ac b/configure.ac index 46e2a27..2feb9ff 100644 --- a/configure.ac +++ b/configure.ac @@ -1,7 +1,7 @@ # Initialize Autoconf AC_PREREQ([2.60]) -AC_INIT([libXpm], [3.5.11], +AC_INIT([libXpm], [3.5.12], [https://bugs.freedesktop.org/enter_bug.cgi?product=xorg], [libXpm]) AC_CONFIG_SRCDIR([Makefile.am]) AC_CONFIG_HEADERS([config.h]) commit 8b3024e6871ce50b34bf2dff924774bd654703bc Author: Tobias Stoeckmann <[email protected]> Date: Sun Dec 11 13:50:05 2016 +0100 Handle size_t in file/buffer length The values of file sizes and buffer sizes can exceed current limits. Therefore, use proper variable types for these operations. Signed-off-by: Matthieu Herrb <[email protected]> Reviewed-by: Matthieu Herrb <[email protected]> diff --git a/src/RdFToBuf.c b/src/RdFToBuf.c index 7f8ebee..69e3347 100644 --- a/src/RdFToBuf.c +++ b/src/RdFToBuf.c @@ -89,6 +89,10 @@ XpmReadFileToBuffer( return XpmOpenFailed; } len = stats.st_size; + if (len < 0 || len >= SIZE_MAX) { + close(fd); + return XpmOpenFailed; + } ptr = (char *) XpmMalloc(len + 1); if (!ptr) { fclose(fp); diff --git a/src/WrFFrBuf.c b/src/WrFFrBuf.c index b80aa62..0e57cc8 100644 --- a/src/WrFFrBuf.c +++ b/src/WrFFrBuf.c @@ -44,7 +44,7 @@ XpmWriteFileFromBuffer( const char *filename, char *buffer) { - int fcheck, len; + size_t fcheck, len; FILE *fp = fopen(filename, "w"); if (!fp) commit d1167418f0fd02a27f617ec5afd6db053afbe185 Author: Tobias Stoeckmann <[email protected]> Date: Thu Dec 8 17:07:55 2016 +0100 Avoid OOB write when handling malicious XPM files. libXpm uses unsigned int to store sizes, which fits size_t on 32 bit systems, but leads to issues on 64 bit systems. On 64 bit systems, it is possible to overflow 32 bit integers while parsing XPM extensions in a file. At first, it looks like a rather unimportant detail, because nobody will seriously open a 4 GB file. But unfortunately XPM has support for gzip compression out of the box. An attacker can therefore craft a compressed file which is merely 4 MB in size, which makes an attack much for feasable. Signed-off-by: Matthieu Herrb <[email protected]> Reviewed-by: Matthieu Herrb <[email protected]> diff --git a/src/CrDatFrI.c b/src/CrDatFrI.c index 0dacf51..6735bfc 100644 --- a/src/CrDatFrI.c +++ b/src/CrDatFrI.c @@ -48,7 +48,7 @@ LFUNC(CreatePixels, void, (char **dataptr, unsigned int data_size, unsigned int height, unsigned int cpp, unsigned int *pixels, XpmColor *colors)); -LFUNC(CountExtensions, void, (XpmExtension *ext, unsigned int num, +LFUNC(CountExtensions, int, (XpmExtension *ext, unsigned int num, unsigned int *ext_size, unsigned int *ext_nlines)); @@ -122,8 +122,9 @@ XpmCreateDataFromXpmImage( /* compute the number of extensions lines and size */ if (extensions) - CountExtensions(info->extensions, info->nextensions, - &ext_size, &ext_nlines); + if (CountExtensions(info->extensions, info->nextensions, + &ext_size, &ext_nlines)) + return(XpmNoMemory); /* * alloc a temporary array of char pointer for the header section which @@ -187,7 +188,8 @@ XpmCreateDataFromXpmImage( if(offset <= image->width || offset <= image->cpp) RETURN(XpmNoMemory); - if( (image->height + ext_nlines) >= UINT_MAX / sizeof(char *)) + if (image->height > UINT_MAX - ext_nlines || + image->height + ext_nlines >= UINT_MAX / sizeof(char *)) RETURN(XpmNoMemory); data_size = (image->height + ext_nlines) * sizeof(char *); @@ -196,7 +198,8 @@ XpmCreateDataFromXpmImage( RETURN(XpmNoMemory); data_size += image->height * offset; - if( (header_size + ext_size) >= (UINT_MAX - data_size) ) + if (header_size > UINT_MAX - ext_size || + header_size + ext_size >= (UINT_MAX - data_size) ) RETURN(XpmNoMemory); data_size += header_size + ext_size; @@ -343,13 +346,14 @@ CreatePixels( *s = '\0'; } -static void +static int CountExtensions( XpmExtension *ext, unsigned int num, unsigned int *ext_size, unsigned int *ext_nlines) { + size_t len; unsigned int x, y, a, size, nlines; char **line; @@ -357,16 +361,28 @@ CountExtensions( nlines = 0; for (x = 0; x < num; x++, ext++) { /* 1 for the name */ + if (ext->nlines == UINT_MAX || nlines > UINT_MAX - ext->nlines - 1) + return (1); nlines += ext->nlines + 1; /* 8 = 7 (for "XPMEXT ") + 1 (for 0) */ - size += strlen(ext->name) + 8; + len = strlen(ext->name) + 8; + if (len > UINT_MAX - size) + return (1); + size += len; a = ext->nlines; - for (y = 0, line = ext->lines; y < a; y++, line++) - size += strlen(*line) + 1; + for (y = 0, line = ext->lines; y < a; y++, line++) { + len = strlen(*line) + 1; + if (len > UINT_MAX - size) + return (1); + size += len; + } } + if (size > UINT_MAX - 10 || nlines > UINT_MAX - 1) + return (1); /* 10 and 1 are for the ending "XPMENDEXT" */ *ext_size = size + 10; *ext_nlines = nlines + 1; + return (0); } static void commit 1ec33006a9e4214b390045b820464e24297dc6c0 Author: Tobias Stoeckmann <[email protected]> Date: Tue Dec 6 22:34:33 2016 +0100 Gracefully handle EOF while parsing files. libXpm does not properly handle EOF conditions when xpmGetC is called multiple times in a row to construct a string. Instead of checking its return value for EOF, the result is automatically casted into a char and attached to a string. By carefully crafting the color table in an XPM file, it is possible to send a libXpm program like gimp into a very long lasting loop and massive memory allocations. Otherwise no memory issues arise, therefore this is just a purely functional patch to dismiss invalid input. Signed-off-by: Matthieu Herrb <[email protected]> Reviewed-by: Matthieu Herrb <[email protected]> diff --git a/src/parse.c b/src/parse.c index ff23a47..c19209c 100644 --- a/src/parse.c +++ b/src/parse.c @@ -234,8 +234,14 @@ xpmParseColors( xpmFreeColorTable(colorTable, ncolors); return (XpmNoMemory); } - for (b = 0, s = color->string; b < cpp; b++, s++) - *s = xpmGetC(data); + for (b = 0, s = color->string; b < cpp; b++, s++) { + int c = xpmGetC(data); + if (c < 0) { + xpmFreeColorTable(colorTable, ncolors); + return (XpmFileInvalid); + } + *s = (char) c; + } *s = '\0'; /* @@ -322,8 +328,14 @@ xpmParseColors( xpmFreeColorTable(colorTable, ncolors); return (XpmNoMemory); } - for (b = 0, s = color->string; b < cpp; b++, s++) - *s = xpmGetC(data); + for (b = 0, s = color->string; b < cpp; b++, s++) { + int c = xpmGetC(data); + if (c < 0) { + xpmFreeColorTable(colorTable, ncolors); + return (XpmFileInvalid); + } + *s = (char) c; + } *s = '\0'; /* @@ -505,8 +517,14 @@ do \ for (y = 0; y < height; y++) { xpmNextString(data); for (x = 0; x < width; x++, iptr++) { - for (a = 0, s = buf; a < cpp; a++, s++) - *s = xpmGetC(data); /* int assigned to char, not a problem here */ + for (a = 0, s = buf; a < cpp; a++, s++) { + int c = xpmGetC(data); + if (c < 0) { + XpmFree(iptr2); + return (XpmFileInvalid); + } + *s = (char) c; + } slot = xpmHashSlot(hashtable, buf); if (!*slot) { /* no color matches */ XpmFree(iptr2); @@ -519,8 +537,14 @@ do \ for (y = 0; y < height; y++) { xpmNextString(data); for (x = 0; x < width; x++, iptr++) { - for (a = 0, s = buf; a < cpp; a++, s++) - *s = xpmGetC(data); /* int assigned to char, not a problem here */ + for (a = 0, s = buf; a < cpp; a++, s++) { + int c = xpmGetC(data); + if (c < 0) { + XpmFree(iptr2); + return (XpmFileInvalid); + } + *s = (char) c; + } for (a = 0; a < ncolors; a++) if (!strcmp(colorTable[a].string, buf)) break; commit c46dedeba15edf7216d62633ed6daf40cd1f5bfd Author: Tobias Stoeckmann <[email protected]> Date: Tue Dec 6 22:31:53 2016 +0100 Fix out out boundary read on unknown colors libXpm is vulnerable to an out of boundary read if an XPM file contains a color with a symbolic name but without any default color value. A caller must set XpmColorSymbols and a color with a NULL name in the supplied XpmAttributes to XpmReadFileToImage (or other functions of this type) in order to trigger this issue. Signed-off-by: Matthieu Herrb <[email protected]> Reviewed-by: Matthieu Herrb <[email protected]> diff --git a/src/create.c b/src/create.c index d013da9..a750846 100644 --- a/src/create.c +++ b/src/create.c @@ -647,7 +647,8 @@ CreateColors( while (def_index <= 5 && defaults[def_index] == NULL) ++def_index; } - if (def_index >= 2 && defaults[def_index] != NULL && + if (def_index >= 2 && def_index <= 5 && + defaults[def_index] != NULL && !xpmstrcasecmp(symbol->value, defaults[def_index])) break; } commit 42ca8d956276bc00bec09e410d76daf053ae35f9 Author: Jörg Sonnenberger <[email protected]> Date: Wed Mar 19 09:26:37 2014 +0100 Fix abs() usage. For long arguments, use labs(). Reviewed-by: Matt Turner <[email protected]> Signed-off-by: Thomas Klausner <[email protected]> diff --git a/src/create.c b/src/create.c index 98678d8..d013da9 100644 --- a/src/create.c +++ b/src/create.c @@ -347,10 +347,10 @@ SetCloseColor( closenesses[i].cols_index = i; closenesses[i].closeness = - COLOR_FACTOR * (abs((long) col->red - (long) cols[i].red) - + abs((long) col->green - (long) cols[i].green) - + abs((long) col->blue - (long) cols[i].blue)) - + BRIGHTNESS_FACTOR * abs(((long) col->red + + COLOR_FACTOR * (labs((long) col->red - (long) cols[i].red) + + labs((long) col->green - (long) cols[i].green) + + labs((long) col->blue - (long) cols[i].blue)) + + BRIGHTNESS_FACTOR * labs(((long) col->red + (long) col->green + (long) col->blue) - ((long) cols[i].red +

