summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorian Weimer <fweimer@redhat.com>2015-03-01 18:59:48 +0100
committerFlorian Weimer <fweimer@redhat.com>2016-04-25 06:19:30 +0200
commit4e10cf98c38e471f1c0637150c51fa2935b271fa (patch)
treea544092d359154150e288955ebba9fdd776df154
parent4e0898ab1bd8502cf4acbbe82c1755127b561ae8 (diff)
downloadglibc-4e10cf98c38e471f1c0637150c51fa2935b271fa.tar.gz
nscd: Switch to struct scratch_buffer in adhstaiX
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.
-rw-r--r--nscd/aicache.c79
1 files changed, 45 insertions, 34 deletions
diff --git a/nscd/aicache.c b/nscd/aicache.c
index a2e6cf8475..e181fdc5c3 100644
--- a/nscd/aicache.c
+++ b/nscd/aicache.c
@@ -26,6 +26,7 @@
#include <unistd.h>
#include <sys/mman.h>
#include <resolv/res_hconf.h>
+#include <scratch_buffer.h>
#include "dbg_log.h"
#include "nscd.h"
@@ -113,10 +114,13 @@ addhstaiX (struct database_dyn *db, int fd, request_header *req,
int old_res_options = _res.options;
_res.options &= ~RES_USE_INET6;
- 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;
@@ -129,6 +133,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;
@@ -143,12 +148,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)
@@ -226,41 +236,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)
@@ -286,13 +293,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
@@ -321,18 +326,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)
@@ -560,6 +567,10 @@ next_nip:
dh->usable = false;
}
+ scratch_buffer_free (&tmpbuf6);
+ scratch_buffer_free (&tmpbuf4);
+ scratch_buffer_free (&canonbuf);
+
return timeout;
}