summary refs log tree commit diff
path: root/nscd
diff options
context:
space:
mode:
authorFlorian Weimer <fweimer@redhat.com>2018-06-25 16:05:46 +0200
committerFlorian Weimer <fweimer@redhat.com>2018-06-25 18:41:54 +0200
commit6b7b2abac75f969a86c537d64adf003378e24113 (patch)
tree2a21c31d51b43cabd497965a4cfd88f2ea674b61 /nscd
parent2f9f0d182eb87bfab49534d4f9ac102d6c0c0469 (diff)
downloadglibc-6b7b2abac75f969a86c537d64adf003378e24113.tar.gz
glibc-6b7b2abac75f969a86c537d64adf003378e24113.tar.xz
glibc-6b7b2abac75f969a86c537d64adf003378e24113.zip
nscd: Switch to struct scratch_buffer in adhstaiX [BZ #18023]
The pre-allocation of the three scratch buffers increased the initial
stack size somewhat, but if retries are needed, the previous version
used more stack space if extend_alloca could not merge allocations.
Lack of alloca accounting also means could be problematic with
extremely large NSS responses, too.

	[BZ #18023]
	* nscd/aicache.c (addhstaiX): Use struct scratch_buffer instead
	of extend_alloca.
Diffstat (limited to 'nscd')
-rw-r--r--nscd/aicache.c79
1 files changed, 45 insertions, 34 deletions
diff --git a/nscd/aicache.c b/nscd/aicache.c
index 2095edf911..439e0ea126 100644
--- a/nscd/aicache.c
+++ b/nscd/aicache.c
@@ -28,6 +28,7 @@
 #include <resolv/resolv-internal.h>
 #include <resolv/resolv_context.h>
 #include <resolv/res_use_inet6.h>
+#include <scratch_buffer.h>
 
 #include "dbg_log.h"
 #include "nscd.h"
@@ -108,10 +109,13 @@ addhstaiX (struct database_dyn *db, int fd, request_header *req,
   if (ctx == NULL)
     no_more = 1;
 
-  size_t tmpbuf6len = 1024;
-  char *tmpbuf6 = alloca (tmpbuf6len);
-  size_t tmpbuf4len = 0;
-  char *tmpbuf4 = NULL;
+  struct scratch_buffer tmpbuf6;
+  scratch_buffer_init (&tmpbuf6);
+  struct scratch_buffer tmpbuf4;
+  scratch_buffer_init (&tmpbuf4);
+  struct scratch_buffer canonbuf;
+  scratch_buffer_init (&canonbuf);
+
   int32_t ttl = INT32_MAX;
   ssize_t total = 0;
   char *key_copy = NULL;
@@ -124,6 +128,7 @@ addhstaiX (struct database_dyn *db, int fd, request_header *req,
       int status[2] = { NSS_STATUS_UNAVAIL, NSS_STATUS_UNAVAIL };
       int naddrs = 0;
       size_t addrslen = 0;
+
       char *canon = NULL;
       size_t canonlen;
 
@@ -138,12 +143,17 @@ addhstaiX (struct database_dyn *db, int fd, request_header *req,
 	      at = &atmem;
 	      rc6 = 0;
 	      herrno = 0;
-	      status[1] = DL_CALL_FCT (fct4, (key, &at, tmpbuf6, tmpbuf6len,
+	      status[1] = DL_CALL_FCT (fct4, (key, &at,
+					      tmpbuf6.data, tmpbuf6.length,
 					      &rc6, &herrno, &ttl));
 	      if (rc6 != ERANGE || (herrno != NETDB_INTERNAL
 				    && herrno != TRY_AGAIN))
 		break;
-	      tmpbuf6 = extend_alloca (tmpbuf6, tmpbuf6len, 2 * tmpbuf6len);
+	      if (!scratch_buffer_grow (&tmpbuf6))
+		{
+		  rc6 = ENOMEM;
+		  break;
+		}
 	    }
 
 	  if (rc6 != 0 && herrno == NETDB_INTERNAL)
@@ -221,41 +231,38 @@ addhstaiX (struct database_dyn *db, int fd, request_header *req,
 	  while (1)
 	    {
 	      rc6 = 0;
-	      status[0] = DL_CALL_FCT (fct, (key, AF_INET6, &th[0], tmpbuf6,
-					     tmpbuf6len, &rc6, &herrno, &ttl,
+	      status[0] = DL_CALL_FCT (fct, (key, AF_INET6, &th[0],
+					     tmpbuf6.data, tmpbuf6.length,
+					     &rc6, &herrno, &ttl,
 					     &canon));
 	      if (rc6 != ERANGE || herrno != NETDB_INTERNAL)
 		break;
-	      tmpbuf6 = extend_alloca (tmpbuf6, tmpbuf6len, 2 * tmpbuf6len);
+	      if (!scratch_buffer_grow (&tmpbuf6))
+		{
+		  rc6 = ENOMEM;
+		  break;
+		}
 	    }
 
 	  if (rc6 != 0 && herrno == NETDB_INTERNAL)
 	    goto out;
 
-	  /* If the IPv6 lookup has been successful do not use the
-	     buffer used in that lookup, use a new one.  */
-	  if (status[0] == NSS_STATUS_SUCCESS && rc6 == 0)
-	    {
-	      tmpbuf4len = 512;
-	      tmpbuf4 = alloca (tmpbuf4len);
-	    }
-	  else
-	    {
-	      tmpbuf4len = tmpbuf6len;
-	      tmpbuf4 = tmpbuf6;
-	    }
-
 	  /* Next collect IPv4 information.  */
 	  while (1)
 	    {
 	      rc4 = 0;
-	      status[1] = DL_CALL_FCT (fct, (key, AF_INET, &th[1], tmpbuf4,
-					     tmpbuf4len, &rc4, &herrno,
+	      status[1] = DL_CALL_FCT (fct, (key, AF_INET, &th[1],
+					     tmpbuf4.data, tmpbuf4.length,
+					     &rc4, &herrno,
 					     ttl == INT32_MAX ? &ttl : NULL,
 					     canon == NULL ? &canon : NULL));
 	      if (rc4 != ERANGE || herrno != NETDB_INTERNAL)
 		break;
-	      tmpbuf4 = extend_alloca (tmpbuf4, tmpbuf4len, 2 * tmpbuf4len);
+	      if (!scratch_buffer_grow (&tmpbuf4))
+		{
+		  rc4 = ENOMEM;
+		  break;
+		}
 	    }
 
 	  if (rc4 != 0 && herrno == NETDB_INTERNAL)
@@ -281,13 +288,11 @@ addhstaiX (struct database_dyn *db, int fd, request_header *req,
 	      cfct = __nss_lookup_function (nip, "getcanonname_r");
 	      if (cfct != NULL)
 		{
-		  const size_t max_fqdn_len = 256;
-		  char *buf = alloca (max_fqdn_len);
 		  char *s;
 		  int rc;
 
-		  if (DL_CALL_FCT (cfct, (key, buf, max_fqdn_len, &s,
-					  &rc, &herrno))
+		  if (DL_CALL_FCT (cfct, (key, canonbuf.data, canonbuf.length,
+					  &s, &rc, &herrno))
 		      == NSS_STATUS_SUCCESS)
 		    canon = s;
 		  else
@@ -316,18 +321,20 @@ addhstaiX (struct database_dyn *db, int fd, request_header *req,
 		      addrfamily = AF_INET6;
 		    }
 
-		  size_t tmpbuflen = 512;
-		  char *tmpbuf = alloca (tmpbuflen);
 		  int rc;
 		  while (1)
 		    {
 		      rc = __gethostbyaddr2_r (addr, addrlen, addrfamily,
-					       &hstent_mem, tmpbuf, tmpbuflen,
+					       &hstent_mem,
+					       canonbuf.data, canonbuf.length,
 					       &hstent, &herrno, NULL);
 		      if (rc != ERANGE || herrno != NETDB_INTERNAL)
 			break;
-		      tmpbuf = extend_alloca (tmpbuf, tmpbuflen,
-					      tmpbuflen * 2);
+		      if (!scratch_buffer_grow (&canonbuf))
+			{
+			  rc = ENOMEM;
+			  break;
+			}
 		    }
 
 		  if (rc == 0)
@@ -531,6 +538,10 @@ next_nip:
 	dh->usable = false;
     }
 
+  scratch_buffer_free (&tmpbuf6);
+  scratch_buffer_free (&tmpbuf4);
+  scratch_buffer_free (&canonbuf);
+
   return timeout;
 }