From 3446b4dbf970223f16f8ea294b723fc2e86bc4c4 Mon Sep 17 00:00:00 2001
From: Alan Coopersmith <alan.coopersmith@oracle.com>
Date: Wed, 6 Sep 2023 17:34:33 -0700
Subject: [PATCH libXpm 5/7] 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 <alan.coopersmith@oracle.com>
---
 src/CrPFrBuf.c | 28 +++++++++++++++++++++++-----
 src/CrPFrDat.c | 31 +++++++++++++++++++++++--------
 src/CrPFrI.c   |  9 ++++++++-
 src/RdFToP.c   | 28 +++++++++++++++++++++++-----
 src/XpmI.h     |  2 +-
 src/create.c   | 28 +++++++++++++++++++++++-----
 6 files changed, 101 insertions(+), 25 deletions(-)

Index: libXpm-3.5.11/src/CrPFrBuf.c
===================================================================
--- libXpm-3.5.11.orig/src/CrPFrBuf.c
+++ libXpm-3.5.11/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);
 }
Index: libXpm-3.5.11/src/CrPFrDat.c
===================================================================
--- libXpm-3.5.11.orig/src/CrPFrDat.c
+++ libXpm-3.5.11/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);
 }
Index: libXpm-3.5.11/src/CrPFrI.c
===================================================================
--- libXpm-3.5.11.orig/src/CrPFrI.c
+++ libXpm-3.5.11/src/CrPFrI.c
@@ -35,9 +35,10 @@
 #ifdef HAVE_CONFIG_H
 #include <config.h>
 #endif
+#include <stdint.h>
 #include "XpmI.h"
 
-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;
 }
Index: libXpm-3.5.11/src/RdFToP.c
===================================================================
--- libXpm-3.5.11.orig/src/RdFToP.c
+++ libXpm-3.5.11/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);
 }
Index: libXpm-3.5.11/src/XpmI.h
===================================================================
--- libXpm-3.5.11.orig/src/XpmI.h
+++ libXpm-3.5.11/src/XpmI.h
@@ -188,7 +188,7 @@ FUNC(xpmSetAttributes, void, (XpmAttribu
 			      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,
Index: libXpm-3.5.11/src/create.c
===================================================================
--- libXpm-3.5.11.orig/src/create.c
+++ libXpm-3.5.11/src/create.c
@@ -1651,7 +1651,7 @@ XpmCreatePixmapFromXpmImage(
     Pixmap		*shapemask_return,
     XpmAttributes	*attributes)
 {
-    XImage *ximage, *shapeimage;
+    XImage *ximage = NULL, *shapeimage = NULL;
     int ErrorStatus;
 
     /* initialize return values */
@@ -1667,16 +1667,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);
 }
