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