forked from rpms/glibc
67108a5592
Upstream commit: 11c4f5010c58029e73e656d5df4f8f42c9b8e877 - crypt: Use NSPR header files in addition to NSS header files (#1489339) - math: Fix yn(n,0) without SVID wrapper (swbz#22244) - math: Fix log2(0) and log(10) in downward rounding (swbz#22243) - math: Add C++ versions of iscanonical for ldbl-96, ldbl-128ibm (swbz#22235) - powerpc: Optimize memrchr for power8 - Hide various internal functions (swbz#18822)
1704 lines
50 KiB
Diff
1704 lines
50 KiB
Diff
From the upstream branch fw/extend_alloca.
|
|
|
|
commit dc79f9aa56933dc8b475209f9a4059965b50ea26
|
|
Author: Florian Weimer <fweimer@redhat.com>
|
|
Date: Sun Mar 1 18:29:47 2015 +0100
|
|
|
|
nscd restart: Use malloc instead of extend_alloca
|
|
|
|
This introduces a separate function, read_cmdline, which reads the
|
|
contents of /proc/self/cmdline into a heap-allocated buffer.
|
|
|
|
[BZ #18023]
|
|
* nscd/connections.c (read_cmdline): New function.
|
|
(restart): Use it. Update comment.
|
|
|
|
commit 9bed8b7fca7867d3027b66ce3985a75136aed013
|
|
Author: Florian Weimer <fweimer@redhat.com>
|
|
Date: Sun Mar 1 15:14:19 2015 +0100
|
|
|
|
getgrent_next_nss (compat-initgroups): Remove alloca fallback
|
|
|
|
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.
|
|
|
|
[BZ #18023]
|
|
* nis/nss_compat/compat-initgroups.c (getgrent_next_nss): Fall
|
|
back to malloc directly, without stack allocations.
|
|
|
|
commit c95cc759ecb21f812872934ac55518aef28cf46b
|
|
Author: Florian Weimer <fweimer@redhat.com>
|
|
Date: Sun Mar 1 16:03:01 2015 +0100
|
|
|
|
_dl_map_object_deps: Use struct scratch_buffer instead of extend_alloca
|
|
|
|
The function comment suggests that _dl_map_object_deps cannot use
|
|
malloc, but it already allocates the l_initfini array on the heap, so
|
|
the additional allocation should be acceptable.
|
|
|
|
[BZ #18023]
|
|
* elf/dl-deps.c (_dl_map_object_deps): Use struct
|
|
scratch_buffer instead of extend_alloca.
|
|
|
|
commit e38bff4db6f03d1fab732737f43a25160c3e4703
|
|
Author: Florian Weimer <fweimer@redhat.com>
|
|
Date: Sun Mar 1 16:18:21 2015 +0100
|
|
|
|
_nss_nis_initgroups_dyn: Use struct scratch_buffer instead of extend_alloca
|
|
|
|
Also adjusts the internal function get_uid.
|
|
|
|
[BZ #18023]
|
|
* nis/nss_nis/nis-initgroups.c (get_uid, _nss_nis_initgroups_dyn):
|
|
Use struct scratch_buffer instead of extend_alloca.
|
|
|
|
commit 8825d4709a686a870d313cc602d489ddd5354a08
|
|
Author: Florian Weimer <fweimer@redhat.com>
|
|
Date: Sun Mar 1 18:55:33 2015 +0100
|
|
|
|
nscd: Use struct scratch_buffer instead of extend_alloca in most caches
|
|
|
|
This replaces the ERANGE retry loops with loops which have heap
|
|
fallback. Heap allocation might actually be required for extremely
|
|
large NSS results.
|
|
|
|
[BZ #18023]
|
|
* nscd/grpcache.c (addgrbyX): Use struct scratch_buffer instead
|
|
of extend_alloca.
|
|
* nscd/hstcache.c (addhstbyX): Likewise.
|
|
* nscd/pwdcache.c (addpwbyX): Likewise.
|
|
* nscd/servicescache.c (addservbyX): Likewise.
|
|
|
|
commit 140d8711d446f5193b04b56e714ddf8d0eddbf62
|
|
Author: Florian Weimer <fweimer@redhat.com>
|
|
Date: Sun Mar 1 18:59:48 2015 +0100
|
|
|
|
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.
|
|
|
|
commit 1af14faef808f03276766e5ee6d9ee7dc9053fba
|
|
Author: Florian Weimer <fweimer@redhat.com>
|
|
Date: Sun Mar 1 19:03:01 2015 +0100
|
|
|
|
getent: Switch to struct scratch_buffer in initgroups_keys
|
|
|
|
The retry loop is slightly different here because getgrouplist
|
|
provides size information, so scratch_buffer_set_array_size can be
|
|
used to grow the buffer in a more precise fashion.
|
|
|
|
[BZ #18023]
|
|
* nss/getent.c (initgroups_keys): Use struct scratch_buffer
|
|
instead of extend_alloca.
|
|
|
|
commit 9b71d3b4df6dd4e49f7638d1d936c921c50fa3d9
|
|
Author: Florian Weimer <fweimer@redhat.com>
|
|
Date: Sun Mar 1 19:09:00 2015 +0100
|
|
|
|
nss_files: Use struct scratch_buffer instead of extend_alloca
|
|
|
|
In both _nss_files_gethostbyname3_r and _nss_files_initgroups_dyn,
|
|
__libc_use_alloca was misused because it was not taken into account
|
|
that extend_alloca can fail to merge allocations.
|
|
|
|
[BZ #18023]
|
|
* nss/nss_files/files-hosts.c (_nss_files_gethostbyname3_r):
|
|
Use struct scratch_buffer instead of extend_alloca.
|
|
* nss/nss_files/files-initgroups.c (_nss_files_initgroups_dyn):
|
|
Likewise.
|
|
|
|
commit 11c2a8bad9ca5fe510b73c0204b3dcf703f14d5c
|
|
Author: Florian Weimer <fweimer@redhat.com>
|
|
Date: Sun Mar 1 19:11:55 2015 +0100
|
|
|
|
gethostid (Linux variant): Switch to struct scratch_buffer
|
|
|
|
Previously, extend_alloca was used without alloca accounting,
|
|
which could have been problematic with large NSS results.
|
|
|
|
[BZ #18023]
|
|
* sysdeps/unix/sysv/linux/gethostid.c (gethostid): Use struct
|
|
scratch_buffer instead of extend_alloca.
|
|
|
|
commit 6de00dd8a3a76d0b7586393451e65ad6c2721a71
|
|
Author: Florian Weimer <fweimer@redhat.com>
|
|
Date: Sun Mar 1 19:14:29 2015 +0100
|
|
|
|
getlogin_r (Linux variant): Switch to struct scratch_buffer
|
|
|
|
This corrects the alloca accounting as a side effect. It was not off
|
|
if extend_alloca failed to merge allocations.
|
|
|
|
[BZ #18023]
|
|
* sysdeps/unix/sysv/linux/getlogin_r.c (__getlogin_r_loginuid):
|
|
Use struct scratch_buffer instead of extend_alloca.
|
|
|
|
commit 488063238ee5c87b66c6982b1b6d508e30e44386
|
|
Author: Florian Weimer <fweimer@redhat.com>
|
|
Date: Sun Mar 1 19:48:31 2015 +0100
|
|
|
|
wordexp: Rewrite parse_tilde to use struct scratch_buffer
|
|
|
|
[BZ #18023]
|
|
* posix/wordexp.c (parse_tilde): Use struct scratch_buffer
|
|
instead of extend_alloca.
|
|
|
|
commit 683543bbb3e2c1b17554c4096d00c2980f39a802
|
|
Author: Florian Weimer <fweimer@redhat.com>
|
|
Date: Sun Mar 1 23:22:45 2015 +0100
|
|
|
|
Remove macros extend_alloca, extend_alloca_account [BZ #18023]
|
|
|
|
And also the helper macro stackinfo_alloca_round.
|
|
|
|
extend_alloca simply does not work on x86_64 and current i386 because
|
|
its peculiar stack alignment rules.
|
|
|
|
Here's an analysis of the _dl_fini situation (before the removal of
|
|
extend_alloca).
|
|
|
|
Dump of assembler code for function _dl_fini:
|
|
<+0>: push %rbp
|
|
<+1>: mov %rsp,%rbp
|
|
<+4>: push %r15
|
|
<+6>: push %r14
|
|
<+8>: push %r13
|
|
<+10>: push %r12
|
|
<+12>: push %rbx
|
|
<+13>: sub $0x38,%rsp
|
|
|
|
The function pushes 6 registers on the stack and allocates 0x38 bytes,
|
|
which means that %rsp is a multiple of 16 after function prologue.
|
|
|
|
The initial alloca allocation does not change %rsp alignment:
|
|
|
|
<+210>: shr $0x4,%rcx
|
|
<+214>: shl $0x4,%rcx
|
|
<+218>: sub %rcx,%rsp
|
|
|
|
%r15 is the address of the previous stack allocation, it is used below.
|
|
|
|
This is the extend_alloca reallocation branch:
|
|
|
|
<+734>: add $0xf,%rdx
|
|
<+738>: and $0xfffffffffffffff0,%rdx
|
|
<+742>: lea 0x1e(%rdx),%rcx
|
|
<+746>: shr $0x4,%rcx
|
|
<+750>: shl $0x4,%rcx
|
|
<+754>: sub %rcx,%rsp
|
|
<+757>: lea 0xf(%rsp),%rcx
|
|
<+762>: and $0xfffffffffffffff0,%rcx
|
|
<+766>: lea (%rcx,%rdx,1),%rsi
|
|
<+770>: cmp %rsi,%r15
|
|
<+773>: je 0x7f963940b673 <_dl_fini+787>
|
|
<+775>: mov %rdx,-0x58(%rbp)
|
|
<+787>: add %rdx,-0x58(%rbp)
|
|
|
|
(a) %rdx, the new requested size, is rounded up to a multiple of 16
|
|
(+734, %+738), and the result is stored in %rdx@738.
|
|
|
|
(b) %rdx@738 + 31 is rounded down to a multiple of 16, the result is
|
|
stored in rcx@750 (+742, +746, +750). So %rcx@750 == %rdx@738 + 16.
|
|
|
|
(c) %rcx@750 bytes are allocated on the stack (+754). %rsp is rounded
|
|
upwards to a multiple of 16, result is stored in %rcx@762 (+757, +762).
|
|
This does not change the value of %rsp because it already was a multiple
|
|
of 16.
|
|
|
|
(d) %rsi@766 == %rcx@762 + %rdx@738 is compared against %r15. But this
|
|
comparison is always false because we allocated 16 extra bytes on the
|
|
stack in (b), which were reserved for the alignment in (c), but in fact
|
|
unused. We are left with a gap in stack usage, and the comparison is
|
|
always false.
|
|
|
|
(@XXX refers to register values after executing the instruction at
|
|
offset +XXX.)
|
|
|
|
If the alignment gap was actually used because of different alignment
|
|
for %rsp, then the comparison failure would still occur because the gap
|
|
would not have been added after this reallocation, but before the
|
|
previous allocation.
|
|
|
|
As a result, extend_alloca is never able to merge allocations. It also
|
|
turns out that the interface is difficult to use, especially in
|
|
cojunction with alloca account (which is rarely optional).
|
|
|
|
[BZ #18023]
|
|
* include/alloca.h (stackinfo_alloca_round, extend_alloca,
|
|
extend_alloca_account): Remove.
|
|
Index: b/elf/dl-deps.c
|
|
===================================================================
|
|
--- a/elf/dl-deps.c
|
|
+++ b/elf/dl-deps.c
|
|
@@ -27,6 +27,7 @@
|
|
#include <unistd.h>
|
|
#include <sys/param.h>
|
|
#include <ldsodefs.h>
|
|
+#include <scratch_buffer.h>
|
|
|
|
#include <dl-dst.h>
|
|
|
|
@@ -184,9 +185,8 @@ _dl_map_object_deps (struct link_map *ma
|
|
/* Pointer to last unique object. */
|
|
tail = &known[nlist - 1];
|
|
|
|
- /* No alloca'd space yet. */
|
|
- struct link_map **needed_space = NULL;
|
|
- size_t needed_space_bytes = 0;
|
|
+ struct scratch_buffer needed_space;
|
|
+ scratch_buffer_init (&needed_space);
|
|
|
|
/* Process each element of the search list, loading each of its
|
|
auxiliary objects and immediate dependencies. Auxiliary objects
|
|
@@ -217,13 +217,12 @@ _dl_map_object_deps (struct link_map *ma
|
|
if (l->l_searchlist.r_list == NULL && l->l_initfini == NULL
|
|
&& l != map && l->l_ldnum > 0)
|
|
{
|
|
- size_t new_size = l->l_ldnum * sizeof (struct link_map *);
|
|
-
|
|
- if (new_size > needed_space_bytes)
|
|
- needed_space
|
|
- = extend_alloca (needed_space, needed_space_bytes, new_size);
|
|
-
|
|
- needed = needed_space;
|
|
+ /* l->l_ldnum includes space for the terminating NULL. */
|
|
+ if (!scratch_buffer_set_array_size
|
|
+ (&needed_space, l->l_ldnum, sizeof (struct link_map *)))
|
|
+ _dl_signal_error (ENOMEM, map->l_name, NULL,
|
|
+ N_("cannot allocate dependency buffer"));
|
|
+ needed = needed_space.data;
|
|
}
|
|
|
|
if (l->l_info[DT_NEEDED] || l->l_info[AUXTAG] || l->l_info[FILTERTAG])
|
|
@@ -463,8 +462,11 @@ _dl_map_object_deps (struct link_map *ma
|
|
struct link_map **l_initfini = (struct link_map **)
|
|
malloc ((2 * nneeded + 1) * sizeof needed[0]);
|
|
if (l_initfini == NULL)
|
|
- _dl_signal_error (ENOMEM, map->l_name, NULL,
|
|
- N_("cannot allocate dependency list"));
|
|
+ {
|
|
+ scratch_buffer_free (&needed_space);
|
|
+ _dl_signal_error (ENOMEM, map->l_name, NULL,
|
|
+ N_("cannot allocate dependency list"));
|
|
+ }
|
|
l_initfini[0] = l;
|
|
memcpy (&l_initfini[1], needed, nneeded * sizeof needed[0]);
|
|
memcpy (&l_initfini[nneeded + 1], l_initfini,
|
|
@@ -482,6 +484,8 @@ _dl_map_object_deps (struct link_map *ma
|
|
}
|
|
|
|
out:
|
|
+ scratch_buffer_free (&needed_space);
|
|
+
|
|
if (errno == 0 && errno_saved != 0)
|
|
__set_errno (errno_saved);
|
|
|
|
Index: b/include/alloca.h
|
|
===================================================================
|
|
--- a/include/alloca.h
|
|
+++ b/include/alloca.h
|
|
@@ -23,57 +23,17 @@ libc_hidden_proto (__libc_alloca_cutoff)
|
|
|
|
#include <allocalim.h>
|
|
|
|
-#ifndef stackinfo_alloca_round
|
|
-# define stackinfo_alloca_round(l) (((l) + 15) & -16)
|
|
-#endif
|
|
-
|
|
-#if _STACK_GROWS_DOWN
|
|
-# define extend_alloca(buf, len, newlen) \
|
|
- (__typeof (buf)) ({ size_t __newlen = stackinfo_alloca_round (newlen); \
|
|
- char *__newbuf = __alloca (__newlen); \
|
|
- if (__newbuf + __newlen == (char *) (buf)) \
|
|
- len += __newlen; \
|
|
- else \
|
|
- len = __newlen; \
|
|
- __newbuf; })
|
|
-#elif _STACK_GROWS_UP
|
|
-# define extend_alloca(buf, len, newlen) \
|
|
- (__typeof (buf)) ({ size_t __newlen = stackinfo_alloca_round (newlen); \
|
|
- char *__newbuf = __alloca (__newlen); \
|
|
- char *__buf = (char *) (buf); \
|
|
- if (__buf + len == __newbuf) \
|
|
- { \
|
|
- len += __newlen; \
|
|
- __newbuf = __buf; \
|
|
- } \
|
|
- else \
|
|
- len = __newlen; \
|
|
- __newbuf; })
|
|
-#else
|
|
-# define extend_alloca(buf, len, newlen) \
|
|
- __alloca (((len) = (newlen)))
|
|
-#endif
|
|
-
|
|
#if defined stackinfo_get_sp && defined stackinfo_sub_sp
|
|
# define alloca_account(size, avar) \
|
|
({ void *old__ = stackinfo_get_sp (); \
|
|
void *m__ = __alloca (size); \
|
|
avar += stackinfo_sub_sp (old__); \
|
|
m__; })
|
|
-# define extend_alloca_account(buf, len, newlen, avar) \
|
|
- ({ void *old__ = stackinfo_get_sp (); \
|
|
- void *m__ = extend_alloca (buf, len, newlen); \
|
|
- avar += stackinfo_sub_sp (old__); \
|
|
- m__; })
|
|
#else
|
|
# define alloca_account(size, avar) \
|
|
({ size_t s__ = (size); \
|
|
avar += s__; \
|
|
__alloca (s__); })
|
|
-# define extend_alloca_account(buf, len, newlen, avar) \
|
|
- ({ size_t s__ = (newlen); \
|
|
- avar += s__; \
|
|
- extend_alloca (buf, len, s__); })
|
|
#endif
|
|
|
|
# endif /* !_ISOMAC */
|
|
Index: b/nss/nss_compat/compat-initgroups.c
|
|
===================================================================
|
|
--- a/nss/nss_compat/compat-initgroups.c
|
|
+++ b/nss/nss_compat/compat-initgroups.c
|
|
@@ -262,7 +262,6 @@ getgrent_next_nss (ent_t *ent, char *buf
|
|
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++)
|
|
{
|
|
@@ -271,29 +270,26 @@ getgrent_next_nss (ent_t *ent, char *buf
|
|
== 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))
|
|
@@ -321,7 +317,7 @@ getgrent_next_nss (ent_t *ent, char *buf
|
|
status = NSS_STATUS_NOTFOUND;
|
|
|
|
done:
|
|
- if (use_malloc)
|
|
+ if (tmpbuf != buffer)
|
|
free (tmpbuf);
|
|
}
|
|
|
|
Index: b/nis/nss_nis/nis-initgroups.c
|
|
===================================================================
|
|
--- a/nis/nss_nis/nis-initgroups.c
|
|
+++ b/nis/nss_nis/nis-initgroups.c
|
|
@@ -16,7 +16,6 @@
|
|
License along with the GNU C Library; if not, see
|
|
<http://www.gnu.org/licenses/>. */
|
|
|
|
-#include <alloca.h>
|
|
#include <ctype.h>
|
|
#include <errno.h>
|
|
#include <grp.h>
|
|
@@ -27,6 +26,7 @@
|
|
#include <rpcsvc/yp.h>
|
|
#include <rpcsvc/ypclnt.h>
|
|
#include <sys/param.h>
|
|
+#include <scratch_buffer.h>
|
|
|
|
#include "nss-nis.h"
|
|
#include <libnsl.h>
|
|
@@ -120,27 +120,30 @@ internal_getgrent_r (struct group *grp,
|
|
static int
|
|
get_uid (const char *user, uid_t *uidp)
|
|
{
|
|
- size_t buflen = sysconf (_SC_GETPW_R_SIZE_MAX);
|
|
- char *buf = (char *) alloca (buflen);
|
|
+ struct scratch_buffer tmpbuf;
|
|
+ scratch_buffer_init (&tmpbuf);
|
|
|
|
while (1)
|
|
{
|
|
struct passwd result;
|
|
struct passwd *resp;
|
|
|
|
- int r = getpwnam_r (user, &result, buf, buflen, &resp);
|
|
+ int r = getpwnam_r (user, &result, tmpbuf.data, tmpbuf.length, &resp);
|
|
if (r == 0 && resp != NULL)
|
|
{
|
|
*uidp = resp->pw_uid;
|
|
+ scratch_buffer_free (&tmpbuf);
|
|
return 0;
|
|
}
|
|
|
|
if (r != ERANGE)
|
|
break;
|
|
|
|
- buf = extend_alloca (buf, buflen, 2 * buflen);
|
|
+ if (!scratch_buffer_grow (&tmpbuf))
|
|
+ return 1;
|
|
}
|
|
|
|
+ scratch_buffer_free (&tmpbuf);
|
|
return 1;
|
|
}
|
|
|
|
@@ -254,8 +257,6 @@ _nss_nis_initgroups_dyn (const char *use
|
|
}
|
|
|
|
struct group grpbuf, *g;
|
|
- size_t buflen = sysconf (_SC_GETPW_R_SIZE_MAX);
|
|
- char *tmpbuf;
|
|
enum nss_status status;
|
|
intern_t intern = { NULL, NULL, 0 };
|
|
gid_t *groups = *groupsp;
|
|
@@ -264,15 +265,21 @@ _nss_nis_initgroups_dyn (const char *use
|
|
if (status != NSS_STATUS_SUCCESS)
|
|
return status;
|
|
|
|
- tmpbuf = __alloca (buflen);
|
|
+ struct scratch_buffer tmpbuf;
|
|
+ scratch_buffer_init (&tmpbuf);
|
|
|
|
while (1)
|
|
{
|
|
while ((status =
|
|
- internal_getgrent_r (&grpbuf, tmpbuf, buflen, errnop,
|
|
+ internal_getgrent_r (&grpbuf, tmpbuf.data, tmpbuf.length, errnop,
|
|
&intern)) == NSS_STATUS_TRYAGAIN
|
|
&& *errnop == ERANGE)
|
|
- tmpbuf = extend_alloca (tmpbuf, buflen, 2 * buflen);
|
|
+ if (!scratch_buffer_grow (&tmpbuf))
|
|
+ {
|
|
+ status = NSS_STATUS_TRYAGAIN;
|
|
+ *errnop = errno;
|
|
+ goto done;
|
|
+ }
|
|
|
|
if (status != NSS_STATUS_SUCCESS)
|
|
{
|
|
@@ -331,6 +338,7 @@ done:
|
|
intern.start = intern.start->next;
|
|
free (intern.next);
|
|
}
|
|
+ scratch_buffer_free (&tmpbuf);
|
|
|
|
return status;
|
|
}
|
|
Index: b/nscd/aicache.c
|
|
===================================================================
|
|
--- 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"
|
|
@@ -111,10 +112,13 @@ addhstaiX (struct database_dyn *db, int
|
|
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;
|
|
@@ -127,6 +131,7 @@ addhstaiX (struct database_dyn *db, int
|
|
int status[2] = { NSS_STATUS_UNAVAIL, NSS_STATUS_UNAVAIL };
|
|
int naddrs = 0;
|
|
size_t addrslen = 0;
|
|
+
|
|
char *canon = NULL;
|
|
size_t canonlen;
|
|
|
|
@@ -141,12 +146,17 @@ addhstaiX (struct database_dyn *db, int
|
|
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)
|
|
@@ -224,41 +234,38 @@ addhstaiX (struct database_dyn *db, int
|
|
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)
|
|
@@ -284,13 +291,11 @@ addhstaiX (struct database_dyn *db, int
|
|
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
|
|
@@ -319,18 +324,20 @@ addhstaiX (struct database_dyn *db, int
|
|
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)
|
|
@@ -559,6 +566,10 @@ next_nip:
|
|
dh->usable = false;
|
|
}
|
|
|
|
+ scratch_buffer_free (&tmpbuf6);
|
|
+ scratch_buffer_free (&tmpbuf4);
|
|
+ scratch_buffer_free (&canonbuf);
|
|
+
|
|
return timeout;
|
|
}
|
|
|
|
Index: b/nscd/connections.c
|
|
===================================================================
|
|
--- a/nscd/connections.c
|
|
+++ b/nscd/connections.c
|
|
@@ -1324,64 +1324,83 @@ request from '%s' [%ld] not handled due
|
|
}
|
|
}
|
|
|
|
-
|
|
-/* Restart the process. */
|
|
-static void
|
|
-restart (void)
|
|
+static char *
|
|
+read_cmdline (size_t *size)
|
|
{
|
|
- /* First determine the parameters. We do not use the parameters
|
|
- passed to main() since in case nscd is started by running the
|
|
- dynamic linker this will not work. Yes, this is not the usual
|
|
- case but nscd is part of glibc and we occasionally do this. */
|
|
- size_t buflen = 1024;
|
|
- char *buf = alloca (buflen);
|
|
- size_t readlen = 0;
|
|
int fd = open ("/proc/self/cmdline", O_RDONLY);
|
|
- if (fd == -1)
|
|
- {
|
|
- dbg_log (_("\
|
|
-cannot open /proc/self/cmdline: %s; disabling paranoia mode"),
|
|
- strerror (errno));
|
|
-
|
|
- paranoia = 0;
|
|
- return;
|
|
+ if (fd < 0)
|
|
+ return NULL;
|
|
+ size_t current = 0;
|
|
+ size_t limit = 1024;
|
|
+ char *buffer = malloc (limit);
|
|
+ if (buffer == NULL)
|
|
+ {
|
|
+ close (fd);
|
|
+ errno = ENOMEM;
|
|
+ return NULL;
|
|
}
|
|
-
|
|
while (1)
|
|
{
|
|
- ssize_t n = TEMP_FAILURE_RETRY (read (fd, buf + readlen,
|
|
- buflen - readlen));
|
|
- if (n == -1)
|
|
+ if (current == limit)
|
|
{
|
|
- dbg_log (_("\
|
|
-cannot read /proc/self/cmdline: %s; disabling paranoia mode"),
|
|
- strerror (errno));
|
|
+ char *newptr;
|
|
+ if (2 * limit < limit
|
|
+ || (newptr = realloc (buffer, 2 * limit)) == NULL)
|
|
+ {
|
|
+ free (buffer);
|
|
+ close (fd);
|
|
+ errno = ENOMEM;
|
|
+ return NULL;
|
|
+ }
|
|
+ buffer = newptr;
|
|
+ limit *= 2;
|
|
+ }
|
|
|
|
+ ssize_t n = TEMP_FAILURE_RETRY (read (fd, buffer + current,
|
|
+ limit - current));
|
|
+ if (n == -1)
|
|
+ {
|
|
+ int e = errno;
|
|
+ free (buffer);
|
|
close (fd);
|
|
- paranoia = 0;
|
|
- return;
|
|
+ errno = e;
|
|
+ return NULL;
|
|
}
|
|
-
|
|
- readlen += n;
|
|
-
|
|
- if (readlen < buflen)
|
|
+ if (n == 0)
|
|
break;
|
|
-
|
|
- /* We might have to extend the buffer. */
|
|
- size_t old_buflen = buflen;
|
|
- char *newp = extend_alloca (buf, buflen, 2 * buflen);
|
|
- buf = memmove (newp, buf, old_buflen);
|
|
+ current += n;
|
|
}
|
|
|
|
close (fd);
|
|
+ *size = current;
|
|
+ return buffer;
|
|
+}
|
|
+
|
|
+
|
|
+/* Restart the process. */
|
|
+static void
|
|
+restart (void)
|
|
+{
|
|
+ /* First determine the parameters. We do not use the parameters
|
|
+ passed to main() because then nscd would would use the system
|
|
+ libc after restarting even if it was started by a non-system
|
|
+ dynamic linker during glibc testing. */
|
|
+ size_t readlen;
|
|
+ char *cmdline = read_cmdline (&readlen);
|
|
+ if (cmdline == NULL)
|
|
+ {
|
|
+ dbg_log (_("\
|
|
+cannot open /proc/self/cmdline: %m; disabling paranoia mode"));
|
|
+ paranoia = 0;
|
|
+ return;
|
|
+ }
|
|
|
|
/* Parse the command line. Worst case scenario: every two
|
|
characters form one parameter (one character plus NUL). */
|
|
char **argv = alloca ((readlen / 2 + 1) * sizeof (argv[0]));
|
|
int argc = 0;
|
|
|
|
- char *cp = buf;
|
|
- while (cp < buf + readlen)
|
|
+ for (char *cp = cmdline; cp < cmdline + readlen;)
|
|
{
|
|
argv[argc++] = cp;
|
|
cp = (char *) rawmemchr (cp, '\0') + 1;
|
|
@@ -1398,6 +1417,7 @@ cannot change to old UID: %s; disabling
|
|
strerror (errno));
|
|
|
|
paranoia = 0;
|
|
+ free (cmdline);
|
|
return;
|
|
}
|
|
|
|
@@ -1409,6 +1429,7 @@ cannot change to old GID: %s; disabling
|
|
|
|
ignore_value (setuid (server_uid));
|
|
paranoia = 0;
|
|
+ free (cmdline);
|
|
return;
|
|
}
|
|
}
|
|
@@ -1426,6 +1447,7 @@ cannot change to old working directory:
|
|
ignore_value (setgid (server_gid));
|
|
}
|
|
paranoia = 0;
|
|
+ free (cmdline);
|
|
return;
|
|
}
|
|
|
|
@@ -1474,6 +1496,7 @@ cannot change to old working directory:
|
|
dbg_log (_("cannot change current working directory to \"/\": %s"),
|
|
strerror (errno));
|
|
paranoia = 0;
|
|
+ free (cmdline);
|
|
|
|
/* Reenable the databases. */
|
|
time_t now = time (NULL);
|
|
Index: b/nscd/grpcache.c
|
|
===================================================================
|
|
--- a/nscd/grpcache.c
|
|
+++ b/nscd/grpcache.c
|
|
@@ -16,7 +16,6 @@
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, see <http://www.gnu.org/licenses/>. */
|
|
|
|
-#include <alloca.h>
|
|
#include <assert.h>
|
|
#include <errno.h>
|
|
#include <error.h>
|
|
@@ -32,6 +31,7 @@
|
|
#include <sys/mman.h>
|
|
#include <sys/socket.h>
|
|
#include <stackinfo.h>
|
|
+#include <scratch_buffer.h>
|
|
|
|
#include "nscd.h"
|
|
#include "dbg_log.h"
|
|
@@ -448,12 +448,12 @@ addgrbyX (struct database_dyn *db, int f
|
|
look again in the table whether the dataset is now available. We
|
|
simply insert it. It does not matter if it is in there twice. The
|
|
pruning function only will look at the timestamp. */
|
|
- size_t buflen = 1024;
|
|
- char *buffer = (char *) alloca (buflen);
|
|
+
|
|
struct group resultbuf;
|
|
struct group *grp;
|
|
- bool use_malloc = false;
|
|
int errval = 0;
|
|
+ struct scratch_buffer tmpbuf;
|
|
+ scratch_buffer_init (&tmpbuf);
|
|
|
|
if (__glibc_unlikely (debug_level > 0))
|
|
{
|
|
@@ -463,43 +463,24 @@ addgrbyX (struct database_dyn *db, int f
|
|
dbg_log (_("Reloading \"%s\" in group cache!"), keystr);
|
|
}
|
|
|
|
- while (lookup (req->type, key, &resultbuf, buffer, buflen, &grp) != 0
|
|
+ while (lookup (req->type, key, &resultbuf,
|
|
+ tmpbuf.data, tmpbuf.length, &grp) != 0
|
|
&& (errval = errno) == ERANGE)
|
|
- {
|
|
- errno = 0;
|
|
-
|
|
- if (__glibc_unlikely (buflen > 32768))
|
|
- {
|
|
- char *old_buffer = buffer;
|
|
- buflen *= 2;
|
|
- buffer = (char *) realloc (use_malloc ? buffer : NULL, buflen);
|
|
- if (buffer == NULL)
|
|
- {
|
|
- /* We ran out of memory. We cannot do anything but
|
|
- sending a negative response. In reality this should
|
|
- never happen. */
|
|
- grp = NULL;
|
|
- buffer = old_buffer;
|
|
-
|
|
- /* We set the error to indicate this is (possibly) a
|
|
- temporary error and that it does not mean the entry
|
|
- is not available at all. */
|
|
- errval = EAGAIN;
|
|
- break;
|
|
- }
|
|
- use_malloc = true;
|
|
- }
|
|
- else
|
|
- /* Allocate a new buffer on the stack. If possible combine it
|
|
- with the previously allocated buffer. */
|
|
- buffer = (char *) extend_alloca (buffer, buflen, 2 * buflen);
|
|
- }
|
|
+ if (!scratch_buffer_grow (&tmpbuf))
|
|
+ {
|
|
+ /* We ran out of memory. We cannot do anything but sending a
|
|
+ negative response. In reality this should never
|
|
+ happen. */
|
|
+ grp = NULL;
|
|
+ /* We set the error to indicate this is (possibly) a temporary
|
|
+ error and that it does not mean the entry is not available
|
|
+ at all. */
|
|
+ errval = EAGAIN;
|
|
+ break;
|
|
+ }
|
|
|
|
time_t timeout = cache_addgr (db, fd, req, keystr, grp, uid, he, dh, errval);
|
|
-
|
|
- if (use_malloc)
|
|
- free (buffer);
|
|
-
|
|
+ scratch_buffer_free (&tmpbuf);
|
|
return timeout;
|
|
}
|
|
|
|
Index: b/nscd/hstcache.c
|
|
===================================================================
|
|
--- a/nscd/hstcache.c
|
|
+++ b/nscd/hstcache.c
|
|
@@ -34,6 +34,7 @@
|
|
#include <arpa/nameser.h>
|
|
#include <sys/mman.h>
|
|
#include <stackinfo.h>
|
|
+#include <scratch_buffer.h>
|
|
|
|
#include "nscd.h"
|
|
#include "dbg_log.h"
|
|
@@ -463,11 +464,8 @@ addhstbyX (struct database_dyn *db, int
|
|
look again in the table whether the dataset is now available. We
|
|
simply insert it. It does not matter if it is in there twice. The
|
|
pruning function only will look at the timestamp. */
|
|
- int buflen = 1024;
|
|
- char *buffer = (char *) alloca (buflen);
|
|
struct hostent resultbuf;
|
|
struct hostent *hst;
|
|
- bool use_malloc = false;
|
|
int errval = 0;
|
|
int32_t ttl = INT32_MAX;
|
|
|
|
@@ -487,46 +485,30 @@ addhstbyX (struct database_dyn *db, int
|
|
dbg_log (_("Reloading \"%s\" in hosts cache!"), (char *) str);
|
|
}
|
|
|
|
- while (lookup (req->type, key, &resultbuf, buffer, buflen, &hst, &ttl) != 0
|
|
+ struct scratch_buffer tmpbuf;
|
|
+ scratch_buffer_init (&tmpbuf);
|
|
+
|
|
+ while (lookup (req->type, key, &resultbuf,
|
|
+ tmpbuf.data, tmpbuf.length, &hst, &ttl) != 0
|
|
&& h_errno == NETDB_INTERNAL
|
|
&& (errval = errno) == ERANGE)
|
|
- {
|
|
- errno = 0;
|
|
-
|
|
- if (__glibc_unlikely (buflen > 32768))
|
|
- {
|
|
- char *old_buffer = buffer;
|
|
- buflen *= 2;
|
|
- buffer = (char *) realloc (use_malloc ? buffer : NULL, buflen);
|
|
- if (buffer == NULL)
|
|
- {
|
|
- /* We ran out of memory. We cannot do anything but
|
|
- sending a negative response. In reality this should
|
|
- never happen. */
|
|
- hst = NULL;
|
|
- buffer = old_buffer;
|
|
-
|
|
- /* We set the error to indicate this is (possibly) a
|
|
- temporary error and that it does not mean the entry
|
|
- is not available at all. */
|
|
- h_errno = TRY_AGAIN;
|
|
- errval = EAGAIN;
|
|
- break;
|
|
- }
|
|
- use_malloc = true;
|
|
- }
|
|
- else
|
|
- /* Allocate a new buffer on the stack. If possible combine it
|
|
- with the previously allocated buffer. */
|
|
- buffer = (char *) extend_alloca (buffer, buflen, 2 * buflen);
|
|
- }
|
|
+ if (!scratch_buffer_grow (&tmpbuf))
|
|
+ {
|
|
+ /* We ran out of memory. We cannot do anything but sending a
|
|
+ negative response. In reality this should never
|
|
+ happen. */
|
|
+ hst = NULL;
|
|
+ /* We set the error to indicate this is (possibly) a temporary
|
|
+ error and that it does not mean the entry is not
|
|
+ available at all. */
|
|
+ h_errno = TRY_AGAIN;
|
|
+ errval = EAGAIN;
|
|
+ break;
|
|
+ }
|
|
|
|
time_t timeout = cache_addhst (db, fd, req, key, hst, uid, he, dh,
|
|
h_errno == TRY_AGAIN ? errval : 0, ttl);
|
|
-
|
|
- if (use_malloc)
|
|
- free (buffer);
|
|
-
|
|
+ scratch_buffer_free (&tmpbuf);
|
|
return timeout;
|
|
}
|
|
|
|
Index: b/nscd/pwdcache.c
|
|
===================================================================
|
|
--- a/nscd/pwdcache.c
|
|
+++ b/nscd/pwdcache.c
|
|
@@ -16,7 +16,6 @@
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, see <http://www.gnu.org/licenses/>. */
|
|
|
|
-#include <alloca.h>
|
|
#include <assert.h>
|
|
#include <errno.h>
|
|
#include <error.h>
|
|
@@ -32,6 +31,7 @@
|
|
#include <sys/mman.h>
|
|
#include <sys/socket.h>
|
|
#include <stackinfo.h>
|
|
+#include <scratch_buffer.h>
|
|
|
|
#include "nscd.h"
|
|
#include "dbg_log.h"
|
|
@@ -426,12 +426,11 @@ addpwbyX (struct database_dyn *db, int f
|
|
look again in the table whether the dataset is now available. We
|
|
simply insert it. It does not matter if it is in there twice. The
|
|
pruning function only will look at the timestamp. */
|
|
- size_t buflen = 1024;
|
|
- char *buffer = (char *) alloca (buflen);
|
|
struct passwd resultbuf;
|
|
struct passwd *pwd;
|
|
- bool use_malloc = false;
|
|
int errval = 0;
|
|
+ struct scratch_buffer tmpbuf;
|
|
+ scratch_buffer_init (&tmpbuf);
|
|
|
|
if (__glibc_unlikely (debug_level > 0))
|
|
{
|
|
@@ -441,45 +440,26 @@ addpwbyX (struct database_dyn *db, int f
|
|
dbg_log (_("Reloading \"%s\" in password cache!"), keystr);
|
|
}
|
|
|
|
- while (lookup (req->type, key, &resultbuf, buffer, buflen, &pwd) != 0
|
|
+ while (lookup (req->type, key, &resultbuf,
|
|
+ tmpbuf.data, tmpbuf.length, &pwd) != 0
|
|
&& (errval = errno) == ERANGE)
|
|
- {
|
|
- errno = 0;
|
|
-
|
|
- if (__glibc_unlikely (buflen > 32768))
|
|
- {
|
|
- char *old_buffer = buffer;
|
|
- buflen *= 2;
|
|
- buffer = (char *) realloc (use_malloc ? buffer : NULL, buflen);
|
|
- if (buffer == NULL)
|
|
- {
|
|
- /* We ran out of memory. We cannot do anything but
|
|
- sending a negative response. In reality this should
|
|
- never happen. */
|
|
- pwd = NULL;
|
|
- buffer = old_buffer;
|
|
-
|
|
- /* We set the error to indicate this is (possibly) a
|
|
- temporary error and that it does not mean the entry
|
|
- is not available at all. */
|
|
- errval = EAGAIN;
|
|
- break;
|
|
- }
|
|
- use_malloc = true;
|
|
- }
|
|
- else
|
|
- /* Allocate a new buffer on the stack. If possible combine it
|
|
- with the previously allocated buffer. */
|
|
- buffer = (char *) extend_alloca (buffer, buflen, 2 * buflen);
|
|
- }
|
|
+ if (!scratch_buffer_grow (&tmpbuf))
|
|
+ {
|
|
+ /* We ran out of memory. We cannot do anything but sending a
|
|
+ negative response. In reality this should never
|
|
+ happen. */
|
|
+ pwd = NULL;
|
|
+ /* We set the error to indicate this is (possibly) a temporary
|
|
+ error and that it does not mean the entry is not available
|
|
+ at all. */
|
|
+ errval = EAGAIN;
|
|
+ break;
|
|
+ }
|
|
|
|
/* Add the entry to the cache. */
|
|
time_t timeout = cache_addpw (db, fd, req, keystr, pwd, c_uid, he, dh,
|
|
errval);
|
|
-
|
|
- if (use_malloc)
|
|
- free (buffer);
|
|
-
|
|
+ scratch_buffer_free (&tmpbuf);
|
|
return timeout;
|
|
}
|
|
|
|
Index: b/nscd/servicescache.c
|
|
===================================================================
|
|
--- a/nscd/servicescache.c
|
|
+++ b/nscd/servicescache.c
|
|
@@ -16,7 +16,6 @@
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, see <http://www.gnu.org/licenses/>. */
|
|
|
|
-#include <alloca.h>
|
|
#include <assert.h>
|
|
#include <errno.h>
|
|
#include <libintl.h>
|
|
@@ -25,6 +24,7 @@
|
|
#include <stdint.h>
|
|
#include <sys/mman.h>
|
|
#include <kernel-features.h>
|
|
+#include <scratch_buffer.h>
|
|
|
|
#include "nscd.h"
|
|
#include "dbg_log.h"
|
|
@@ -374,12 +374,11 @@ addservbyX (struct database_dyn *db, int
|
|
look again in the table whether the dataset is now available. We
|
|
simply insert it. It does not matter if it is in there twice. The
|
|
pruning function only will look at the timestamp. */
|
|
- size_t buflen = 1024;
|
|
- char *buffer = (char *) alloca (buflen);
|
|
struct servent resultbuf;
|
|
struct servent *serv;
|
|
- bool use_malloc = false;
|
|
int errval = 0;
|
|
+ struct scratch_buffer tmpbuf;
|
|
+ scratch_buffer_init (&tmpbuf);
|
|
|
|
if (__glibc_unlikely (debug_level > 0))
|
|
{
|
|
@@ -389,43 +388,24 @@ addservbyX (struct database_dyn *db, int
|
|
dbg_log (_("Reloading \"%s\" in services cache!"), key);
|
|
}
|
|
|
|
- while (lookup (req->type, key, &resultbuf, buffer, buflen, &serv) != 0
|
|
+ while (lookup (req->type, key, &resultbuf,
|
|
+ tmpbuf.data, tmpbuf.length, &serv) != 0
|
|
&& (errval = errno) == ERANGE)
|
|
- {
|
|
- errno = 0;
|
|
-
|
|
- if (__glibc_unlikely (buflen > 32768))
|
|
- {
|
|
- char *old_buffer = buffer;
|
|
- buflen *= 2;
|
|
- buffer = (char *) realloc (use_malloc ? buffer : NULL, buflen);
|
|
- if (buffer == NULL)
|
|
- {
|
|
- /* We ran out of memory. We cannot do anything but
|
|
- sending a negative response. In reality this should
|
|
- never happen. */
|
|
- serv = NULL;
|
|
- buffer = old_buffer;
|
|
-
|
|
- /* We set the error to indicate this is (possibly) a
|
|
- temporary error and that it does not mean the entry
|
|
- is not available at all. */
|
|
- errval = EAGAIN;
|
|
- break;
|
|
- }
|
|
- use_malloc = true;
|
|
- }
|
|
- else
|
|
- /* Allocate a new buffer on the stack. If possible combine it
|
|
- with the previously allocated buffer. */
|
|
- buffer = (char *) extend_alloca (buffer, buflen, 2 * buflen);
|
|
- }
|
|
+ if (!scratch_buffer_grow (&tmpbuf))
|
|
+ {
|
|
+ /* We ran out of memory. We cannot do anything but sending a
|
|
+ negative response. In reality this should never
|
|
+ happen. */
|
|
+ serv = NULL;
|
|
+ /* We set the error to indicate this is (possibly) a temporary
|
|
+ error and that it does not mean the entry is not available
|
|
+ at all. */
|
|
+ errval = EAGAIN;
|
|
+ break;
|
|
+ }
|
|
|
|
time_t timeout = cache_addserv (db, fd, req, key, serv, uid, he, dh, errval);
|
|
-
|
|
- if (use_malloc)
|
|
- free (buffer);
|
|
-
|
|
+ scratch_buffer_free (&tmpbuf);
|
|
return timeout;
|
|
}
|
|
|
|
Index: b/nss/getent.c
|
|
===================================================================
|
|
--- a/nss/getent.c
|
|
+++ b/nss/getent.c
|
|
@@ -39,6 +39,7 @@
|
|
#include <netinet/ether.h>
|
|
#include <netinet/in.h>
|
|
#include <sys/socket.h>
|
|
+#include <scratch_buffer.h>
|
|
|
|
/* Get libc version number. */
|
|
#include <version.h>
|
|
@@ -477,30 +478,34 @@ netgroup_keys (int number, char *key[])
|
|
static int
|
|
initgroups_keys (int number, char *key[])
|
|
{
|
|
- int ngrps = 100;
|
|
- size_t grpslen = ngrps * sizeof (gid_t);
|
|
- gid_t *grps = alloca (grpslen);
|
|
-
|
|
if (number == 0)
|
|
{
|
|
fprintf (stderr, _("Enumeration not supported on %s\n"), "initgroups");
|
|
return 3;
|
|
}
|
|
|
|
+ struct scratch_buffer tmpbuf;
|
|
+ scratch_buffer_init (&tmpbuf);
|
|
+
|
|
for (int i = 0; i < number; ++i)
|
|
{
|
|
+ ssize_t ngrps = tmpbuf.length / sizeof (gid_t);
|
|
int no = ngrps;
|
|
int n;
|
|
- while ((n = getgrouplist (key[i], -1, grps, &no)) == -1
|
|
+ while ((n = getgrouplist (key[i], -1, tmpbuf.data, &no)) == -1
|
|
&& no > ngrps)
|
|
{
|
|
- grps = extend_alloca (grps, grpslen, no * sizeof (gid_t));
|
|
- ngrps = no;
|
|
+ if (!scratch_buffer_set_array_size (&tmpbuf, no, sizeof (gid_t)))
|
|
+ {
|
|
+ fprintf (stderr, _("Could not allocate group list: %m\n"));
|
|
+ return 3;
|
|
+ }
|
|
}
|
|
|
|
if (n == -1)
|
|
return 1;
|
|
|
|
+ const gid_t *grps = tmpbuf.data;
|
|
printf ("%-21s", key[i]);
|
|
for (int j = 0; j < n; ++j)
|
|
if (grps[j] != -1)
|
|
@@ -508,6 +513,8 @@ initgroups_keys (int number, char *key[]
|
|
putchar_unlocked ('\n');
|
|
}
|
|
|
|
+ scratch_buffer_free (&tmpbuf);
|
|
+
|
|
return 0;
|
|
}
|
|
|
|
Index: b/nss/nss_files/files-hosts.c
|
|
===================================================================
|
|
--- a/nss/nss_files/files-hosts.c
|
|
+++ b/nss/nss_files/files-hosts.c
|
|
@@ -22,7 +22,7 @@
|
|
#include <arpa/nameser.h>
|
|
#include <netdb.h>
|
|
#include <resolv/resolv-internal.h>
|
|
-
|
|
+#include <scratch_buffer.h>
|
|
|
|
/* Get implementation for some internal functions. */
|
|
#include "../resolv/mapv4v6addr.h"
|
|
@@ -145,15 +145,12 @@ _nss_files_gethostbyname3_r (const char
|
|
&& _res_hconf.flags & HCONF_FLAG_MULTI)
|
|
{
|
|
/* We have to get all host entries from the file. */
|
|
- size_t tmp_buflen = MIN (buflen, 4096);
|
|
- char tmp_buffer_stack[tmp_buflen]
|
|
- __attribute__ ((__aligned__ (__alignof__ (struct hostent_data))));
|
|
- char *tmp_buffer = tmp_buffer_stack;
|
|
struct hostent tmp_result_buf;
|
|
int naddrs = 1;
|
|
int naliases = 0;
|
|
char *bufferend;
|
|
- bool tmp_buffer_malloced = false;
|
|
+ struct scratch_buffer tmpbuf;
|
|
+ scratch_buffer_init (&tmpbuf);
|
|
|
|
while (result->h_aliases[naliases] != NULL)
|
|
++naliases;
|
|
@@ -161,9 +158,9 @@ _nss_files_gethostbyname3_r (const char
|
|
bufferend = (char *) &result->h_aliases[naliases + 1];
|
|
|
|
again:
|
|
- while ((status = internal_getent (stream, &tmp_result_buf, tmp_buffer,
|
|
- tmp_buflen, errnop, herrnop, af,
|
|
- flags))
|
|
+ while ((status = internal_getent (stream, &tmp_result_buf,
|
|
+ tmpbuf.data, tmpbuf.length,
|
|
+ errnop, herrnop, af, flags))
|
|
== NSS_STATUS_SUCCESS)
|
|
{
|
|
int matches = 1;
|
|
@@ -287,54 +284,13 @@ _nss_files_gethostbyname3_r (const char
|
|
}
|
|
}
|
|
|
|
- if (status == NSS_STATUS_TRYAGAIN)
|
|
- {
|
|
- size_t newsize = 2 * tmp_buflen;
|
|
- if (tmp_buffer_malloced)
|
|
- {
|
|
- char *newp = realloc (tmp_buffer, newsize);
|
|
- if (newp != NULL)
|
|
- {
|
|
- assert ((((uintptr_t) newp)
|
|
- & (__alignof__ (struct hostent_data) - 1))
|
|
- == 0);
|
|
- tmp_buffer = newp;
|
|
- tmp_buflen = newsize;
|
|
- goto again;
|
|
- }
|
|
- }
|
|
- else if (!__libc_use_alloca (buflen + newsize))
|
|
- {
|
|
- tmp_buffer = malloc (newsize);
|
|
- if (tmp_buffer != NULL)
|
|
- {
|
|
- assert ((((uintptr_t) tmp_buffer)
|
|
- & (__alignof__ (struct hostent_data) - 1))
|
|
- == 0);
|
|
- tmp_buffer_malloced = true;
|
|
- tmp_buflen = newsize;
|
|
- goto again;
|
|
- }
|
|
- }
|
|
- else
|
|
- {
|
|
- tmp_buffer
|
|
- = extend_alloca (tmp_buffer, tmp_buflen,
|
|
- newsize
|
|
- + __alignof__ (struct hostent_data));
|
|
- tmp_buffer = (char *) (((uintptr_t) tmp_buffer
|
|
- + __alignof__ (struct hostent_data)
|
|
- - 1)
|
|
- & ~(__alignof__ (struct hostent_data)
|
|
- - 1));
|
|
- goto again;
|
|
- }
|
|
- }
|
|
+ if (status == NSS_STATUS_TRYAGAIN
|
|
+ && scratch_buffer_grow (&tmpbuf))
|
|
+ goto again;
|
|
else
|
|
status = NSS_STATUS_SUCCESS;
|
|
out:
|
|
- if (tmp_buffer_malloced)
|
|
- free (tmp_buffer);
|
|
+ scratch_buffer_free (&tmpbuf);
|
|
}
|
|
|
|
internal_endent (&stream);
|
|
Index: b/nss/nss_files/files-initgroups.c
|
|
===================================================================
|
|
--- a/nss/nss_files/files-initgroups.c
|
|
+++ b/nss/nss_files/files-initgroups.c
|
|
@@ -16,7 +16,6 @@
|
|
License along with the GNU C Library; if not, see
|
|
<http://www.gnu.org/licenses/>. */
|
|
|
|
-#include <alloca.h>
|
|
#include <errno.h>
|
|
#include <grp.h>
|
|
#include <nss.h>
|
|
@@ -25,6 +24,7 @@
|
|
#include <sys/param.h>
|
|
#include <stdbool.h>
|
|
#include <stdlib.h>
|
|
+#include <scratch_buffer.h>
|
|
|
|
enum nss_status
|
|
_nss_files_initgroups_dyn (const char *user, gid_t group, long int *start,
|
|
@@ -46,9 +46,8 @@ _nss_files_initgroups_dyn (const char *u
|
|
enum nss_status status = NSS_STATUS_SUCCESS;
|
|
bool any = false;
|
|
|
|
- size_t buflen = 1024;
|
|
- void *buffer = alloca (buflen);
|
|
- bool buffer_use_malloc = false;
|
|
+ struct scratch_buffer tmpbuf;
|
|
+ scratch_buffer_init (&tmpbuf);
|
|
|
|
gid_t *groups = *groupsp;
|
|
|
|
@@ -67,26 +66,16 @@ _nss_files_initgroups_dyn (const char *u
|
|
}
|
|
|
|
struct group grp;
|
|
- int res = _nss_files_parse_grent (line, &grp, buffer, buflen, errnop);
|
|
+ int res = _nss_files_parse_grent (line, &grp,
|
|
+ tmpbuf.data, tmpbuf.length, errnop);
|
|
if (res == -1)
|
|
{
|
|
- size_t newbuflen = 2 * buflen;
|
|
- if (buffer_use_malloc || ! __libc_use_alloca (buflen + newbuflen))
|
|
+ if (!scratch_buffer_grow (&tmpbuf))
|
|
{
|
|
- void *newbuf = realloc (buffer_use_malloc ? buffer : NULL,
|
|
- newbuflen);
|
|
- if (newbuf == NULL)
|
|
- {
|
|
- *errnop = ENOMEM;
|
|
- status = NSS_STATUS_TRYAGAIN;
|
|
- goto out;
|
|
- }
|
|
- buffer = newbuf;
|
|
- buflen = newbuflen;
|
|
- buffer_use_malloc = true;
|
|
+ *errnop = ENOMEM;
|
|
+ status = NSS_STATUS_TRYAGAIN;
|
|
+ goto out;
|
|
}
|
|
- else
|
|
- buffer = extend_alloca (buffer, buflen, newbuflen);
|
|
/* Reread current line, the parser has clobbered it. */
|
|
fsetpos (stream, &pos);
|
|
continue;
|
|
@@ -132,8 +121,7 @@ _nss_files_initgroups_dyn (const char *u
|
|
|
|
out:
|
|
/* Free memory. */
|
|
- if (buffer_use_malloc)
|
|
- free (buffer);
|
|
+ scratch_buffer_free (&tmpbuf);
|
|
free (line);
|
|
|
|
fclose (stream);
|
|
Index: b/posix/wordexp.c
|
|
===================================================================
|
|
--- a/posix/wordexp.c
|
|
+++ b/posix/wordexp.c
|
|
@@ -17,7 +17,6 @@
|
|
License along with the GNU C Library; if not, see
|
|
<http://www.gnu.org/licenses/>. */
|
|
|
|
-#include <alloca.h>
|
|
#include <ctype.h>
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
@@ -41,6 +40,7 @@
|
|
#include <wchar.h>
|
|
#include <wordexp.h>
|
|
#include <kernel-features.h>
|
|
+#include <scratch_buffer.h>
|
|
|
|
#include <libc-lock.h>
|
|
#include <_itoa.h>
|
|
@@ -308,12 +308,7 @@ parse_tilde (char **word, size_t *word_l
|
|
if (i == 1 + *offset)
|
|
{
|
|
/* Tilde appears on its own */
|
|
- uid_t uid;
|
|
- struct passwd pwd, *tpwd;
|
|
- int buflen = 1000;
|
|
char* home;
|
|
- char* buffer;
|
|
- int result;
|
|
|
|
/* POSIX.2 says ~ expands to $HOME and if HOME is unset the
|
|
results are unspecified. We do a lookup on the uid if
|
|
@@ -328,25 +323,38 @@ parse_tilde (char **word, size_t *word_l
|
|
}
|
|
else
|
|
{
|
|
- uid = __getuid ();
|
|
- buffer = __alloca (buflen);
|
|
-
|
|
- while ((result = __getpwuid_r (uid, &pwd, buffer, buflen, &tpwd)) != 0
|
|
+ struct passwd pwd, *tpwd;
|
|
+ uid_t uid = __getuid ();
|
|
+ int result;
|
|
+ struct scratch_buffer tmpbuf;
|
|
+ scratch_buffer_init (&tmpbuf);
|
|
+
|
|
+ while ((result = __getpwuid_r (uid, &pwd,
|
|
+ tmpbuf.data, tmpbuf.length,
|
|
+ &tpwd)) != 0
|
|
&& errno == ERANGE)
|
|
- buffer = extend_alloca (buffer, buflen, buflen + 1000);
|
|
+ if (!scratch_buffer_grow (&tmpbuf))
|
|
+ return WRDE_NOSPACE;
|
|
|
|
if (result == 0 && tpwd != NULL && pwd.pw_dir != NULL)
|
|
{
|
|
*word = w_addstr (*word, word_length, max_length, pwd.pw_dir);
|
|
if (*word == NULL)
|
|
- return WRDE_NOSPACE;
|
|
+ {
|
|
+ scratch_buffer_free (&tmpbuf);
|
|
+ return WRDE_NOSPACE;
|
|
+ }
|
|
}
|
|
else
|
|
{
|
|
*word = w_addchar (*word, word_length, max_length, '~');
|
|
if (*word == NULL)
|
|
- return WRDE_NOSPACE;
|
|
+ {
|
|
+ scratch_buffer_free (&tmpbuf);
|
|
+ return WRDE_NOSPACE;
|
|
+ }
|
|
}
|
|
+ scratch_buffer_free (&tmpbuf);
|
|
}
|
|
}
|
|
else
|
|
@@ -354,13 +362,15 @@ parse_tilde (char **word, size_t *word_l
|
|
/* Look up user name in database to get home directory */
|
|
char *user = strndupa (&words[1 + *offset], i - (1 + *offset));
|
|
struct passwd pwd, *tpwd;
|
|
- int buflen = 1000;
|
|
- char* buffer = __alloca (buflen);
|
|
int result;
|
|
+ struct scratch_buffer tmpbuf;
|
|
+ scratch_buffer_init (&tmpbuf);
|
|
|
|
- while ((result = __getpwnam_r (user, &pwd, buffer, buflen, &tpwd)) != 0
|
|
+ while ((result = __getpwnam_r (user, &pwd, tmpbuf.data, tmpbuf.length,
|
|
+ &tpwd)) != 0
|
|
&& errno == ERANGE)
|
|
- buffer = extend_alloca (buffer, buflen, buflen + 1000);
|
|
+ if (!scratch_buffer_grow (&tmpbuf))
|
|
+ return WRDE_NOSPACE;
|
|
|
|
if (result == 0 && tpwd != NULL && pwd.pw_dir)
|
|
*word = w_addstr (*word, word_length, max_length, pwd.pw_dir);
|
|
@@ -372,6 +382,8 @@ parse_tilde (char **word, size_t *word_l
|
|
*word = w_addstr (*word, word_length, max_length, user);
|
|
}
|
|
|
|
+ scratch_buffer_free (&tmpbuf);
|
|
+
|
|
*offset = i - 1;
|
|
}
|
|
return *word ? 0 : WRDE_NOSPACE;
|
|
Index: b/sysdeps/unix/sysv/linux/gethostid.c
|
|
===================================================================
|
|
--- a/sysdeps/unix/sysv/linux/gethostid.c
|
|
+++ b/sysdeps/unix/sysv/linux/gethostid.c
|
|
@@ -63,13 +63,12 @@ sethostid (long int id)
|
|
# include <sys/param.h>
|
|
# include <resolv/netdb.h>
|
|
# include <netinet/in.h>
|
|
+# include <scratch_buffer.h>
|
|
|
|
long int
|
|
gethostid (void)
|
|
{
|
|
char hostname[MAXHOSTNAMELEN + 1];
|
|
- size_t buflen;
|
|
- char *buffer;
|
|
struct hostent hostbuf, *hp;
|
|
int32_t id;
|
|
struct in_addr in;
|
|
@@ -94,23 +93,26 @@ gethostid (void)
|
|
/* This also fails. Return and arbitrary value. */
|
|
return 0;
|
|
|
|
- buflen = 1024;
|
|
- buffer = __alloca (buflen);
|
|
+ struct scratch_buffer tmpbuf;
|
|
+ scratch_buffer_init (&tmpbuf);
|
|
|
|
/* To get the IP address we need to know the host name. */
|
|
- while (__gethostbyname_r (hostname, &hostbuf, buffer, buflen, &hp, &herr)
|
|
- != 0
|
|
+ while (__gethostbyname_r (hostname, &hostbuf,
|
|
+ tmpbuf.data, tmpbuf.length, &hp, &herr) != 0
|
|
|| hp == NULL)
|
|
if (herr != NETDB_INTERNAL || errno != ERANGE)
|
|
- return 0;
|
|
+ {
|
|
+ scratch_buffer_free (&tmpbuf);
|
|
+ return 0;
|
|
+ }
|
|
else
|
|
- /* Enlarge buffer. */
|
|
- buffer = extend_alloca (buffer, buflen, 2 * buflen);
|
|
+ if (!scratch_buffer_grow (&tmpbuf))
|
|
+ return 0;
|
|
|
|
in.s_addr = 0;
|
|
memcpy (&in, hp->h_addr,
|
|
(int) sizeof (in) < hp->h_length ? (int) sizeof (in) : hp->h_length);
|
|
-
|
|
+ scratch_buffer_free (&tmpbuf);
|
|
/* For the return value to be not exactly the IP address we do some
|
|
bit fiddling. */
|
|
return (int32_t) (in.s_addr << 16 | in.s_addr >> 16);
|
|
Index: b/sysdeps/unix/sysv/linux/getlogin_r.c
|
|
===================================================================
|
|
--- a/sysdeps/unix/sysv/linux/getlogin_r.c
|
|
+++ b/sysdeps/unix/sysv/linux/getlogin_r.c
|
|
@@ -18,6 +18,7 @@
|
|
#include <pwd.h>
|
|
#include <unistd.h>
|
|
#include <not-cancel.h>
|
|
+#include <scratch_buffer.h>
|
|
|
|
#define STATIC static
|
|
static int getlogin_r_fd0 (char *name, size_t namesize);
|
|
@@ -54,28 +55,19 @@ __getlogin_r_loginuid (char *name, size_
|
|
endp == uidbuf || *endp != '\0'))
|
|
return -1;
|
|
|
|
- size_t buflen = 1024;
|
|
- char *buf = alloca (buflen);
|
|
- bool use_malloc = false;
|
|
struct passwd pwd;
|
|
struct passwd *tpwd;
|
|
int result = 0;
|
|
int res;
|
|
+ struct scratch_buffer tmpbuf;
|
|
+ scratch_buffer_init (&tmpbuf);
|
|
|
|
- while ((res = __getpwuid_r (uid, &pwd, buf, buflen, &tpwd)) == ERANGE)
|
|
- if (__libc_use_alloca (2 * buflen))
|
|
- buf = extend_alloca (buf, buflen, 2 * buflen);
|
|
- else
|
|
+ while ((res = __getpwuid_r (uid, &pwd,
|
|
+ tmpbuf.data, tmpbuf.length, &tpwd)) == ERANGE)
|
|
+ if (!scratch_buffer_grow (&tmpbuf))
|
|
{
|
|
- buflen *= 2;
|
|
- char *newp = realloc (use_malloc ? buf : NULL, buflen);
|
|
- if (newp == NULL)
|
|
- {
|
|
- result = ENOMEM;
|
|
- goto out;
|
|
- }
|
|
- buf = newp;
|
|
- use_malloc = true;
|
|
+ result = ENOMEM;
|
|
+ goto out;
|
|
}
|
|
|
|
if (res != 0 || tpwd == NULL)
|
|
@@ -95,9 +87,7 @@ __getlogin_r_loginuid (char *name, size_
|
|
memcpy (name, pwd.pw_name, needed);
|
|
|
|
out:
|
|
- if (use_malloc)
|
|
- free (buf);
|
|
-
|
|
+ scratch_buffer_free (&tmpbuf);
|
|
return result;
|
|
}
|
|
|