From: Bernhard Voelker <mail@bernhard-voelker.de>
Subject: sort, join, uniq: avoid segmentation fault with long input lines

    The i18n patches used to make use of the alloca function which cannot
    guarantee success, and the result can not be tested for success/failure.
    From `man alloca`:
      "If the allocation causes stack overflow, program behavior is undefined."
    Simply replace all uses of alloca by xmalloc.

    - Avoid segmentation fault in "join -i" with long line input
      (bnc#798541, VUL-1)
      
       Test case:
         $ perl -e 'print "1","A"x50000000,"\r\n\r\n"' > /tmp/test.txt
         $ join -i /tmp/test.txt /tmp/test.txt
       
       * src/join.c: Instead of usig unreliable alloca() stack allocation,
         use heap allocation via xmalloc()+free().
         (coreutils-i18n.patch, from Philipp Thomas <pth@suse.de>)

    - Avoid segmentation fault in "sort -d" and "sort -M" with long line input
      (bnc#798538, VUL-1)

      Test cases:
        $ perl -e 'print "1","A"x50000000,"\r\n\r\n"' | sort -d
        $ perl -e 'print "1","A"x50000000,"\r\n\r\n"' | sort -M        
      
      * src/sort.c: Instead of usig unreliable alloca() stack allocation,
        use heap allocation via xmalloc()+free().
        (coreutils-i18n.patch, from Philipp Thomas <pth@suse.de>)

    - Avoid segmentation fault in "uniq" with long line input
      (bnc#796243, VUL-1)

      Test case:
        $ perl -e 'print "1","\0"x50000000,"\r\n\r\n"' | uniq

      * src/cut.c: Instead of usig unreliable alloca() stack allocation,
        use heap allocation via xmalloc()+free().
        (coreutils-i18n.patch)

---
 src/join.c |   53 ++++++++++++++++++++++++++++++++++++++++++++++++-----
 src/sort.c |   10 +++++++---
 src/uniq.c |   10 ++++++++--
 3 files changed, 63 insertions(+), 10 deletions(-)

Index: src/join.c
===================================================================
--- src/join.c.orig	2013-08-13 12:33:09.462560284 +0200
+++ src/join.c	2013-08-13 12:33:09.811552024 +0200
@@ -328,6 +328,7 @@ keycmp (struct line const *line1, struct
   size_t len[2];           /* Length of fields to compare.  */
   int diff;
   int i, j;
+  int mallocd = 0;
 
   if (jf_1 < line1->nfields)
     {
@@ -369,7 +370,8 @@ keycmp (struct line const *line1, struct
 
 	  for (i = 0; i < 2; i++)
 	    {
-	      copy[i] = alloca (len[i] + 1);
+	      mallocd = 1;
+	      copy[i] = xmalloc (len[i] + 1);
 
 	      for (j = 0; j < MIN (len[0], len[1]);)
 		{
@@ -403,21 +405,49 @@ keycmp (struct line const *line1, struct
 		}
 	      copy[i][j] = '\0';
 	    }
-	  return xmemcoll (copy[0], len[0], copy[1], len[1]);
+
+	  {
+	    diff = xmemcoll (copy[0], len[0], copy[1], len[1]);
+
+	    if (mallocd)
+	      for (i = 0; i < 2; i++)
+	      	free (copy[i]);
+
+	    return diff;
+	  }
+
+	  for(i = 0; i < 2; i++)
+	      free(copy[i]);
+
+	  return diff;
 	}
 #endif
       if (hard_LC_COLLATE)
 	{
 	  for (i = 0; i < 2; i++)
 	    {
-	      copy[i] = alloca (len[i] + 1);
+	      mallocd = 1;
+	      copy[i] = xmalloc (len[i] + 1);
 
 	      for (j = 0; j < MIN (len[0], len[1]); j++)
 		copy[i][j] = toupper (beg[i][j]);
 
 	      copy[i][j] = '\0';
 	    }
-	  return xmemcoll (copy[0], len[0], copy[1], len[1]);
+	  {
+	    diff = xmemcoll (copy[0], len[0], copy[1], len[1]);
+
+	    if (mallocd)
+	      for (i = 0; i < 2; i++)
+	      	free (copy[i]);
+
+	    return diff;
+	  }
+
+	  for(i = 0; i < 2; i++)
+	      free(copy[i]);
+
+          return diff;
 	}
       else
 	diff = memcasecmp (beg[0], beg[1], MIN (len[0], len[1]));
@@ -425,10 +455,23 @@ keycmp (struct line const *line1, struct
   else
     {
       if (hard_LC_COLLATE)
-	return xmemcoll (beg[0], len[0], beg[1], len[1]);
+      {
+	diff = xmemcoll (beg[0], len[0], beg[1], len[1]);
+
+        if (mallocd)
+          for (i = 0; i < 2; i++)
+            free (copy[i]);
+
+	return diff;
+      }
+
       diff = memcmp (beg[0], beg[1], MIN (len[0], len[1]));
     }
 
+    if (mallocd)
+      for (i = 0; i < 2; i++)
+      	free (copy[i]);
+
   if (diff)
     return diff;
   return len[0] < len[1] ? -1 : len[0] != len[1];
Index: src/sort.c
===================================================================
--- src/sort.c.orig	2013-08-13 12:33:09.556558059 +0200
+++ src/sort.c	2013-08-13 12:33:09.812552000 +0200
@@ -2098,13 +2098,13 @@ getmonth_mb (char const *s, size_t len)
   if (len == 0)
     return 0;
 
-  month = (char *) alloca (len + 1);
+  month = (char *) xmalloc (len + 1);
 
-  tmp = (char *) alloca (len + 1);
+  tmp = (char *) xmalloc (len + 1);
   memcpy (tmp, s, len);
   tmp[len] = '\0';
   pp = (const char **) &tmp;
-  month_wcs = (wchar_t *) alloca ((len + 1) * sizeof (wchar_t));
+  month_wcs = (wchar_t *) xmalloc ((len + 1) * sizeof (wchar_t));
   memset (&state, '\0', sizeof (mbstate_t));
 
   wclength = mbsrtowcs (month_wcs, pp, len + 1, &state);
@@ -2139,6 +2139,10 @@ getmonth_mb (char const *s, size_t len)
   result = (!strncmp (month, monthtab[lo].name, strlen (monthtab[lo].name))
 	    ? monthtab[lo].val : 0);
 
+  free (month);
+  free (tmp);
+  free (month_wcs);
+
   return result;
 }
 #endif
Index: src/uniq.c
===================================================================
--- src/uniq.c.orig	2013-08-13 12:33:09.464560237 +0200
+++ src/uniq.c	2013-08-13 12:33:09.813551976 +0200
@@ -363,6 +363,7 @@ different_multi (const char *old, const
   size_t mblength;
   wchar_t wc, uwc;
   mbstate_t state_bak;
+  int ret;
 
   str[0] = old;
   str[1] = new;
@@ -373,7 +374,7 @@ different_multi (const char *old, const
 
   for (i = 0; i < 2; i++)
     {
-      copy[i] = alloca (len[i] + 1);
+      copy[i] = xmalloc (len[i] + 1);
 
       for (j = 0, chars = 0; j < len[i] && chars < check_chars; chars++)
 	{
@@ -414,7 +415,12 @@ different_multi (const char *old, const
       len[i] = j;
     }
 
-  return xmemcoll (copy[0], len[0], copy[1], len[1]);
+  ret = xmemcoll (copy[0], len[0], copy[1], len[1]);
+
+  for (i = 0; i < 2; i++)
+      free(copy[i]);
+
+  return ret;
 }
 #endif
 
