summary refs log tree commit diff
diff options
context:
space:
mode:
authorJeff Law <law@redhat.com>2012-03-29 09:56:27 -0600
committerJeff Law <law@redhat.com>2012-03-29 09:56:27 -0600
commit984a42374ce2055836f580c2240306171757ea72 (patch)
tree1d6442623675711d32c962ee9bb69dbb3bd8dd69
parent88d85d4f001fac0fd7ef4e3d05ca8a7d50b0c98f (diff)
downloadglibc-984a42374ce2055836f580c2240306171757ea72.tar.gz
glibc-984a42374ce2055836f580c2240306171757ea72.tar.xz
glibc-984a42374ce2055836f580c2240306171757ea72.zip
[BZ #13761]
	* nis/nss_compat/compat-initgroups.c (getgrent_next_nss,
	_nss_compat_initgroups_dyn): Fall back to malloc/free for
	large group memberships.
-rw-r--r--ChangeLog7
-rw-r--r--NEWS6
-rw-r--r--nis/nss_compat/compat-initgroups.c74
3 files changed, 69 insertions, 18 deletions
diff --git a/ChangeLog b/ChangeLog
index 23b72905f5..165a178076 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2012-03-28  Siddhesh Poyarekar  <siddhesh@redhat.com>
+
+	[BZ #13761]
+	* nis/nss_compat/compat-initgroups.c (getgrent_next_nss,
+	_nss_compat_initgroups_dyn): Fall back to malloc/free
+	for large group memberships.
+
 2012-03-28  David S. Miller  <davem@davemloft.net>
 
 	* sysdeps/sparc/sparc32/memcpy.S: Implement mempcpy using a stub
diff --git a/NEWS b/NEWS
index ec8ecdb45d..612acc8581 100644
--- a/NEWS
+++ b/NEWS
@@ -16,9 +16,9 @@ Version 2.16
   11494, 12047, 13058, 13525, 13526, 13527, 13528, 13529, 13530, 13531,
   13532, 13533, 13547, 13551, 13552, 13553, 13555, 13559, 13566, 13583,
   13618, 13637, 13656, 13658, 13673, 13695, 13704, 13706, 13726, 13738,
-  13760, 13786, 13792, 13806, 13824, 13840, 13841, 13844, 13846, 13851,
-  13852, 13854, 13871, 13879, 13883, 13892, 13910, 13911, 13912, 13913,
-  13915, 13916, 13917, 13918, 13919, 13920, 13921
+  13760, 13761, 13786, 13792, 13806, 13824, 13840, 13841, 13844, 13846,
+  13851, 13852, 13854, 13871, 13879, 13883, 13892, 13910, 13911, 13912,
+  13913, 13915, 13916, 13917, 13918, 13919, 13920, 13921
 
 * ISO C11 support:
 
diff --git a/nis/nss_compat/compat-initgroups.c b/nis/nss_compat/compat-initgroups.c
index a70d66df8b..4aa23fda18 100644
--- a/nis/nss_compat/compat-initgroups.c
+++ b/nis/nss_compat/compat-initgroups.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1998-2004,2006,2007,2009,2010 Free Software Foundation, Inc.
+/* Copyright (C) 1998-2004,2006,2007,2009,2010,2012 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Thorsten Kukuk <kukuk@suse.de>, 1998.
 
@@ -296,6 +296,8 @@ getgrent_next_nss (ent_t *ent, char *buffer, size_t buflen, const char *user,
       if (nss_initgroups_dyn (user, group, &mystart, &mysize, &mygroups,
 			      limit, errnop) == NSS_STATUS_SUCCESS)
 	{
+	  status = NSS_STATUS_NOTFOUND;
+
 	  /* If there is no blacklist we can trust the underlying
 	     initgroups implementation.  */
 	  if (ent->blacklist.current <= 1)
@@ -308,6 +310,7 @@ getgrent_next_nss (ent_t *ent, char *buffer, size_t buflen, const char *user,
 		 overwrite the pointer with one to a bigger buffer.  */
 	      char *tmpbuf = buffer;
 	      size_t tmplen = buflen;
+	      bool use_malloc = false;
 
 	      for (int i = 0; i < mystart; i++)
 		{
@@ -315,21 +318,36 @@ getgrent_next_nss (ent_t *ent, char *buffer, size_t buflen, const char *user,
 						   tmpbuf, tmplen, errnop))
 			 == NSS_STATUS_TRYAGAIN
 			 && *errnop == ERANGE)
-		    if (tmpbuf == buffer)
-		      {
-			tmplen *= 2;
-			tmpbuf = __alloca (tmplen);
-		      }
-		    else
-		      tmpbuf = extend_alloca (tmpbuf, tmplen, 2 * tmplen);
+                    {
+                      if (__libc_use_alloca (tmplen * 2))
+                        {
+                          if (tmpbuf == buffer)
+                            {
+                              tmplen *= 2;
+                              tmpbuf = __alloca (tmplen);
+                            }
+                          else
+                            tmpbuf = extend_alloca (tmpbuf, tmplen, tmplen * 2);
+                        }
+                      else
+                        {
+                          tmplen *= 2;
+                          char *newbuf = realloc (use_malloc ? tmpbuf : NULL, tmplen);
+
+                          if (newbuf == NULL)
+                            {
+                              status = NSS_STATUS_TRYAGAIN;
+			      goto done;
+                            }
+                          use_malloc = true;
+                          tmpbuf = newbuf;
+                        }
+                    }
 
 		  if (__builtin_expect  (status != NSS_STATUS_NOTFOUND, 1))
 		    {
 		      if (__builtin_expect  (status != NSS_STATUS_SUCCESS, 0))
-			{
-			  free (mygroups);
-			  return status;
-			}
+		        goto done;
 
 		      if (!in_blacklist (grpbuf.gr_name,
 					 strlen (grpbuf.gr_name), ent)
@@ -347,11 +365,17 @@ getgrent_next_nss (ent_t *ent, char *buffer, size_t buflen, const char *user,
 			}
 		    }
 		}
+
+	      status = NSS_STATUS_NOTFOUND;
+
+ done:
+	      if (use_malloc)
+	        free (tmpbuf);
 	    }
 
 	  free (mygroups);
 
-	  return NSS_STATUS_NOTFOUND;
+	  return status;
 	}
 
       free (mygroups);
@@ -508,6 +532,7 @@ _nss_compat_initgroups_dyn (const char *user, gid_t group, long int *start,
   char *tmpbuf;
   enum nss_status status;
   ent_t intern = { true, false, false, NULL, {NULL, 0, 0} };
+  bool use_malloc = false;
 
   status = internal_setgrent (&intern);
   if (status != NSS_STATUS_SUCCESS)
@@ -521,13 +546,32 @@ _nss_compat_initgroups_dyn (const char *user, gid_t group, long int *start,
 					    user, group, start, size,
 					    groupsp, limit, errnop))
 	     == NSS_STATUS_TRYAGAIN && *errnop == ERANGE)
-	tmpbuf = extend_alloca (tmpbuf, buflen, 2 * buflen);
+        if (__libc_use_alloca (buflen * 2))
+          tmpbuf = extend_alloca (tmpbuf, buflen, 2 * buflen);
+        else
+          {
+            buflen *= 2;
+            char *newbuf = realloc (use_malloc ? tmpbuf : NULL, buflen);
+            if (newbuf == NULL)
+              {
+                status = NSS_STATUS_TRYAGAIN;
+                goto done;
+              }
+            use_malloc = true;
+            tmpbuf = newbuf;
+          }
     }
   while (status == NSS_STATUS_SUCCESS);
 
+  status = NSS_STATUS_SUCCESS;
+
+ done:
+  if (use_malloc)
+    free (tmpbuf);
+
   internal_endgrent (&intern);
 
-  return NSS_STATUS_SUCCESS;
+  return status;
 }