ce426f
commit af37a8a3496327a6e5617a2c76f17aa1e8db835e
ce426f
Author: Siddhesh Poyarekar <siddhesh@redhat.com>
ce426f
Date:   Mon Jan 27 11:32:44 2014 +0530
ce426f
ce426f
    Avoid undefined behaviour in netgroupcache
ce426f
    
ce426f
    Using a buffer after it has been reallocated is undefined behaviour,
ce426f
    so get offsets of the triplets in the old buffer before reallocating
ce426f
    it.
ce426f
ce426f
commit 5d41dadf31bc8a2f9c34c40d52a442d3794e405c
ce426f
Author: Siddhesh Poyarekar <siddhesh@redhat.com>
ce426f
Date:   Fri Jan 24 13:51:15 2014 +0530
ce426f
ce426f
    Adjust pointers to triplets in netgroup query data (BZ #16474)
ce426f
    
ce426f
    The _nss_*_getnetgrent_r query populates the netgroup results in the
ce426f
    allocated buffer and then sets the result triplet to point to strings
ce426f
    in the buffer.  This is a problem when the buffer is reallocated since
ce426f
    the pointers to the triplet strings are no longer valid.  The pointers
ce426f
    need to be adjusted so that they now point to strings in the
ce426f
    reallocated buffer.
ce426f
ce426f
commit 980cb5180e1b71224a57ca52b995c959b7148c09
ce426f
Author: Siddhesh Poyarekar <siddhesh@redhat.com>
ce426f
Date:   Thu Jan 16 10:20:22 2014 +0530
ce426f
ce426f
    Don't use alloca in addgetnetgrentX (BZ #16453)
ce426f
ce426f
    addgetnetgrentX has a buffer which is grown as per the needs of the
ce426f
    requested size either by using alloca or by falling back to malloc if
ce426f
    the size is larger than 1K.  There are two problems with the alloca
ce426f
    bits: firstly, it doesn't really extend the buffer since it does not
ce426f
    use the return value of the extend_alloca macro, which is the location
ce426f
    of the reallocated buffer.  Due to this the buffer does not actually
ce426f
    extend itself and hence a subsequent write may overwrite stuff on the
ce426f
    stack.
ce426f
ce426f
    The second problem is more subtle - the buffer growth on the stack is
ce426f
    discontinuous due to block scope local variables.  Combine that with
ce426f
    the fact that unlike realloc, extend_alloca does not copy over old
ce426f
    content and you have a situation where the buffer just has garbage in
ce426f
    the space where it should have had data.
ce426f
ce426f
    This could have been fixed by adding code to copy over old data
ce426f
    whenever we call extend_alloca, but it seems unnecessarily
ce426f
    complicated.  This code is not exactly a performance hotspot (it's
ce426f
    called when there is a cache miss, so factors like network lookup or
ce426f
    file reads will dominate over memory allocation/reallocation), so this
ce426f
    premature optimization is unnecessary.
ce426f
    
ce426f
    Thanks Brad Hubbard <bhubbard@redhat.com> for his help with debugging
ce426f
    the problem.
ce426f
ce426f
diff -pruN glibc-2.17-c758a686/nscd/netgroupcache.c glibc-2.17-c758a686/nscd/netgroupcache.c
ce426f
--- glibc-2.17-c758a686/nscd/netgroupcache.c	2014-04-09 12:13:58.618582111 +0530
ce426f
+++ glibc-2.17-c758a686/nscd/netgroupcache.c	2014-04-09 12:07:21.486598665 +0530
ce426f
@@ -93,7 +93,6 @@ addgetnetgrentX (struct database_dyn *db
ce426f
   size_t buffilled = sizeof (*dataset);
ce426f
   char *buffer = NULL;
ce426f
   size_t nentries = 0;
ce426f
-  bool use_malloc = false;
ce426f
   size_t group_len = strlen (key) + 1;
ce426f
   union
ce426f
   {
ce426f
@@ -138,7 +137,7 @@ addgetnetgrentX (struct database_dyn *db
ce426f
     }
ce426f
 
ce426f
   memset (&data, '\0', sizeof (data));
ce426f
-  buffer = alloca (buflen);
ce426f
+  buffer = xmalloc (buflen);
ce426f
   first_needed.elem.next = &first_needed.elem;
ce426f
   memcpy (first_needed.elem.name, key, group_len);
ce426f
   data.needed_groups = &first_needed.elem;
ce426f
@@ -218,21 +217,24 @@ addgetnetgrentX (struct database_dyn *db
ce426f
 
ce426f
 				if (buflen - req->key_len - bufused < needed)
ce426f
 				  {
ce426f
-				    size_t newsize = MAX (2 * buflen,
ce426f
-							  buflen + 2 * needed);
ce426f
-				    if (use_malloc || newsize > 1024 * 1024)
ce426f
-				      {
ce426f
-					buflen = newsize;
ce426f
-					char *newbuf = xrealloc (use_malloc
ce426f
-								 ? buffer
ce426f
-								 : NULL,
ce426f
-								 buflen);
ce426f
-
ce426f
-					buffer = newbuf;
ce426f
-					use_malloc = true;
ce426f
-				      }
ce426f
-				    else
ce426f
-				      extend_alloca (buffer, buflen, newsize);
ce426f
+				    buflen += MAX (buflen, 2 * needed);
ce426f
+				    /* Save offset in the old buffer.  We don't
ce426f
+				       bother with the NULL check here since
ce426f
+				       we'll do that later anyway.  */
ce426f
+				    size_t nhostdiff = nhost - buffer;
ce426f
+				    size_t nuserdiff = nuser - buffer;
ce426f
+				    size_t ndomaindiff = ndomain - buffer;
ce426f
+
ce426f
+				    char *newbuf = xrealloc (buffer, buflen);
ce426f
+				    /* Fix up the triplet pointers into the new
ce426f
+				       buffer.  */
ce426f
+				    nhost = (nhost ? newbuf + nhostdiff
ce426f
+					     : NULL);
ce426f
+				    nuser = (nuser ? newbuf + nuserdiff
ce426f
+					     : NULL);
ce426f
+				    ndomain = (ndomain ? newbuf + ndomaindiff
ce426f
+					       : NULL);
ce426f
+				    buffer = newbuf;
ce426f
 				  }
ce426f
 
ce426f
 				nhost = memcpy (buffer + bufused,
ce426f
@@ -299,18 +301,8 @@ addgetnetgrentX (struct database_dyn *db
ce426f
 		      }
ce426f
 		    else if (status == NSS_STATUS_UNAVAIL && e == ERANGE)
ce426f
 		      {
ce426f
-			size_t newsize = 2 * buflen;
ce426f
-			if (use_malloc || newsize > 1024 * 1024)
ce426f
-			  {
ce426f
-			    buflen = newsize;
ce426f
-			    char *newbuf = xrealloc (use_malloc
ce426f
-						     ? buffer : NULL, buflen);
ce426f
-
ce426f
-			    buffer = newbuf;
ce426f
-			    use_malloc = true;
ce426f
-			  }
ce426f
-			else
ce426f
-			  extend_alloca (buffer, buflen, newsize);
ce426f
+			buflen *= 2;
ce426f
+			buffer = xrealloc (buffer, buflen);
ce426f
 		      }
ce426f
 		  }
ce426f
 
ce426f
@@ -446,8 +438,7 @@ addgetnetgrentX (struct database_dyn *db
ce426f
     }
ce426f
 
ce426f
  out:
ce426f
-  if (use_malloc)
ce426f
-    free (buffer);
ce426f
+  free (buffer);
ce426f
 
ce426f
   *resultp = dataset;
ce426f