Patchwork [16/18] posix: More check for overflow allocation in glob

login
register
mail settings
Submitter Adhemerval Zanella Netto
Date Aug. 11, 2017, 2:50 p.m.
Message ID <1502463044-4042-17-git-send-email-adhemerval.zanella@linaro.org>
Download mbox | patch
Permalink /patch/22099/
State New
Headers show

Comments

Adhemerval Zanella Netto - Aug. 11, 2017, 2:50 p.m.
This patch adds and replace the allocation overflow based using
malloc internal functions check_add_wrapv_size_t and __libc_reallocarray.

Checked on x86_64-linux-gnu.

	* posix/glob.c (glob_malloc_incr): New function.
	(glob_malloc_incr2): Likewise.
	(glob_realloc_incr): Likewise.
	(glob): Use glob_{realloc,malloc}_incr{2}.
---
 posix/glob.c | 92 +++++++++++++++++++++++++++++++++++++++++-------------------
 1 file changed, 63 insertions(+), 29 deletions(-)

Patch

diff --git a/posix/glob.c b/posix/glob.c
index c85342a..647334d 100644
--- a/posix/glob.c
+++ b/posix/glob.c
@@ -303,6 +303,39 @@  get_home_directory (const char *user_name, struct char_array *home_dir)
   return retval;
 }
 
+/* Allocate '(size + incr) * typesize' bytes while for overflow on the
+   arithmetic operations.  */
+static void *
+glob_malloc_incr (size_t size, size_t incr, size_t typesize)
+{
+  size_t newsize;
+  if (check_add_overflow_size_t (size, incr, &newsize))
+    return NULL;
+  return __libc_reallocarray (NULL, newsize, typesize);
+}
+
+/* Allocate '(size + incr1 + incr2) * typesize' bytes while for overflow on
+   the arithmetic operations.  */
+static void *
+glob_malloc_incr2 (size_t size, size_t incr1, size_t incr2, size_t typesize)
+{
+  size_t newsize;
+  if (check_add_overflow_size_t (size, incr1, &newsize)
+      || check_add_overflow_size_t (newsize, incr2, &newsize))
+    return NULL;
+  return __libc_reallocarray (NULL, newsize, typesize);
+}
+
+/* Reallocate '(size + incr1) * typesize' bytes while for overflow on the
+   arithmetic operations.  */
+static void *
+glob_realloc_incr (void *old, size_t size, size_t incr, size_t typesize)
+{
+  size_t newsize;
+  if (check_add_overflow_size_t (size, incr, &newsize))
+    return NULL;
+  return __libc_reallocarray (old, newsize, typesize);
+}
 
 /* Do glob searching for PATTERN, placing results in PGLOB.
    The bits defined above may be set in FLAGS.
@@ -357,11 +390,8 @@  glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
 	{
 	  size_t i;
 
-	  if (pglob->gl_offs >= ~((size_t) 0) / sizeof (char *))
-	    goto err_nospace;
-
-	  pglob->gl_pathv = (char **) malloc ((pglob->gl_offs + 1)
-					      * sizeof (char *));
+	  pglob->gl_pathv = glob_malloc_incr (pglob->gl_offs, 1,
+					      sizeof (char *));
 	  if (pglob->gl_pathv == NULL)
 	    goto err_nospace;
 
@@ -817,10 +847,11 @@  glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
 	       : (__lstat64 (char_array_str (&dirname), &st64) == 0
 		  && S_ISDIR (st64.st_mode)))))
 	{
-	  size_t newcount = pglob->gl_pathc + pglob->gl_offs;
 	  char **new_gl_pathv;
+	  size_t newcount;
 
-          if (newcount > SIZE_MAX / sizeof (char *) - 2)
+	  if (check_add_overflow_size_t (pglob->gl_pathc, pglob->gl_offs,
+					 &newcount))
 	    {
 	    nospace:
 	      free (pglob->gl_pathv);
@@ -829,8 +860,8 @@  glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
 	      goto err_nospace;
 	    }
 
-	  new_gl_pathv = realloc (pglob->gl_pathv,
-				  (newcount + 2) * sizeof (char *));
+	  new_gl_pathv = glob_realloc_incr (pglob->gl_pathv, newcount, 2,
+					    sizeof (char *));
 	  if (new_gl_pathv == NULL)
 	    goto nospace;
 	  pglob->gl_pathv = new_gl_pathv;
@@ -838,9 +869,12 @@  glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
 	  if (flags & GLOB_MARK)
 	    {
 	      char *p;
-	      pglob->gl_pathv[newcount] = malloc (dirlen + 2);
+
+	      pglob->gl_pathv[newcount] = glob_malloc_incr (dirlen, 2,
+							    sizeof (char));
 	      if (pglob->gl_pathv[newcount] == NULL)
 		goto nospace;
+
 	      p = mempcpy (pglob->gl_pathv[newcount],
 			   char_array_str (&dirname), dirlen);
 	      p[0] = '/';
@@ -978,18 +1012,19 @@  glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
 	  /* No matches.  */
 	  if (flags & GLOB_NOCHECK)
 	    {
-	      size_t newcount = pglob->gl_pathc + pglob->gl_offs;
+	      size_t newcount;
 	      char **new_gl_pathv;
 
-	      if (newcount > SIZE_MAX / sizeof (char *) - 2)
+	      if (check_add_overflow_size_t (pglob->gl_pathc, pglob->gl_offs,
+					     &newcount))
 		{
 		nospace2:
 		  globfree (&dirs);
 		  goto err_nospace;
 		}
 
-	      new_gl_pathv = realloc (pglob->gl_pathv,
-				      (newcount + 2) * sizeof (char *));
+	      new_gl_pathv = glob_realloc_incr (pglob->gl_pathv, newcount, 2,
+						sizeof (char *));
 	      if (new_gl_pathv == NULL)
 		goto nospace2;
 	      pglob->gl_pathv = new_gl_pathv;
@@ -1091,15 +1126,16 @@  glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
 	     : (__lstat64 (pglob->gl_pathv[i], &st64) == 0
 		&& (S_ISDIR (st64.st_mode) || S_ISLNK (st64.st_mode)))))
 	  {
-	    size_t len = strlen (pglob->gl_pathv[i]) + 2;
-	    char *new = realloc (pglob->gl_pathv[i], len);
+	    size_t len = strlen (pglob->gl_pathv[i]);
+	    char *new = glob_realloc_incr (pglob->gl_pathv[i], len, 2,
+					   sizeof (char));
 	    if (new == NULL)
 	      {
 		globfree (pglob);
 		pglob->gl_pathc = 0;
 		goto err_nospace;
 	      }
-	    strcpy (&new[len - 2], "/");
+	    strcpy (&new[len], "/");
 	    pglob->gl_pathv[i] = new;
 	  }
     }
@@ -1184,7 +1220,7 @@  prefix_array (const char *dirname, char **array, size_t n)
   for (i = 0; i < n; ++i)
     {
       size_t eltlen = strlen (array[i]) + 1;
-      char *new = malloc (dirlen + 1 + eltlen);
+      char *new = glob_malloc_incr2 (dirlen, 1, eltlen, sizeof (char));
       if (new == NULL)
 	{
 	  while (i > 0)
@@ -1192,11 +1228,10 @@  prefix_array (const char *dirname, char **array, size_t n)
 	  return 1;
 	}
 
-      {
-	char *endp = mempcpy (new, dirname, dirlen);
-	*endp++ = DIRSEP_CHAR;
-	mempcpy (endp, array[i], eltlen);
-      }
+      char *endp = mempcpy (new, dirname, dirlen);
+      *endp++ = DIRSEP_CHAR;
+      mempcpy (endp, array[i], eltlen);
+
       free (array[i]);
       array[i] = new;
     }
@@ -1349,16 +1384,15 @@  glob_in_dir (const char *pattern, const char *directory, int flags,
   if (nfound != 0)
     {
       char **new_gl_pathv;
+      size_t newlen;
       result = 0;
 
-      if (SIZE_MAX / sizeof (char *) - pglob->gl_pathc
-          < pglob->gl_offs + nfound + 1)
+      if (check_add_overflow_size_t (pglob->gl_pathc, pglob->gl_offs, &newlen)
+	  || check_add_overflow_size_t (newlen, nfound, &newlen)
+	  || check_add_overflow_size_t (newlen, 1, &newlen))
 	goto memory_error;
 
-      new_gl_pathv
-	= realloc (pglob->gl_pathv,
-		   (pglob->gl_pathc + pglob->gl_offs + nfound + 1)
-		    * sizeof (char *));
+      new_gl_pathv = realloc (pglob->gl_pathv, newlen * sizeof (char *));
 
       if (new_gl_pathv == NULL)
 	{