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.
This commit is contained in:
Florian Weimer 2018-06-25 16:05:46 +02:00
parent 2f9f0d182e
commit 6b7b2abac7
2 changed files with 51 additions and 34 deletions

View File

@ -1,3 +1,9 @@
2018-06-25 Florian Weimer <fweimer@redhat.com>
[BZ #18023]
* nscd/aicache.c (addhstaiX): Use struct scratch_buffer instead
of extend_alloca.
2018-06-25 Florian Weimer <fweimer@redhat.com>
[BZ #18023]

View File

@ -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;
}