Blame SOURCES/0005-Fix-CVE-2022-4883-compression-commands-depend-on-PAT.patch

2c1650
From cdbc3fa8edc5b42391a5f2bfe1a8f6099929acf7 Mon Sep 17 00:00:00 2001
2c1650
From: Alan Coopersmith <alan.coopersmith@oracle.com>
2c1650
Date: Fri, 6 Jan 2023 12:50:48 -0800
2c1650
Subject: [PATCH libXpm 5/6] Fix CVE-2022-4883: compression commands depend on
2c1650
 $PATH
2c1650
2c1650
By default, on all platforms except MinGW, libXpm will detect if a
2c1650
filename ends in .Z or .gz, and will when reading such a file fork off
2c1650
an uncompress or gunzip command to read from via a pipe, and when
2c1650
writing such a file will fork off a compress or gzip command to write
2c1650
to via a pipe.
2c1650
2c1650
In libXpm 3.5.14 or older these are run via execlp(), relying on $PATH
2c1650
to find the commands.  If libXpm is called from a program running with
2c1650
raised privileges, such as via setuid, then a malicious user could set
2c1650
$PATH to include programs of their choosing to be run with those
2c1650
privileges.
2c1650
2c1650
Signed-off-by: Alan Coopersmith <alan.coopersmith@oracle.com>
2c1650
---
2c1650
 README.md    | 12 ++++++++++++
2c1650
 configure.ac | 14 ++++++++++++++
2c1650
 src/RdFToI.c | 17 ++++++++++++++---
2c1650
 src/WrFFrI.c |  4 ++--
2c1650
 4 files changed, 42 insertions(+), 5 deletions(-)
2c1650
2c1650
diff --git a/README.md b/README.md
2c1650
index f3f4c93..0b1c886 100644
2c1650
--- a/README.md
2c1650
+++ b/README.md
2c1650
@@ -31,3 +31,15 @@ if it can't find the file it was asked to open.  It relies on the
2c1650
 --enable-open-zfile feature to open the file, and is enabled by default
2c1650
 when --enable-open-zfile is enabled, and can be disabled by passing the
2c1650
 --disable-stat-zfile flag to the configure script.
2c1650
+
2c1650
+All of these commands will be executed with whatever userid & privileges the
2c1650
+function is called with, relying on the caller to ensure the correct euid,
2c1650
+egid, etc. are set before calling.
2c1650
+
2c1650
+To reduce risk, the paths to these commands are now set at configure time to
2c1650
+the first version found in the PATH used to run configure, and do not depend
2c1650
+on the PATH environment variable set at runtime.
2c1650
+
2c1650
+To specify paths to be used for these commands instead of searching $PATH, pass
2c1650
+the XPM_PATH_COMPRESS, XPM_PATH_UNCOMPRESS, XPM_PATH_GZIP, and XPM_PATH_GUNZIP
2c1650
+variables to the configure command.
2c1650
diff --git a/configure.ac b/configure.ac
2c1650
index 85e2c73..4fc370d 100644
2c1650
--- a/configure.ac
2c1650
+++ b/configure.ac
2c1650
@@ -49,6 +49,14 @@ if test "x$USE_GETTEXT" = "xyes" ; then
2c1650
 fi
2c1650
 AM_CONDITIONAL(USE_GETTEXT, test "x$USE_GETTEXT" = "xyes")
2c1650
 
2c1650
+dnl Helper macro to find absolute path to program and add a #define for it
2c1650
+AC_DEFUN([XPM_PATH_PROG],[
2c1650
+AC_PATH_PROG([$1], [$2], [])
2c1650
+AS_IF([test "x$$1" = "x"],
2c1650
+      [AC_MSG_ERROR([$2 not found, set $1 or use --disable-stat-zfile])])
2c1650
+AC_DEFINE_UNQUOTED([$1], ["$$1"], [Path to $2])
2c1650
+]) dnl End of AC_DEFUN([XPM_PATH_PROG]...
2c1650
+
2c1650
 # Optional feature: When a filename ending in .Z or .gz is requested,
2c1650
 # open a pipe to a newly forked compress/uncompress/gzip/gunzip command to
2c1650
 # handle it.
2c1650
@@ -64,6 +72,12 @@ AC_ARG_ENABLE(open-zfile,
2c1650
 AC_MSG_RESULT([$OPEN_ZFILE])
2c1650
 if test x$OPEN_ZFILE = xno ; then
2c1650
         AC_DEFINE(NO_ZPIPE, 1, [Define to 1 to disable decompression via pipes])
2c1650
+else
2c1650
+        XPM_PATH_PROG([XPM_PATH_COMPRESS], [compress])
2c1650
+        XPM_PATH_PROG([XPM_PATH_UNCOMPRESS], [uncompress])
2c1650
+        XPM_PATH_PROG([XPM_PATH_GZIP], [gzip])
2c1650
+        XPM_PATH_PROG([XPM_PATH_GUNZIP], [gunzip])
2c1650
+        AC_CHECK_FUNCS([closefrom close_range], [break])
2c1650
 fi
2c1650
 
2c1650
 # Optional feature: When ___.xpm is requested, also look for ___.xpm.Z & .gz
2c1650
diff --git a/src/RdFToI.c b/src/RdFToI.c
2c1650
index bd09611..a91d337 100644
2c1650
--- a/src/RdFToI.c
2c1650
+++ b/src/RdFToI.c
2c1650
@@ -43,6 +43,7 @@
2c1650
 #include <errno.h>
2c1650
 #include <sys/types.h>
2c1650
 #include <sys/wait.h>
2c1650
+#include <unistd.h>
2c1650
 #else
2c1650
 #ifdef FOR_MSW
2c1650
 #include <fcntl.h>
2c1650
@@ -161,7 +162,17 @@ xpmPipeThrough(
2c1650
 	    goto err;
2c1650
 	if ( 0 == pid )
2c1650
 	{
2c1650
-	    execlp(cmd, cmd, arg1, (char *)NULL);
2c1650
+#ifdef HAVE_CLOSEFROM
2c1650
+	    closefrom(3);
2c1650
+#elif defined(HAVE_CLOSE_RANGE)
2c1650
+# ifdef CLOSE_RANGE_UNSHARE
2c1650
+#  define close_range_flags CLOSE_RANGE_UNSHARE
2c1650
+# else
2c1650
+#  define close_range_flags 0
2c1650
+#endif
2c1650
+	    close_range(3, ~0U, close_range_flags);
2c1650
+#endif
2c1650
+	    execl(cmd, cmd, arg1, (char *)NULL);
2c1650
 	    perror(cmd);
2c1650
 	    goto err;
2c1650
 	}
2c1650
@@ -235,12 +246,12 @@ OpenReadFile(
2c1650
 	if ( ext && !strcmp(ext, ".Z") )
2c1650
 	{
2c1650
 	    mdata->type = XPMPIPE;
2c1650
-	    mdata->stream.file = xpmPipeThrough(fd, "uncompress", "-c", "r");
2c1650
+	    mdata->stream.file = xpmPipeThrough(fd, XPM_PATH_UNCOMPRESS, "-c", "r");
2c1650
 	}
2c1650
 	else if ( ext && !strcmp(ext, ".gz") )
2c1650
 	{
2c1650
 	    mdata->type = XPMPIPE;
2c1650
-	    mdata->stream.file = xpmPipeThrough(fd, "gunzip", "-qc", "r");
2c1650
+	    mdata->stream.file = xpmPipeThrough(fd, XPM_PATH_GUNZIP, "-qc", "r");
2c1650
 	}
2c1650
 	else
2c1650
 #endif /* z-files */
2c1650
diff --git a/src/WrFFrI.c b/src/WrFFrI.c
2c1650
index 328c987..d59098f 100644
2c1650
--- a/src/WrFFrI.c
2c1650
+++ b/src/WrFFrI.c
2c1650
@@ -342,10 +342,10 @@ OpenWriteFile(
2c1650
 #ifndef NO_ZPIPE
2c1650
 	len = strlen(filename);
2c1650
 	if (len > 2 && !strcmp(".Z", filename + (len - 2))) {
2c1650
-	    mdata->stream.file = xpmPipeThrough(fd, "compress", NULL, "w");
2c1650
+	    mdata->stream.file = xpmPipeThrough(fd, XPM_PATH_COMPRESS, NULL, "w");
2c1650
 	    mdata->type = XPMPIPE;
2c1650
 	} else if (len > 3 && !strcmp(".gz", filename + (len - 3))) {
2c1650
-	    mdata->stream.file = xpmPipeThrough(fd, "gzip", "-q", "w");
2c1650
+	    mdata->stream.file = xpmPipeThrough(fd, XPM_PATH_GZIP, "-q", "w");
2c1650
 	    mdata->type = XPMPIPE;
2c1650
 	} else
2c1650
 #endif
2c1650
-- 
2c1650
2.39.0
2c1650