From a3c0591d4a78563dc189047d043c71fba380e0ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Exp=C3=B3sito?= Date: Wed, 11 Oct 2023 13:04:16 +0200 Subject: [PATCH] Fixes for CVE-2023-43788 and CVE-2023-43789 Includes hardening for CVE-2023-43786 and CVE-2023-43787. Check X.Org Security Advisory [1] for more information. [1] https://lists.x.org/archives/xorg-announce/2023-October/003424.html Resolves: https://issues.redhat.com/browse/RHEL-12414 --- ...-43786-stack-exhaustion-in-XPutImage.patch | 284 ++++++++++++++++++ ...3787-integer-overflow-in-XCreateImag.patch | 35 +++ ...88-Out-of-bounds-read-in-XpmCreateXp.patch | 32 ++ ...89-Out-of-bounds-read-on-XPM-with-co.patch | 36 +++ libXpm.spec | 22 +- 5 files changed, 408 insertions(+), 1 deletion(-) create mode 100644 0001-Avoid-CVE-2023-43786-stack-exhaustion-in-XPutImage.patch create mode 100644 0001-Avoid-CVE-2023-43787-integer-overflow-in-XCreateImag.patch create mode 100644 0001-Fix-CVE-2023-43788-Out-of-bounds-read-in-XpmCreateXp.patch create mode 100644 0001-Fix-CVE-2023-43789-Out-of-bounds-read-on-XPM-with-co.patch diff --git a/0001-Avoid-CVE-2023-43786-stack-exhaustion-in-XPutImage.patch b/0001-Avoid-CVE-2023-43786-stack-exhaustion-in-XPutImage.patch new file mode 100644 index 0000000..4c8e17d --- /dev/null +++ b/0001-Avoid-CVE-2023-43786-stack-exhaustion-in-XPutImage.patch @@ -0,0 +1,284 @@ +From 84fb14574c039f19ad7face87eb9acc31a50701c Mon Sep 17 00:00:00 2001 +From: Alan Coopersmith +Date: Wed, 6 Sep 2023 17:34:33 -0700 +Subject: [PATCH] Avoid CVE-2023-43786: stack exhaustion in XPutImage() + +This doesn't fix the CVE - that has to happen in libX11, this +just tries to avoid triggering it from libXpm, and saves time +in not pretending we can successfully create an X11 pixmap with +dimensions larger than the unsigned 16-bit integers used in the +X11 protocol for the dimensions. + +Reported by Yair Mizrahi of the JFrog Vulnerability Research team + +Signed-off-by: Alan Coopersmith +--- + src/CrPFrBuf.c | 28 +++++++++++++++++++++++----- + src/CrPFrDat.c | 31 +++++++++++++++++++++++-------- + src/CrPFrI.c | 10 +++++++++- + src/RdFToP.c | 28 +++++++++++++++++++++++----- + src/XpmI.h | 2 +- + src/create.c | 28 +++++++++++++++++++++++----- + 6 files changed, 102 insertions(+), 25 deletions(-) + +diff --git a/src/CrPFrBuf.c b/src/CrPFrBuf.c +index 2c28a41..e9e2243 100644 +--- a/src/CrPFrBuf.c ++++ b/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/src/CrPFrDat.c b/src/CrPFrDat.c +index b65771d..8622663 100644 +--- a/src/CrPFrDat.c ++++ b/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/src/CrPFrI.c b/src/CrPFrI.c +index 8f6f4aa..f6688c5 100644 +--- a/src/CrPFrI.c ++++ b/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/src/RdFToP.c b/src/RdFToP.c +index f829757..2c3e7f9 100644 +--- a/src/RdFToP.c ++++ b/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/src/XpmI.h b/src/XpmI.h +index ab7a680..6691693 100644 +--- a/src/XpmI.h ++++ b/src/XpmI.h +@@ -195,7 +195,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/src/create.c b/src/create.c +index 4921c7d..ec562b2 100644 +--- a/src/create.c ++++ b/src/create.c +@@ -1652,7 +1652,7 @@ XpmCreatePixmapFromXpmImage( + Pixmap *shapemask_return, + XpmAttributes *attributes) + { +- XImage *ximage, *shapeimage; ++ XImage *ximage = NULL, *shapeimage = NULL; + int ErrorStatus; + + /* initialize return values */ +@@ -1668,16 +1668,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); + } +-- +2.41.0 + diff --git a/0001-Avoid-CVE-2023-43787-integer-overflow-in-XCreateImag.patch b/0001-Avoid-CVE-2023-43787-integer-overflow-in-XCreateImag.patch new file mode 100644 index 0000000..f744b30 --- /dev/null +++ b/0001-Avoid-CVE-2023-43787-integer-overflow-in-XCreateImag.patch @@ -0,0 +1,35 @@ +From 91f887b41bf75648df725a4ed3be036da02e911e Mon Sep 17 00:00:00 2001 +From: Yair Mizrahi +Date: Thu, 7 Sep 2023 16:59:07 -0700 +Subject: [PATCH] Avoid CVE-2023-43787 (integer overflow in XCreateImage) + +This doesn't fix the CVE - that has to happen in libX11, this +just tries to avoid triggering it from libXpm, and saves time +in not pretending we can successfully create an X Image for +which the width * depth would overflow the signed int used to +store the bytes_per_line value. + +Signed-off-by: Alan Coopersmith +--- + src/create.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/src/create.c b/src/create.c +index ec562b2..b8c80d2 100644 +--- a/src/create.c ++++ b/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); +-- +2.41.0 + diff --git a/0001-Fix-CVE-2023-43788-Out-of-bounds-read-in-XpmCreateXp.patch b/0001-Fix-CVE-2023-43788-Out-of-bounds-read-in-XpmCreateXp.patch new file mode 100644 index 0000000..a2d039b --- /dev/null +++ b/0001-Fix-CVE-2023-43788-Out-of-bounds-read-in-XpmCreateXp.patch @@ -0,0 +1,32 @@ +From 2fa554b01ef6079a9b35df9332bdc4f139ed67e0 Mon Sep 17 00:00:00 2001 +From: Alan Coopersmith +Date: Sat, 29 Apr 2023 17:50:39 -0700 +Subject: [PATCH] Fix CVE-2023-43788: Out of bounds read in + XpmCreateXpmImageFromBuffer + +When the test case for CVE-2022-46285 was run with the Address Sanitizer +enabled, it found an out-of-bounds read in ParseComment() when reading +from a memory buffer instead of a file, as it continued to look for the +closing comment marker past the end of the buffer. + +Signed-off-by: Alan Coopersmith +--- + src/data.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/data.c b/src/data.c +index 7524e65..0b0f1f3 100644 +--- a/src/data.c ++++ b/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--; +-- +2.41.0 + diff --git a/0001-Fix-CVE-2023-43789-Out-of-bounds-read-on-XPM-with-co.patch b/0001-Fix-CVE-2023-43789-Out-of-bounds-read-on-XPM-with-co.patch new file mode 100644 index 0000000..789c423 --- /dev/null +++ b/0001-Fix-CVE-2023-43789-Out-of-bounds-read-on-XPM-with-co.patch @@ -0,0 +1,36 @@ +From 7e21cb63b9a1ca760a06cc4cd9b19bbc3fcd8f51 Mon Sep 17 00:00:00 2001 +From: Alan Coopersmith +Date: Sat, 29 Apr 2023 18:30:34 -0700 +Subject: [PATCH] Fix CVE-2023-43789: Out of bounds read on XPM with corrupted + colormap + +Found with clang's libfuzzer + +Signed-off-by: Alan Coopersmith +--- + src/data.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/data.c b/src/data.c +index 0b0f1f3..6e87455 100644 +--- a/src/data.c ++++ b/src/data.c +@@ -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 { +-- +2.41.0 + diff --git a/libXpm.spec b/libXpm.spec index 5f88dab..f9ed4ff 100644 --- a/libXpm.spec +++ b/libXpm.spec @@ -1,7 +1,7 @@ Summary: X.Org X11 libXpm runtime library Name: libXpm Version: 3.5.13 -Release: 8%{?dist} +Release: 9%{?dist} License: MIT URL: http://www.x.org @@ -22,6 +22,14 @@ Patch0003: 0003-Prevent-a-double-free-in-the-error-code-path.patch Patch0004: 0004-configure-add-disable-open-zfile-instead-of-requirin.patch Patch0005: 0005-Fix-CVE-2022-4883-compression-commands-depend-on-PAT.patch Patch0006: 0006-Use-gzip-d-instead-of-gunzip.patch +# CVE-2023-43788 +Patch0007: 0001-Fix-CVE-2023-43788-Out-of-bounds-read-in-XpmCreateXp.patch +# CVE-2023-43789 +Patch0008: 0001-Fix-CVE-2023-43789-Out-of-bounds-read-on-XPM-with-co.patch +# CVE-2023-43786 +Patch0009: 0001-Avoid-CVE-2023-43786-stack-exhaustion-in-XPutImage.patch +# CVE-2023-43787 +Patch0010: 0001-Avoid-CVE-2023-43787-integer-overflow-in-XCreateImag.patch %description X.Org X11 libXpm runtime library @@ -42,6 +50,10 @@ X.Org X11 libXpm development package %patch0004 -p1 %patch0005 -p1 %patch0006 -p1 +%patch0007 -p1 +%patch0008 -p1 +%patch0009 -p1 +%patch0010 -p1 %build autoreconf -v --install --force @@ -75,6 +87,14 @@ rm -f $RPM_BUILD_ROOT%{_libdir}/*.la #%{_mandir}/man1/*.1x* %changelog +* Wed Oct 11 2023 José Expósito - 3.5.13-9 +- CVE-2023-43786 libX11: stack exhaustion from infinite recursion + in PutSubImage() +- CVE-2023-43787 libX11: integer overflow in XCreateImage() leading to + a heap overflow +- CVE-2023-43788 libXpm: out of bounds read in XpmCreateXpmImageFromBuffer() +- CVE-2023-43789 libXpm: out of bounds read on XPM with corrupted colormap + * Mon Jan 16 2023 Peter Hutterer - 3.5.13-8 - Fix CVE-2022-46285: infinite loop on unclosed comments (#2160230) - Fix CVE-2022-44617: runaway loop with width of 0 (#2160232)