changeset 4791:c47569f6dfaa

Check for address arithmetic overflow. Do not alloca huge buffers.
author Paul Eggert <eggert@cs.ucla.edu>
date Thu, 16 Oct 2003 06:51:24 +0000
parents 12ade6a1528e
children f5c9bbb6cdc9
files lib/fnmatch.c lib/fnmatch_loop.c
diffstat 2 files changed, 63 insertions(+), 22 deletions(-) [+]
line wrap: on
line diff
--- a/lib/fnmatch.c
+++ b/lib/fnmatch.c
@@ -80,6 +80,10 @@
 extern int fnmatch (const char *pattern, const char *string, int flags);
 #endif
 
+#ifndef SIZE_MAX
+# define SIZE_MAX ((size_t) -1)
+#endif
+
 /* We often have to test for FNM_FILE_NAME and FNM_PERIOD being both set.  */
 #define NO_LEADING_PERIOD(flags) \
   ((flags & (FNM_FILE_NAME | FNM_PERIOD)) == (FNM_FILE_NAME | FNM_PERIOD))
@@ -318,40 +322,70 @@
 fnmatch (const char *pattern, const char *string, int flags)
 {
 # if HANDLE_MULTIBYTE
+#  define ALLOCA_LIMIT 2000
   if (__builtin_expect (MB_CUR_MAX, 1) != 1)
     {
       mbstate_t ps;
-      size_t n;
+      size_t patsize;
+      size_t strsize;
+      size_t totsize;
       wchar_t *wpattern;
       wchar_t *wstring;
+      int res;
 
-      /* Convert the strings into wide characters.  */
+      /* Calculate the size needed to convert the strings to
+	 wide characters.  */
       memset (&ps, '\0', sizeof (ps));
-      n = mbsrtowcs (NULL, &pattern, 0, &ps);
-      if (__builtin_expect (n, 0) == (size_t) -1)
+      patsize = mbsrtowcs (NULL, &pattern, 0, &ps) + 1;
+      if (__builtin_expect (patsize == 0, 0))
+	/* Something wrong.
+	   XXX Do we have to set `errno' to something which mbsrtows hasn't
+	   already done?  */
+	return -1;
+      assert (mbsinit (&ps));
+      strsize = mbsrtowcs (NULL, &string, 0, &ps) + 1;
+      if (__builtin_expect (strsize == 0, 0))
 	/* Something wrong.
 	   XXX Do we have to set `errno' to something which mbsrtows hasn't
 	   already done?  */
 	return -1;
-      wpattern = (wchar_t *) alloca ((n + 1) * sizeof (wchar_t));
-      assert (mbsinit (&ps));
-      (void) mbsrtowcs (wpattern, &pattern, n + 1, &ps);
-
       assert (mbsinit (&ps));
-      n = mbsrtowcs (NULL, &string, 0, &ps);
-      if (__builtin_expect (n, 0) == (size_t) -1)
-	/* Something wrong.
-	   XXX Do we have to set `errno' to something which mbsrtows hasn't
-	   already done?  */
-	return -1;
-      wstring = (wchar_t *) alloca ((n + 1) * sizeof (wchar_t));
+      totsize = patsize + strsize;
+      if (__builtin_expect (! (patsize <= totsize
+			       && totsize <= SIZE_MAX / sizeof (wchar_t)),
+			    0))
+	{
+	  errno = ENOMEM;
+	  return -1;
+	}
+
+      /* Allocate room for the wide characters.  */
+      if (__builtin_expect (totsize < ALLOCA_LIMIT, 1))
+	wpattern = (wchar_t *) alloca (totsize * sizeof (wchar_t));
+      else
+	{
+	  wpattern = malloc (totsize * sizeof (wchar_t));
+	  if (__builtin_expect (! wpattern, 0))
+	    {
+	      errno = ENOMEM;
+	      return -1;
+	    }
+	}
+      wstring = wpattern + patsize;
+
+      /* Convert the strings into wide characters.  */
+      mbsrtowcs (wpattern, &pattern, patsize, &ps);
       assert (mbsinit (&ps));
-      (void) mbsrtowcs (wstring, &string, n + 1, &ps);
+      mbsrtowcs (wstring, &string, strsize, &ps);
+
+      res = internal_fnwmatch (wpattern, wstring, wstring + strsize - 1,
+			       flags & FNM_PERIOD, flags);
 
-      return internal_fnwmatch (wpattern, wstring, wstring + n,
-				flags & FNM_PERIOD, flags);
+      if (__builtin_expect (! (totsize < ALLOCA_LIMIT), 0))
+	free (wpattern);
+      return res;
     }
-# endif  /* mbstate_t and mbsrtowcs or _LIBC.  */
+# endif /* HANDLE_MULTIBYTE */
 
   return internal_fnmatch (pattern, string, string + strlen (string),
 			   flags & FNM_PERIOD, flags);
--- a/lib/fnmatch_loop.c
+++ b/lib/fnmatch_loop.c
@@ -1042,16 +1042,23 @@
 	if (level-- == 0)
 	  {
 	    /* This means we found the end of the pattern.  */
+#define ALLOCA_LIMIT 8000
 #define NEW_PATTERN \
 	    struct patternlist *newp;					      \
 	    size_t plen;						      \
+	    size_t plensize;						      \
+	    size_t newpsize;						      \
 									      \
 	    plen = (opt == L('?') || opt == L('@')			      \
 		    ? pattern_len					      \
 		    : p - startp + 1);					      \
-	    newp = (struct patternlist *)				      \
-	      alloca (offsetof (struct patternlist, str)		      \
-		      + (plen * sizeof (CHAR)));			      \
+	    plensize = plen * sizeof (CHAR);				      \
+	    newpsize = offsetof (struct patternlist, str) + plensize;	      \
+	    if ((size_t) -1 / sizeof (CHAR) < plen			      \
+		|| newpsize < offsetof (struct patternlist, str)	      \
+		|| ALLOCA_LIMIT <= newpsize)				      \
+	      return -1;						      \
+	    newp = (struct patternlist *) alloca (newpsize);		      \
 	    *((CHAR *) MEMPCPY (newp->str, startp, p - startp)) = L('\0');    \
 	    newp->next = NULL;						      \
 	    *lastp = newp;						      \