2015-02-05  Paul Pluzhnikov  <ppluzhnikov@google.com>

	[BZ #16618]
	* stdio-common/tst-sscanf.c (main): Test for buffer overflow.
	* stdio-common/vfscanf.c (_IO_vfscanf_internal): Compute needed
	size in bytes. Store needed elements in wpmax. Use needed size
	in bytes for extend_alloca.

2012-01-05  Paul Pluzhnikov  <ppluzhnikov@google.com>

	* stdio-common/vfscanf.c (_IO_vfscanf_internal): Use alloca when
	appropriate.

2011-09-09  Ulrich Drepper  <drepper@gmail.com>

	[BZ #13138]
	* stdio-common/vfscanf.c (ADDW): Allocate large memory block with
	realloc.
	(_IO_vfscanf_internal): Remove reteof.  Use errout after setting done.
	Free memory block if necessary.

Index: glibc-2.11.3/stdio-common/tst-sscanf.c
===================================================================
--- glibc-2.11.3.orig/stdio-common/tst-sscanf.c
+++ glibc-2.11.3/stdio-common/tst-sscanf.c
@@ -197,5 +197,38 @@ main (void)
 	}
     }
 
+  /* BZ #16618
+     The test will segfault during SSCANF if the buffer overflow
+     is not fixed.  The size of `s` is such that it forces the use
+     of malloc internally and this triggers the incorrect computation.
+     Thus the value for SIZE is arbitrariy high enough that malloc
+     is used.  */
+  {
+#define SIZE 131072
+    CHAR *s = malloc ((SIZE + 1) * sizeof (*s));
+    if (s == NULL)
+      abort ();
+    for (size_t i = 0; i < SIZE; i++)
+      s[i] = L('0');
+    s[SIZE] = L('\0');
+    int i = 42;
+    /* Scan multi-digit zero into `i`.  */
+    if (SSCANF (s, L("%d"), &i) != 1)
+      {
+	printf ("FAIL: bug16618: SSCANF did not read one input item.\n");
+	result = 1;
+      }
+    if (i != 0)
+      {
+	printf ("FAIL: bug16618: Value of `i` was not zero as expected.\n");
+	result = 1;
+      }
+    free (s);
+    if (result != 1)
+      printf ("PASS: bug16618: Did not crash.\n");
+#undef SIZE
+  }
+
+
   return result;
 }
Index: glibc-2.11.3/stdio-common/vfscanf.c
===================================================================
--- glibc-2.11.3.orig/stdio-common/vfscanf.c
+++ glibc-2.11.3/stdio-common/vfscanf.c
@@ -265,16 +265,39 @@ _IO_vfscanf_internal (_IO_FILE *s, const
   CHAR_T *wp = NULL;		/* Workspace.  */
   size_t wpmax = 0;		/* Maximal size of workspace.  */
   size_t wpsize;		/* Currently used bytes in workspace.  */
+  bool use_malloc = false;
 #define ADDW(Ch)							    \
   do									    \
     {									    \
-      if (wpsize == wpmax)						    \
+      if (__builtin_expect (wpsize == wpmax, 0))			    \
 	{								    \
 	  CHAR_T *old = wp;						    \
-	  wpmax = (UCHAR_MAX + 1 > 2 * wpmax ? UCHAR_MAX + 1 : 2 * wpmax);  \
-	  wp = (CHAR_T *) alloca (wpmax * sizeof (CHAR_T));		    \
-	  if (old != NULL)						    \
-	    MEMCPY (wp, old, wpsize);					    \
+	  bool fits = __builtin_expect (wpmax <= SIZE_MAX / sizeof (CHAR_T) / 2, 1); \
+	  size_t wpneed = MAX (UCHAR_MAX + 1, 2 * wpmax);		    \
+	  size_t newsize = fits ? wpneed * sizeof (CHAR_T) : SIZE_MAX;	    \
+	  if (!__libc_use_alloca (newsize))				    \
+	    {								    \
+	      wp = realloc (use_malloc ? wp : NULL, newsize);		    \
+	      if (wp == NULL)						    \
+		{							    \
+		  if (use_malloc)					    \
+		    free (old);						    \
+		  done = EOF;						    \
+		  goto errout;						    \
+		}							    \
+	      if (! use_malloc)						    \
+		MEMCPY (wp, old, wpsize);				    \
+	      wpmax = wpneed;						    \
+	      use_malloc = true;					    \
+	    }								    \
+	  else								    \
+	    {								    \
+	      size_t s = wpmax * sizeof (CHAR_T);			    \
+	      wp = (CHAR_T *) extend_alloca (wp, s, newsize);		    \
+	      wpmax = s / sizeof (CHAR_T);				    \
+	      if (old != NULL)						    \
+		MEMCPY (wp, old, wpsize);				    \
+	    }								    \
 	}								    \
       wp[wpsize++] = (Ch);						    \
     }									    \
@@ -670,7 +693,10 @@ _IO_vfscanf_internal (_IO_FILE *s, const
 		      if (Str != NULL)					      \
 			add_ptr_to_free (strptr);			      \
 		      else if (flags & POSIX_MALLOC)			      \
-			goto reteof;					      \
+			{						      \
+			  done = EOF;					      \
+			  goto errout;					      \
+			}						      \
 		    }							      \
 		  else							      \
 		    Str = ARG (Type *);					      \
@@ -711,8 +737,11 @@ _IO_vfscanf_internal (_IO_FILE *s, const
 			  newstr = (char *) realloc (*strptr,
 						     strleng + MB_CUR_MAX);
 			  if (newstr == NULL)
-			    /* c can't have `a' flag, only `m'.  */
-			    goto reteof;
+			    {
+			      /* c can't have `a' flag, only `m'.  */
+			      done = EOF;
+			      goto errout;
+			    }
 			  else
 			    {
 			      *strptr = newstr;
@@ -758,8 +787,11 @@ _IO_vfscanf_internal (_IO_FILE *s, const
 				 effort.  */
 			      str = (char *) realloc (*strptr, strsize + 1);
 			      if (str == NULL)
-				/* c can't have `a' flag, only `m'.  */
-				goto reteof;
+				{
+				  /* c can't have `a' flag, only `m'.  */
+				  done = EOF;
+				  goto errout;
+				}
 			      else
 				{
 				  *strptr = (char *) str;
@@ -828,8 +860,12 @@ _IO_vfscanf_internal (_IO_FILE *s, const
 						      (strsize + 1)
 						      * sizeof (wchar_t));
 			  if (wstr == NULL)
-			    /* C or lc can't have `a' flag, only `m' flag.  */
-			    goto reteof;
+			    {
+			      /* C or lc can't have `a' flag, only `m'
+				 flag.  */
+			      done = EOF;
+			      goto errout;
+			    }
 			  else
 			    {
 			      *strptr = (char *) wstr;
@@ -879,8 +915,11 @@ _IO_vfscanf_internal (_IO_FILE *s, const
 						    ((strsize + 1)
 						     * sizeof (wchar_t)));
 			if (wstr == NULL)
-			  /* C or lc can't have `a' flag, only `m' flag.  */
-			  goto reteof;
+			  {
+			    /* C or lc can't have `a' flag, only `m' flag.  */
+			    done = EOF;
+			    goto errout;
+			  }
 			else
 			  {
 			    *strptr = (char *) wstr;
@@ -992,7 +1031,10 @@ _IO_vfscanf_internal (_IO_FILE *s, const
 			    if (newstr == NULL)
 			      {
 				if (flags & POSIX_MALLOC)
-				  goto reteof;
+				  {
+				    done = EOF;
+				    goto errout;
+				  }
 				/* We lose.  Oh well.  Terminate the
 				   string and stop converting,
 				   so at least we don't skip any input.  */
@@ -1042,7 +1084,10 @@ _IO_vfscanf_internal (_IO_FILE *s, const
 			      if (str == NULL)
 				{
 				  if (flags & POSIX_MALLOC)
-				    goto reteof;
+				    {
+				      done = EOF;
+				      goto errout;
+				    }
 				  /* We lose.  Oh well.  Terminate the
 				     string and stop converting,
 				     so at least we don't skip any input.  */
@@ -1088,7 +1133,10 @@ _IO_vfscanf_internal (_IO_FILE *s, const
 		      if (newstr == NULL)
 			{
 			  if (flags & POSIX_MALLOC)
-			    goto reteof;
+			    {
+			      done = EOF;
+			      goto errout;
+			    }
 			  /* We lose.  Oh well.  Terminate the string
 			     and stop converting, so at least we don't
 			     skip any input.  */
@@ -1170,7 +1218,10 @@ _IO_vfscanf_internal (_IO_FILE *s, const
 			    if (wstr == NULL)
 			      {
 				if (flags & POSIX_MALLOC)
-				  goto reteof;
+				  {
+				    done = EOF;
+				    goto errout;
+				  }
 				/* We lose.  Oh well.  Terminate the string
 				   and stop converting, so at least we don't
 				   skip any input.  */
@@ -1242,7 +1293,10 @@ _IO_vfscanf_internal (_IO_FILE *s, const
 			  if (wstr == NULL)
 			    {
 			      if (flags & POSIX_MALLOC)
-				goto reteof;
+				{
+				  done = EOF;
+				  goto errout;
+				}
 			      /* We lose.  Oh well.  Terminate the
 				 string and stop converting, so at
 				 least we don't skip any input.  */
@@ -2433,7 +2487,10 @@ _IO_vfscanf_internal (_IO_FILE *s, const
 			      if (wstr == NULL)
 				{
 				  if (flags & POSIX_MALLOC)
-				    goto reteof;
+				    {
+				      done = EOF;
+				      goto errout;
+				    }
 				  /* We lose.  Oh well.  Terminate the string
 				     and stop converting, so at least we don't
 				     skip any input.  */
@@ -2515,7 +2572,10 @@ _IO_vfscanf_internal (_IO_FILE *s, const
 			      if (wstr == NULL)
 				{
 				  if (flags & POSIX_MALLOC)
-				    goto reteof;
+				    {
+				      done = EOF;
+				      goto errout;
+				    }
 				  /* We lose.  Oh well.  Terminate the
 				     string and stop converting,
 				     so at least we don't skip any input.  */
@@ -2657,7 +2717,10 @@ _IO_vfscanf_internal (_IO_FILE *s, const
 			      if (newstr == NULL)
 				{
 				  if (flags & POSIX_MALLOC)
-				    goto reteof;
+				    {
+				      done = EOF;
+				      goto errout;
+				    }
 				  /* We lose.  Oh well.  Terminate the string
 				     and stop converting, so at least we don't
 				     skip any input.  */
@@ -2722,7 +2785,10 @@ _IO_vfscanf_internal (_IO_FILE *s, const
 				  goto allocagain;
 				}
 			      if (flags & POSIX_MALLOC)
-				goto reteof;
+				{
+				  done = EOF;
+				  goto errout;
+				}
 			      /* We lose.  Oh well.  Terminate the
 				 string and stop converting,
 				 so at least we don't skip any input.  */
@@ -2765,7 +2831,10 @@ _IO_vfscanf_internal (_IO_FILE *s, const
 		      if (newstr == NULL)
 			{
 			  if (flags & POSIX_MALLOC)
-			    goto reteof;
+			    {
+			      done = EOF;
+			      goto errout;
+			    }
 			  /* We lose.  Oh well.  Terminate the string
 			     and stop converting, so at least we don't
 			     skip any input.  */
@@ -2828,12 +2897,14 @@ _IO_vfscanf_internal (_IO_FILE *s, const
   /* Unlock stream.  */
   UNLOCK_STREAM (s);
 
+  if (use_malloc)
+    free (wp);
+
   if (errp != NULL)
     *errp |= errval;
 
-  if (done == EOF)
+  if (__builtin_expect (done == EOF, 0))
     {
-  reteof:
       if (__builtin_expect (ptrs_to_free != NULL, 0))
 	{
 	  struct ptrs_to_free *p = ptrs_to_free;
@@ -2848,7 +2919,6 @@ _IO_vfscanf_internal (_IO_FILE *s, const
 	      ptrs_to_free = p;
 	    }
 	}
-      return EOF;
     }
   else if (__builtin_expect (strptr != NULL, 0))
     {
