Blob Blame Raw
From 212e2fcac834dec25a4fa0f4fd4652bfd19cdeea Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20P=C3=ADsa=C5=99?= <ppisar@redhat.com>
Date: Fri, 4 Jan 2013 13:35:27 +0100
Subject: [PATCH 2/2] Fix CVE-2012-6090

Upstream fix ported to 5.10.2:

From b2c88972e7515ada025e97e7d3ce3e34f81cf33e Mon Sep 17 00:00:00 2001
From: Jan Wielemaker <J.Wielemaker@cs.vu.nl>
Date: Sun, 16 Dec 2012 17:29:37 +0100
Subject: [PATCH] SECURITY: Possible buffer overflows when expanding
 file-names with long paths.  Affects expand_file_name/2.

Can lead to crashes (DoS attacks) and possibly execution of arbitrary
code if an attacker can control the names of the files searched for,
e.g., if expand_file_name/2 is used in a directory to which an attacker
can upload files for which he can control the name.
---
 src/pl-glob.c | 46 ++++++++++++++++++++++++++++------------------
 1 file changed, 28 insertions(+), 18 deletions(-)

diff --git a/src/pl-glob.c b/src/pl-glob.c
index 417a69c..1fad6ca 100644
--- a/src/pl-glob.c
+++ b/src/pl-glob.c
@@ -423,6 +423,7 @@ expand(const char *pattern, GlobInfo info)
   compiled_pattern cbuf;
   char prefix[MAXPATHLEN];		/* before first pattern */
   char patbuf[MAXPATHLEN];		/* pattern buffer */
+  size_t prefix_len;
   int end, dot;
 
   initBuffer(&info->files);
@@ -441,20 +442,25 @@ expand(const char *pattern, GlobInfo info)
       switch( (c=*s++) )
       { case EOS:
 	  if ( s > pat )		/* something left and expanded */
-	  { un_escape(prefix, pat, s);
+	  { size_t prefix_len;
+
+	    un_escape(prefix, pat, s);
+	    prefix_len = strlen(prefix);
 
 	    end = info->end;
 	    for( ; info->start < end; info->start++ )
 	    { char path[MAXPATHLEN];
-	      size_t plen;
-
-	      strcpy(path, expand_entry(info, info->start));
-	      plen = strlen(path);
-	      if ( prefix[0] && plen > 0 && path[plen-1] != '/' )
-		path[plen++] = '/';
-	      strcpy(&path[plen], prefix);
-	      if ( end == 1 || AccessFile(path, ACCESS_EXIST) )
-		add_path(path, info);
+	      const char *entry = expand_entry(info, info->start);
+	      size_t plen = strlen(entry);
+
+	      if ( plen+prefix_len+2 <= MAXPATHLEN )
+	      { strcpy(path, entry);
+		if ( prefix[0] && plen > 0 && path[plen-1] != '/' )
+		  path[plen++] = '/';
+		strcpy(&path[plen], prefix);
+		if ( end == 1 || AccessFile(path, ACCESS_EXIST) )
+		  add_path(path, info);
+	      }
 	    }
 	  }
 	  succeed;
@@ -489,8 +495,9 @@ expand(const char *pattern, GlobInfo info)
 */
     un_escape(prefix, pat, head);
     un_escape(patbuf, head, tail);
+    prefix_len = strlen(prefix);
 
-    if ( !compilePattern(patbuf, &cbuf) )		/* syntax error */
+    if ( !compilePattern(patbuf, &cbuf) )	/* syntax error */
       fail;
     dot = (patbuf[0] == '.');			/* do dots as well */
 
@@ -502,12 +509,16 @@ expand(const char *pattern, GlobInfo info)
       char path[MAXPATHLEN];
       char tmp[MAXPATHLEN];
       const char *current = expand_entry(info, info->start);
+      size_t clen = strlen(current);
+
+      if ( clen+prefix_len+1 > sizeof(path) )
+	continue;
 
       strcpy(path, current);
-      strcat(path, prefix);
+      strcpy(&path[clen], prefix);
 
       if ( (d=opendir(path[0] ? OsPath(path, tmp) : ".")) )
-      { size_t plen = strlen(path);
+      { size_t plen = clen+prefix_len;
 
 	if ( plen > 0 && path[plen-1] != '/' )
 	  path[plen++] = '/';
@@ -521,12 +532,11 @@ expand(const char *pattern, GlobInfo info)
 	       matchPattern(e->d_name, &cbuf) )
 	  { char newp[MAXPATHLEN];
 
-	    strcpy(newp, path);
-	    strcpy(&newp[plen], e->d_name);
-/*	    if ( !tail[0] || ExistsDirectory(newp) )
-	    Saves memory, but involves one more file-access
-*/
+	    if ( plen+strlen(e->d_name)+1 < sizeof(newp) )
+	    { strcpy(newp, path);
+	      strcpy(&newp[plen], e->d_name);
 	      add_path(newp, info);
+	    }
 	  }
 	}
 	closedir(d);
-- 
1.7.11.7