summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorian Weimer <fweimer@redhat.com>2018-06-25 18:56:42 +0200
committerFlorian Weimer <fweimer@redhat.com>2018-06-25 18:58:49 +0200
commit90d9d9ce2fbeef0f24a957efa83f5a78367a84d4 (patch)
tree05ebd40e8bb0e922dcedfabb37e1084b24de41b7
parent6b7b2abac75f969a86c537d64adf003378e24113 (diff)
downloadglibc-90d9d9ce2fbeef0f24a957efa83f5a78367a84d4.tar.gz
getgrent_next_nss (compat-initgroups): Remove alloca fallback [BZ #18023]
If the caller-supplied buffer is not large enough, fall back directly malloc. The previous __libc_use_alloca check was incorrect because it did not take into account that extend_alloca may fail to merge allocations, so it would underestimate the stack space being used by roughly a factor of two.
-rw-r--r--ChangeLog6
-rw-r--r--nss/nss_compat/compat-initgroups.c46
2 files changed, 27 insertions, 25 deletions
diff --git a/ChangeLog b/ChangeLog
index 1cafbb1882..6241a6369a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,6 +1,12 @@
2018-06-25 Florian Weimer <fweimer@redhat.com>
[BZ #18023]
+ * nss/nss_compat/compat-initgroups.c (getgrent_next_nss): Fall
+ back to malloc directly, without stack allocations.
+
+2018-06-25 Florian Weimer <fweimer@redhat.com>
+
+ [BZ #18023]
* nscd/aicache.c (addhstaiX): Use struct scratch_buffer instead
of extend_alloca.
diff --git a/nss/nss_compat/compat-initgroups.c b/nss/nss_compat/compat-initgroups.c
index 74414f4622..540eee863c 100644
--- a/nss/nss_compat/compat-initgroups.c
+++ b/nss/nss_compat/compat-initgroups.c
@@ -261,7 +261,6 @@ 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++)
{
@@ -270,29 +269,26 @@ getgrent_next_nss (ent_t *ent, char *buffer, size_t buflen, const char *user,
== NSS_STATUS_TRYAGAIN
&& *errnop == ERANGE)
{
- 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;
- }
+ /* Check for overflow. */
+ if (__glibc_unlikely (tmplen * 2 < tmplen))
+ {
+ __set_errno (ENOMEM);
+ status = NSS_STATUS_TRYAGAIN;
+ goto done;
+ }
+ /* Increase the size. Make sure that we retry
+ with a reasonable size. */
+ tmplen *= 2;
+ if (tmplen < 1024)
+ tmplen = 1024;
+ if (tmpbuf != buffer)
+ free (tmpbuf);
+ tmpbuf = malloc (tmplen);
+ if (__glibc_unlikely (tmpbuf == NULL))
+ {
+ status = NSS_STATUS_TRYAGAIN;
+ goto done;
+ }
}
if (__builtin_expect (status != NSS_STATUS_NOTFOUND, 1))
@@ -320,7 +316,7 @@ getgrent_next_nss (ent_t *ent, char *buffer, size_t buflen, const char *user,
status = NSS_STATUS_NOTFOUND;
done:
- if (use_malloc)
+ if (tmpbuf != buffer)
free (tmpbuf);
}