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