From e1ec829e63d75df7dd62d7c7d4532ee8c50cb1f9 Mon Sep 17 00:00:00 2001 From: purplerain Date: Wed, 4 Oct 2023 03:57:45 +0000 Subject: [PATCH] Fix several input validation errors in libX11 and libXpm. CVE-2023-43785 CVE-2023-43786 CVE-2023-43787 CVE-2023-43788 CVE-2023-43789 --- lib/libX11/src/CrPixmap.c | 11 +++++++++++ lib/libX11/src/ImUtil.c | 20 +++++++++++++++----- lib/libX11/src/PutImage.c | 10 ++++++++-- lib/libX11/src/xkb/XKBGetMap.c | 14 +++++++++----- lib/libXpm/src/CrPFrBuf.c | 28 +++++++++++++++++++++++----- lib/libXpm/src/CrPFrDat.c | 31 +++++++++++++++++++++++-------- lib/libXpm/src/CrPFrI.c | 10 +++++++++- lib/libXpm/src/RdFToP.c | 28 +++++++++++++++++++++++----- lib/libXpm/src/XpmI.h | 2 +- lib/libXpm/src/create.c | 33 ++++++++++++++++++++++++++++----- lib/libXpm/src/data.c | 6 +++--- 11 files changed, 153 insertions(+), 40 deletions(-) diff --git a/lib/libX11/src/CrPixmap.c b/lib/libX11/src/CrPixmap.c index cdf31207..3cb2ca6d 100644 --- a/lib/libX11/src/CrPixmap.c +++ b/lib/libX11/src/CrPixmap.c @@ -28,6 +28,7 @@ in this Software without prior written authorization from The Open Group. #include #endif #include "Xlibint.h" +#include #ifdef USE_DYNAMIC_XCURSOR void @@ -47,6 +48,16 @@ Pixmap XCreatePixmap ( Pixmap pid; register xCreatePixmapReq *req; + /* + * Force a BadValue X Error if the requested dimensions are larger + * than the X11 protocol has room for, since that's how callers expect + * to get notified of errors. + */ + if (width > USHRT_MAX) + width = 0; + if (height > USHRT_MAX) + height = 0; + LockDisplay(dpy); GetReq(CreatePixmap, req); req->drawable = d; diff --git a/lib/libX11/src/ImUtil.c b/lib/libX11/src/ImUtil.c index 36f08a03..fbfad33e 100644 --- a/lib/libX11/src/ImUtil.c +++ b/lib/libX11/src/ImUtil.c @@ -30,6 +30,7 @@ in this Software without prior written authorization from The Open Group. #include #include #include +#include #include "ImUtil.h" static int _XDestroyImage(XImage *); @@ -361,13 +362,22 @@ XImage *XCreateImage ( /* * compute per line accelerator. */ - { - if (format == ZPixmap) + if (format == ZPixmap) { + if ((INT_MAX / bits_per_pixel) < width) { + Xfree(image); + return NULL; + } + min_bytes_per_line = - ROUNDUP((bits_per_pixel * width), image->bitmap_pad); - else + ROUNDUP((bits_per_pixel * width), image->bitmap_pad); + } else { + if ((INT_MAX - offset) < width) { + Xfree(image); + return NULL; + } + min_bytes_per_line = - ROUNDUP((width + offset), image->bitmap_pad); + ROUNDUP((width + offset), image->bitmap_pad); } if (image_bytes_per_line == 0) { image->bytes_per_line = min_bytes_per_line; diff --git a/lib/libX11/src/PutImage.c b/lib/libX11/src/PutImage.c index 857ee916..ba411e36 100644 --- a/lib/libX11/src/PutImage.c +++ b/lib/libX11/src/PutImage.c @@ -30,6 +30,7 @@ in this Software without prior written authorization from The Open Group. #include "Xlibint.h" #include "Xutil.h" #include +#include #include "Cr.h" #include "ImUtil.h" #include "reallocarray.h" @@ -914,8 +915,9 @@ PutSubImage ( req_width, req_height - SubImageHeight, dest_bits_per_pixel, dest_scanline_pad); } else { - int SubImageWidth = (((Available << 3) / dest_scanline_pad) - * dest_scanline_pad) - left_pad; + int SubImageWidth = ((((Available << 3) / dest_scanline_pad) + * dest_scanline_pad) - left_pad) + / dest_bits_per_pixel; PutSubImage(dpy, d, gc, image, req_xoffset, req_yoffset, x, y, (unsigned int) SubImageWidth, 1, @@ -961,6 +963,10 @@ XPutImage ( height = image->height - req_yoffset; if ((width <= 0) || (height <= 0)) return 0; + if (width > USHRT_MAX) + width = USHRT_MAX; + if (height > USHRT_MAX) + height = USHRT_MAX; if ((image->bits_per_pixel == 1) || (image->format != ZPixmap)) { dest_bits_per_pixel = 1; diff --git a/lib/libX11/src/xkb/XKBGetMap.c b/lib/libX11/src/xkb/XKBGetMap.c index 2891d21e..31199e4a 100644 --- a/lib/libX11/src/xkb/XKBGetMap.c +++ b/lib/libX11/src/xkb/XKBGetMap.c @@ -182,7 +182,8 @@ _XkbReadKeySyms(XkbReadBufferPtr buf, XkbDescPtr xkb, xkbGetMapReply *rep) if (offset + newMap->nSyms >= map->size_syms) { register int sz; - sz = map->size_syms + 128; + sz = offset + newMap->nSyms; + sz = ((sz + (unsigned) 128) / 128) * 128; _XkbResizeArray(map->syms, map->size_syms, sz, KeySym); if (map->syms == NULL) { map->size_syms = 0; @@ -191,8 +192,9 @@ _XkbReadKeySyms(XkbReadBufferPtr buf, XkbDescPtr xkb, xkbGetMapReply *rep) map->size_syms = sz; } if (newMap->nSyms > 0) { - _XkbReadBufferCopyKeySyms(buf, (KeySym *) &map->syms[offset], - newMap->nSyms); + if (_XkbReadBufferCopyKeySyms(buf, (KeySym *) &map->syms[offset], + newMap->nSyms) == 0) + return BadLength; offset += newMap->nSyms; } else { @@ -222,8 +224,10 @@ _XkbReadKeySyms(XkbReadBufferPtr buf, XkbDescPtr xkb, xkbGetMapReply *rep) newSyms = XkbResizeKeySyms(xkb, i + rep->firstKeySym, tmp); if (newSyms == NULL) return BadAlloc; - if (newMap->nSyms > 0) - _XkbReadBufferCopyKeySyms(buf, newSyms, newMap->nSyms); + if (newMap->nSyms > 0) { + if (_XkbReadBufferCopyKeySyms(buf, newSyms, newMap->nSyms) == 0) + return BadLength; + } else newSyms[0] = NoSymbol; oldMap->kt_index[0] = newMap->ktIndex[0]; diff --git a/lib/libXpm/src/CrPFrBuf.c b/lib/libXpm/src/CrPFrBuf.c index 2c28a413..e9e22436 100644 --- a/lib/libXpm/src/CrPFrBuf.c +++ b/lib/libXpm/src/CrPFrBuf.c @@ -46,7 +46,7 @@ XpmCreatePixmapFromBuffer( Pixmap *shapemask_return, XpmAttributes *attributes) { - XImage *ximage, *shapeimage; + XImage *ximage = NULL, *shapeimage = NULL; int ErrorStatus; /* initialize return values */ @@ -63,16 +63,34 @@ XpmCreatePixmapFromBuffer( attributes); if (ErrorStatus < 0) /* fatal error */ - return (ErrorStatus); + goto cleanup; /* create the pixmaps and destroy images */ if (pixmap_return && ximage) { - xpmCreatePixmapFromImage(display, d, ximage, pixmap_return); - XDestroyImage(ximage); + ErrorStatus = + xpmCreatePixmapFromImage(display, d, ximage, pixmap_return); + if (ErrorStatus < 0) /* fatal error */ + goto cleanup; } if (shapemask_return && shapeimage) { - xpmCreatePixmapFromImage(display, d, shapeimage, shapemask_return); + ErrorStatus = + xpmCreatePixmapFromImage(display, d, shapeimage, shapemask_return); + } + + cleanup: + if (ximage != NULL) + XDestroyImage(ximage); + if (shapeimage != NULL) XDestroyImage(shapeimage); + if (ErrorStatus < 0) { + if (pixmap_return && *pixmap_return) { + XFreePixmap(display, *pixmap_return); + *pixmap_return = 0; + } + if (shapemask_return && *shapemask_return) { + XFreePixmap(display, *shapemask_return); + *shapemask_return = 0; + } } return (ErrorStatus); } diff --git a/lib/libXpm/src/CrPFrDat.c b/lib/libXpm/src/CrPFrDat.c index b65771d1..86226635 100644 --- a/lib/libXpm/src/CrPFrDat.c +++ b/lib/libXpm/src/CrPFrDat.c @@ -46,7 +46,7 @@ XpmCreatePixmapFromData( Pixmap *shapemask_return, XpmAttributes *attributes) { - XImage *ximage, *shapeimage; + XImage *ximage = NULL, *shapeimage = NULL; int ErrorStatus; /* initialize return values */ @@ -63,19 +63,34 @@ XpmCreatePixmapFromData( attributes); if (ErrorStatus != XpmSuccess) - return (ErrorStatus); - - if (ErrorStatus < 0) /* fatal error */ - return (ErrorStatus); + goto cleanup; /* create the pixmaps and destroy images */ if (pixmap_return && ximage) { - xpmCreatePixmapFromImage(display, d, ximage, pixmap_return); - XDestroyImage(ximage); + ErrorStatus = + xpmCreatePixmapFromImage(display, d, ximage, pixmap_return); + if (ErrorStatus < 0) /* fatal error */ + goto cleanup; } if (shapemask_return && shapeimage) { - xpmCreatePixmapFromImage(display, d, shapeimage, shapemask_return); + ErrorStatus = + xpmCreatePixmapFromImage(display, d, shapeimage, shapemask_return); + } + + cleanup: + if (ximage != NULL) + XDestroyImage(ximage); + if (shapeimage != NULL) XDestroyImage(shapeimage); + if (ErrorStatus < 0) { + if (pixmap_return && *pixmap_return) { + XFreePixmap(display, *pixmap_return); + *pixmap_return = 0; + } + if (shapemask_return && *shapemask_return) { + XFreePixmap(display, *shapemask_return); + *shapemask_return = 0; + } } return (ErrorStatus); } diff --git a/lib/libXpm/src/CrPFrI.c b/lib/libXpm/src/CrPFrI.c index 8f6f4aa4..f6688c5d 100644 --- a/lib/libXpm/src/CrPFrI.c +++ b/lib/libXpm/src/CrPFrI.c @@ -36,8 +36,9 @@ #include #endif #include "XpmI.h" +#include -void +int xpmCreatePixmapFromImage( Display *display, Drawable d, @@ -47,6 +48,11 @@ xpmCreatePixmapFromImage( GC gc; XGCValues values; + /* X Pixmaps are limited to unsigned 16-bit height/width */ + if ((ximage->width > UINT16_MAX) || (ximage->height > UINT16_MAX)) { + return XpmNoMemory; + } + *pixmap_return = XCreatePixmap(display, d, ximage->width, ximage->height, ximage->depth); /* set fg and bg in case we have an XYBitmap */ @@ -59,4 +65,6 @@ xpmCreatePixmapFromImage( ximage->width, ximage->height); XFreeGC(display, gc); + + return XpmSuccess; } diff --git a/lib/libXpm/src/RdFToP.c b/lib/libXpm/src/RdFToP.c index f8297578..2c3e7f98 100644 --- a/lib/libXpm/src/RdFToP.c +++ b/lib/libXpm/src/RdFToP.c @@ -46,7 +46,7 @@ XpmReadFileToPixmap( Pixmap *shapemask_return, XpmAttributes *attributes) { - XImage *ximage, *shapeimage; + XImage *ximage = NULL, *shapeimage = NULL; int ErrorStatus; /* initialize return values */ @@ -62,16 +62,34 @@ XpmReadFileToPixmap( attributes); if (ErrorStatus < 0) /* fatal error */ - return (ErrorStatus); + goto cleanup; /* create the pixmaps and destroy images */ if (pixmap_return && ximage) { - xpmCreatePixmapFromImage(display, d, ximage, pixmap_return); - XDestroyImage(ximage); + ErrorStatus = + xpmCreatePixmapFromImage(display, d, ximage, pixmap_return); + if (ErrorStatus < 0) /* fatal error */ + goto cleanup; } if (shapemask_return && shapeimage) { - xpmCreatePixmapFromImage(display, d, shapeimage, shapemask_return); + ErrorStatus = + xpmCreatePixmapFromImage(display, d, shapeimage, shapemask_return); + } + + cleanup: + if (ximage != NULL) + XDestroyImage(ximage); + if (shapeimage != NULL) XDestroyImage(shapeimage); + if (ErrorStatus < 0) { + if (pixmap_return && *pixmap_return) { + XFreePixmap(display, *pixmap_return); + *pixmap_return = 0; + } + if (shapemask_return && *shapemask_return) { + XFreePixmap(display, *shapemask_return); + *shapemask_return = 0; + } } return (ErrorStatus); } diff --git a/lib/libXpm/src/XpmI.h b/lib/libXpm/src/XpmI.h index 70da79e0..90e6a91f 100644 --- a/lib/libXpm/src/XpmI.h +++ b/lib/libXpm/src/XpmI.h @@ -188,7 +188,7 @@ FUNC(xpmSetAttributes, void, (XpmAttributes *attributes, XpmImage *image, XpmInfo *info)); #if !defined(FOR_MSW) && !defined(AMIGA) -FUNC(xpmCreatePixmapFromImage, void, (Display *display, Drawable d, +FUNC(xpmCreatePixmapFromImage, int, (Display *display, Drawable d, XImage *ximage, Pixmap *pixmap_return)); FUNC(xpmCreateImageFromPixmap, void, (Display *display, Pixmap pixmap, diff --git a/lib/libXpm/src/create.c b/lib/libXpm/src/create.c index 4921c7dd..b8c80d2d 100644 --- a/lib/libXpm/src/create.c +++ b/lib/libXpm/src/create.c @@ -997,6 +997,11 @@ CreateXImage( *image_return = NULL; return XpmNoMemory; } + if (width != 0 && (*image_return)->bits_per_pixel >= INT_MAX / width) { + XDestroyImage(*image_return); + *image_return = NULL; + return XpmNoMemory; + } /* now that bytes_per_line must have been set properly alloc data */ if((*image_return)->bytes_per_line == 0 || height == 0) { XDestroyImage(*image_return); @@ -1652,7 +1657,7 @@ XpmCreatePixmapFromXpmImage( Pixmap *shapemask_return, XpmAttributes *attributes) { - XImage *ximage, *shapeimage; + XImage *ximage = NULL, *shapeimage = NULL; int ErrorStatus; /* initialize return values */ @@ -1668,16 +1673,34 @@ XpmCreatePixmapFromXpmImage( &shapeimage : NULL), attributes); if (ErrorStatus < 0) - return (ErrorStatus); + goto cleanup; /* create the pixmaps and destroy images */ if (pixmap_return && ximage) { - xpmCreatePixmapFromImage(display, d, ximage, pixmap_return); - XDestroyImage(ximage); + ErrorStatus = + xpmCreatePixmapFromImage(display, d, ximage, pixmap_return); + if (ErrorStatus < 0) /* fatal error */ + goto cleanup; } if (shapemask_return && shapeimage) { - xpmCreatePixmapFromImage(display, d, shapeimage, shapemask_return); + ErrorStatus = + xpmCreatePixmapFromImage(display, d, shapeimage, shapemask_return); + } + + cleanup: + if (ximage != NULL) + XDestroyImage(ximage); + if (shapeimage != NULL) XDestroyImage(shapeimage); + if (ErrorStatus < 0) { + if (pixmap_return && *pixmap_return) { + XFreePixmap(display, *pixmap_return); + *pixmap_return = 0; + } + if (shapemask_return && *shapemask_return) { + XFreePixmap(display, *shapemask_return); + *shapemask_return = 0; + } } return (ErrorStatus); } diff --git a/lib/libXpm/src/data.c b/lib/libXpm/src/data.c index 7524e65e..6e87455e 100644 --- a/lib/libXpm/src/data.c +++ b/lib/libXpm/src/data.c @@ -108,7 +108,7 @@ ParseComment(xpmData *data) n++; s2++; } while (c == *s2 && *s2 != '\0' && c); - if (*s2 == '\0') { + if (*s2 == '\0' || c == '\0') { /* this is the end of the comment */ notend = 0; data->cptr--; @@ -259,13 +259,13 @@ xpmNextWord( int c; if (!data->type || data->type == XPMBUFFER) { - while (isspace(c = *data->cptr) && c != data->Eos) + while ((c = *data->cptr) && isspace(c) && (c != data->Eos)) data->cptr++; do { c = *data->cptr++; *buf++ = c; n++; - } while (!isspace(c) && c != data->Eos && n < buflen); + } while (c && !isspace(c) && (c != data->Eos) && (n < buflen)); n--; data->cptr--; } else {