This is the mail archive of the libc-alpha@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] vfscanf: Avoid multiple reads of multi-byte character width


This avoids a race condition if the process-global locale is changed
while vfscanf is running.  MB_LEN_MAX is always larger than MB_CUR_MAX,
so we might realloc earlier than necessary (but even MB_CUR_MAX could
be larger than the minimum required space).

The existing length was a bit questionable because str + MB_LEN_MAX
might point past the end of the buffer.

2016-09-02  Florian Weimer  <fweimer@redhat.com>

	* stdio-common/vfscanf.c (_IO_vfwscanf): Use MB_LEN_MAX instead of
	MB_CUR_MAX to avoid race condition.  Avoid pointer arithmetic
	outside of allocated array.

diff --git a/stdio-common/vfscanf.c b/stdio-common/vfscanf.c
index 8cd5955..2b7093e 100644
--- a/stdio-common/vfscanf.c
+++ b/stdio-common/vfscanf.c
@@ -757,7 +757,7 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr,
 		  size_t n;
 
 		  if (!(flags & SUPPRESS) && (flags & POSIX_MALLOC)
-		      && str + MB_CUR_MAX >= *strptr + strsize)
+		      && MB_LEN_MAX >= *strptr + strsize - str)
 		    {
 		      /* We have to enlarge the buffer if the `m' flag
 			 was given.  */
@@ -769,7 +769,7 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr,
 			{
 			  /* Can't allocate that much.  Last-ditch effort.  */
 			  newstr = (char *) realloc (*strptr,
-						     strleng + MB_CUR_MAX);
+						     strleng + MB_LEN_MAX);
 			  if (newstr == NULL)
 			    {
 			      /* c can't have `a' flag, only `m'.  */
@@ -780,7 +780,7 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr,
 			    {
 			      *strptr = newstr;
 			      str = newstr + strleng;
-			      strsize = strleng + MB_CUR_MAX;
+			      strsize = strleng + MB_LEN_MAX;
 			    }
 			}
 		      else
@@ -1048,7 +1048,7 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr,
 		    size_t n;
 
 		    if (!(flags & SUPPRESS) && (flags & MALLOC)
-			&& str + MB_CUR_MAX >= *strptr + strsize)
+			&& MB_LEN_MAX >= *strptr + strsize - str)
 		      {
 			/* We have to enlarge the buffer if the `a' or `m'
 			   flag was given.  */
@@ -1061,7 +1061,7 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr,
 			    /* Can't allocate that much.  Last-ditch
 			       effort.  */
 			    newstr = (char *) realloc (*strptr,
-						       strleng + MB_CUR_MAX);
+						       strleng + MB_LEN_MAX);
 			    if (newstr == NULL)
 			      {
 				if (flags & POSIX_MALLOC)
@@ -1081,7 +1081,7 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr,
 			      {
 				*strptr = newstr;
 				str = newstr + strleng;
-				strsize = strleng + MB_CUR_MAX;
+				strsize = strleng + MB_LEN_MAX;
 			      }
 			  }
 			else
@@ -1097,7 +1097,7 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr,
 		    if (__glibc_unlikely (n == (size_t) -1))
 		      encode_error ();
 
-		    assert (n <= MB_CUR_MAX);
+		    assert (n <= MB_LEN_MAX);
 		    str += n;
 		  }
 #else
@@ -2675,7 +2675,7 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr,
 			  /* Possibly correct character, just not enough
 			     input.  */
 			  ++cnt;
-			  assert (cnt < MB_CUR_MAX);
+			  assert (cnt < MB_LEN_MAX);
 			  continue;
 			}
 		      cnt = 0;
@@ -2827,7 +2827,7 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr,
 		  if (!(flags & SUPPRESS))
 		    {
 		      if ((flags & MALLOC)
-			  && str + MB_CUR_MAX >= *strptr + strsize)
+			  && MB_LEN_MAX >= *strptr + strsize - str)
 			{
 			  /* Enlarge the buffer.  */
 			  size_t strleng = str - *strptr;
@@ -2839,7 +2839,7 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr,
 			      /* Can't allocate that much.  Last-ditch
 				 effort.  */
 			      newstr = (char *) realloc (*strptr,
-							 strleng + MB_CUR_MAX);
+							 strleng + MB_LEN_MAX);
 			      if (newstr == NULL)
 				{
 				  if (flags & POSIX_MALLOC)
@@ -2859,7 +2859,7 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr,
 				{
 				  *strptr = newstr;
 				  str = newstr + strleng;
-				  strsize = strleng + MB_CUR_MAX;
+				  strsize = strleng + MB_LEN_MAX;
 				}
 			    }
 			  else
@@ -2875,7 +2875,7 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr,
 		  if (__glibc_unlikely (n == (size_t) -1))
 		    encode_error ();
 
-		  assert (n <= MB_CUR_MAX);
+		  assert (n <= MB_LEN_MAX);
 		  str += n;
 		}
 	      while (--width > 0 && inchar () != WEOF);


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]