forked from rpms/glibc
ddd7733205
Drop glibc-nsswitch-Add-group-merging-support.patch, applied upstream. Drop glibc-rh1252570.patch, alternative fixes applied upstream. Adjust glibc-rh1315108.patch to minor upstream change. Update SUPPORTED file.
2192 lines
64 KiB
Diff
2192 lines
64 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 f414b3f5947f264cb5d114965f284cacb2fb10b5
|
|
Author: Florian Weimer <fweimer@redhat.com>
|
|
Date: Sun Mar 1 19:38:42 2015 +0100
|
|
|
|
getaddrinfo: Use struct scratch_buffer instead of extend_alloca
|
|
|
|
This results in slightly smaller buffers in some cases, but as the
|
|
buffer size is passed to the called functions (and they will request
|
|
an increased buffer size with an ERANGE error code), this does not
|
|
result in a functional difference.
|
|
|
|
[BZ #18023]
|
|
* sysdeps/posix/getaddrinfo.c (gaih_inet_serv, gethosts)
|
|
(gaih_inet): 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 7b4c16db30304b83a5d1e913d1a8f7e90a8c398c
|
|
Author: Florian Weimer <fweimer@redhat.com>
|
|
Date: Sun Mar 1 19:49:50 2015 +0100
|
|
|
|
glob: Rewrite to use struct scratch_buffer instead of extend_alloca
|
|
|
|
[BZ #18023]
|
|
* posix/glob.c (glob): 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
|
|
@@ -20,57 +20,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
|
|
Index: b/nis/nss_compat/compat-initgroups.c
|
|
===================================================================
|
|
--- a/nis/nss_compat/compat-initgroups.c
|
|
+++ b/nis/nss_compat/compat-initgroups.c
|
|
@@ -310,7 +310,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++)
|
|
{
|
|
@@ -319,29 +318,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))
|
|
@@ -369,7 +365,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,20 @@ _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);
|
|
|
|
do
|
|
{
|
|
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;
|
|
+ goto done;
|
|
+ }
|
|
|
|
if (status != NSS_STATUS_SUCCESS)
|
|
goto done;
|
|
@@ -325,6 +331,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
|
|
@@ -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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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;
|
|
}
|
|
|
|
Index: b/nscd/connections.c
|
|
===================================================================
|
|
--- a/nscd/connections.c
|
|
+++ b/nscd/connections.c
|
|
@@ -1353,64 +1353,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;
|
|
@@ -1427,6 +1446,7 @@ cannot change to old UID: %s; disabling
|
|
strerror (errno));
|
|
|
|
paranoia = 0;
|
|
+ free (cmdline);
|
|
return;
|
|
}
|
|
|
|
@@ -1438,6 +1458,7 @@ cannot change to old GID: %s; disabling
|
|
|
|
ignore_value (setuid (server_uid));
|
|
paranoia = 0;
|
|
+ free (cmdline);
|
|
return;
|
|
}
|
|
}
|
|
@@ -1455,6 +1476,7 @@ cannot change to old working directory:
|
|
ignore_value (setgid (server_gid));
|
|
}
|
|
paranoia = 0;
|
|
+ free (cmdline);
|
|
return;
|
|
}
|
|
|
|
@@ -1503,6 +1525,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"
|
|
@@ -437,12 +437,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))
|
|
{
|
|
@@ -452,43 +452,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"
|
|
@@ -415,12 +415,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))
|
|
{
|
|
@@ -430,45 +429,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.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/glob.c
|
|
===================================================================
|
|
--- a/posix/glob.c
|
|
+++ b/posix/glob.c
|
|
@@ -27,6 +27,7 @@
|
|
#include <stdbool.h>
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
+#include <scratch_buffer.h>
|
|
|
|
/* Outcomment the following line for production quality code. */
|
|
/* #define NDEBUG 1 */
|
|
@@ -293,7 +294,7 @@ glob (const char *pattern, int flags, in
|
|
glob_t dirs;
|
|
int retval = 0;
|
|
#ifdef _LIBC
|
|
- size_t alloca_used = 0;
|
|
+ size_t alloca_used = sizeof (struct scratch_buffer);
|
|
#endif
|
|
|
|
if (pattern == NULL || pglob == NULL || (flags & ~__GLOB_FLAGS) != 0)
|
|
@@ -650,33 +651,13 @@ glob (const char *pattern, int flags, in
|
|
{
|
|
struct passwd *p;
|
|
# if defined HAVE_GETPWNAM_R || defined _LIBC
|
|
- long int pwbuflen = GETPW_R_SIZE_MAX ();
|
|
- char *pwtmpbuf;
|
|
struct passwd pwbuf;
|
|
- int malloc_pwtmpbuf = 0;
|
|
int save = errno;
|
|
+ struct scratch_buffer pwtmpbuf;
|
|
+ scratch_buffer_init (&pwtmpbuf);
|
|
|
|
-# ifndef _LIBC
|
|
- if (pwbuflen == -1)
|
|
- /* `sysconf' does not support _SC_GETPW_R_SIZE_MAX.
|
|
- Try a moderate value. */
|
|
- pwbuflen = 1024;
|
|
-# endif
|
|
- if (__libc_use_alloca (alloca_used + pwbuflen))
|
|
- pwtmpbuf = alloca_account (pwbuflen, alloca_used);
|
|
- else
|
|
- {
|
|
- pwtmpbuf = malloc (pwbuflen);
|
|
- if (pwtmpbuf == NULL)
|
|
- {
|
|
- retval = GLOB_NOSPACE;
|
|
- goto out;
|
|
- }
|
|
- malloc_pwtmpbuf = 1;
|
|
- }
|
|
-
|
|
- while (getpwnam_r (name, &pwbuf, pwtmpbuf, pwbuflen, &p)
|
|
- != 0)
|
|
+ while (getpwnam_r (name, &pwbuf,
|
|
+ pwtmpbuf.data, pwtmpbuf.length, &p) != 0)
|
|
{
|
|
if (errno != ERANGE)
|
|
{
|
|
@@ -684,67 +665,37 @@ glob (const char *pattern, int flags, in
|
|
break;
|
|
}
|
|
|
|
- if (!malloc_pwtmpbuf
|
|
- && __libc_use_alloca (alloca_used
|
|
- + 2 * pwbuflen))
|
|
- pwtmpbuf = extend_alloca_account (pwtmpbuf, pwbuflen,
|
|
- 2 * pwbuflen,
|
|
- alloca_used);
|
|
- else
|
|
+ if (!scratch_buffer_grow (&pwtmpbuf))
|
|
{
|
|
- char *newp = realloc (malloc_pwtmpbuf
|
|
- ? pwtmpbuf : NULL,
|
|
- 2 * pwbuflen);
|
|
- if (newp == NULL)
|
|
- {
|
|
- if (__glibc_unlikely (malloc_pwtmpbuf))
|
|
- free (pwtmpbuf);
|
|
- retval = GLOB_NOSPACE;
|
|
- goto out;
|
|
- }
|
|
- pwtmpbuf = newp;
|
|
- pwbuflen = 2 * pwbuflen;
|
|
- malloc_pwtmpbuf = 1;
|
|
+ retval = GLOB_NOSPACE;
|
|
+ goto out;
|
|
}
|
|
__set_errno (save);
|
|
}
|
|
# else
|
|
- p = getpwnam (name);
|
|
+ p = getpwnam (namebuf.data);
|
|
# endif
|
|
if (p != NULL)
|
|
{
|
|
- if (!malloc_pwtmpbuf)
|
|
- home_dir = p->pw_dir;
|
|
- else
|
|
+ home_dir = strdup (p->pw_dir);
|
|
+ malloc_home_dir = 1;
|
|
+ if (home_dir == NULL)
|
|
{
|
|
- size_t home_dir_len = strlen (p->pw_dir) + 1;
|
|
- if (__libc_use_alloca (alloca_used + home_dir_len))
|
|
- home_dir = alloca_account (home_dir_len,
|
|
- alloca_used);
|
|
- else
|
|
- {
|
|
- home_dir = malloc (home_dir_len);
|
|
- if (home_dir == NULL)
|
|
- {
|
|
- free (pwtmpbuf);
|
|
- retval = GLOB_NOSPACE;
|
|
- goto out;
|
|
- }
|
|
- malloc_home_dir = 1;
|
|
- }
|
|
- memcpy (home_dir, p->pw_dir, home_dir_len);
|
|
-
|
|
- free (pwtmpbuf);
|
|
+ scratch_buffer_free (&pwtmpbuf);
|
|
+ retval = GLOB_NOSPACE;
|
|
+ goto out;
|
|
}
|
|
}
|
|
+ scratch_buffer_free (&pwtmpbuf);
|
|
}
|
|
}
|
|
if (home_dir == NULL || home_dir[0] == '\0')
|
|
{
|
|
+ if (malloc_home_dir)
|
|
+ free (home_dir);
|
|
+ malloc_home_dir = 0;
|
|
if (flags & GLOB_TILDE_CHECK)
|
|
{
|
|
- if (__glibc_unlikely (malloc_home_dir))
|
|
- free (home_dir);
|
|
retval = GLOB_NOMATCH;
|
|
goto out;
|
|
}
|
|
@@ -865,57 +816,24 @@ glob (const char *pattern, int flags, in
|
|
{
|
|
struct passwd *p;
|
|
# if defined HAVE_GETPWNAM_R || defined _LIBC
|
|
- long int buflen = GETPW_R_SIZE_MAX ();
|
|
- char *pwtmpbuf;
|
|
- int malloc_pwtmpbuf = 0;
|
|
struct passwd pwbuf;
|
|
int save = errno;
|
|
+ struct scratch_buffer pwtmpbuf;
|
|
+ scratch_buffer_init (&pwtmpbuf);
|
|
|
|
-# ifndef _LIBC
|
|
- if (buflen == -1)
|
|
- /* `sysconf' does not support _SC_GETPW_R_SIZE_MAX. Try a
|
|
- moderate value. */
|
|
- buflen = 1024;
|
|
-# endif
|
|
- if (__libc_use_alloca (alloca_used + buflen))
|
|
- pwtmpbuf = alloca_account (buflen, alloca_used);
|
|
- else
|
|
- {
|
|
- pwtmpbuf = malloc (buflen);
|
|
- if (pwtmpbuf == NULL)
|
|
- {
|
|
- nomem_getpw:
|
|
- if (__glibc_unlikely (malloc_user_name))
|
|
- free (user_name);
|
|
- retval = GLOB_NOSPACE;
|
|
- goto out;
|
|
- }
|
|
- malloc_pwtmpbuf = 1;
|
|
- }
|
|
-
|
|
- while (getpwnam_r (user_name, &pwbuf, pwtmpbuf, buflen, &p) != 0)
|
|
+ while (getpwnam_r (user_name, &pwbuf,
|
|
+ pwtmpbuf.data, pwtmpbuf.length, &p) != 0)
|
|
{
|
|
if (errno != ERANGE)
|
|
{
|
|
p = NULL;
|
|
break;
|
|
}
|
|
- if (!malloc_pwtmpbuf
|
|
- && __libc_use_alloca (alloca_used + 2 * buflen))
|
|
- pwtmpbuf = extend_alloca_account (pwtmpbuf, buflen,
|
|
- 2 * buflen, alloca_used);
|
|
- else
|
|
+
|
|
+ if (!scratch_buffer_grow (&pwtmpbuf))
|
|
{
|
|
- char *newp = realloc (malloc_pwtmpbuf ? pwtmpbuf : NULL,
|
|
- 2 * buflen);
|
|
- if (newp == NULL)
|
|
- {
|
|
- if (__glibc_unlikely (malloc_pwtmpbuf))
|
|
- free (pwtmpbuf);
|
|
- goto nomem_getpw;
|
|
- }
|
|
- pwtmpbuf = newp;
|
|
- malloc_pwtmpbuf = 1;
|
|
+ retval = GLOB_NOSPACE;
|
|
+ goto out;
|
|
}
|
|
__set_errno (save);
|
|
}
|
|
@@ -944,8 +862,7 @@ glob (const char *pattern, int flags, in
|
|
dirname = malloc (home_len + rest_len + 1);
|
|
if (dirname == NULL)
|
|
{
|
|
- if (__glibc_unlikely (malloc_pwtmpbuf))
|
|
- free (pwtmpbuf);
|
|
+ scratch_buffer_free (&pwtmpbuf);
|
|
retval = GLOB_NOSPACE;
|
|
goto out;
|
|
}
|
|
@@ -957,13 +874,11 @@ glob (const char *pattern, int flags, in
|
|
dirlen = home_len + rest_len;
|
|
dirname_modified = 1;
|
|
|
|
- if (__glibc_unlikely (malloc_pwtmpbuf))
|
|
- free (pwtmpbuf);
|
|
+ scratch_buffer_free (&pwtmpbuf);
|
|
}
|
|
else
|
|
{
|
|
- if (__glibc_unlikely (malloc_pwtmpbuf))
|
|
- free (pwtmpbuf);
|
|
+ scratch_buffer_free (&pwtmpbuf);
|
|
|
|
if (flags & GLOB_TILDE_CHECK)
|
|
/* We have to regard it as an error if we cannot find the
|
|
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/posix/getaddrinfo.c
|
|
===================================================================
|
|
--- a/sysdeps/posix/getaddrinfo.c
|
|
+++ b/sysdeps/posix/getaddrinfo.c
|
|
@@ -63,6 +63,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBI
|
|
#include <nscd/nscd-client.h>
|
|
#include <nscd/nscd_proto.h>
|
|
#include <resolv/res_hconf.h>
|
|
+#include <scratch_buffer.h>
|
|
|
|
#ifdef HAVE_LIBIDN
|
|
extern int __idna_to_ascii_lz (const char *input, char **output, int flags);
|
|
@@ -138,21 +139,22 @@ gaih_inet_serv (const char *servicename,
|
|
const struct addrinfo *req, struct gaih_servtuple *st)
|
|
{
|
|
struct servent *s;
|
|
- size_t tmpbuflen = 1024;
|
|
struct servent ts;
|
|
- char *tmpbuf;
|
|
int r;
|
|
+ struct scratch_buffer tmpbuf;
|
|
+ scratch_buffer_init (&tmpbuf);
|
|
|
|
do
|
|
{
|
|
- tmpbuf = __alloca (tmpbuflen);
|
|
-
|
|
- r = __getservbyname_r (servicename, tp->name, &ts, tmpbuf, tmpbuflen,
|
|
- &s);
|
|
+ r = __getservbyname_r (servicename, tp->name, &ts,
|
|
+ tmpbuf.data, tmpbuf.length, &s);
|
|
if (r != 0 || s == NULL)
|
|
{
|
|
if (r == ERANGE)
|
|
- tmpbuflen *= 2;
|
|
+ {
|
|
+ if (!scratch_buffer_grow (&tmpbuf))
|
|
+ return -EAI_MEMORY;
|
|
+ }
|
|
else
|
|
return -EAI_SERVICE;
|
|
}
|
|
@@ -164,7 +166,7 @@ gaih_inet_serv (const char *servicename,
|
|
st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY)
|
|
? req->ai_protocol : tp->protocol);
|
|
st->port = s->s_port;
|
|
-
|
|
+ scratch_buffer_free (&tmpbuf);
|
|
return 0;
|
|
}
|
|
|
|
@@ -227,25 +229,15 @@ convert_hostent_to_gaih_addrtuple (const
|
|
no_data = 0; \
|
|
while (1) { \
|
|
rc = 0; \
|
|
- status = DL_CALL_FCT (fct, (name, _family, &th, tmpbuf, tmpbuflen, \
|
|
+ status = DL_CALL_FCT (fct, (name, _family, &th, \
|
|
+ tmpbuf.data, tmpbuf.length, \
|
|
&rc, &herrno, NULL, &localcanon)); \
|
|
if (rc != ERANGE || herrno != NETDB_INTERNAL) \
|
|
break; \
|
|
- if (!malloc_tmpbuf && __libc_use_alloca (alloca_used + 2 * tmpbuflen)) \
|
|
- tmpbuf = extend_alloca_account (tmpbuf, tmpbuflen, 2 * tmpbuflen, \
|
|
- alloca_used); \
|
|
- else \
|
|
+ if (!scratch_buffer_grow (&tmpbuf)) \
|
|
{ \
|
|
- char *newp = realloc (malloc_tmpbuf ? tmpbuf : NULL, \
|
|
- 2 * tmpbuflen); \
|
|
- if (newp == NULL) \
|
|
- { \
|
|
- result = -EAI_MEMORY; \
|
|
- goto free_and_return; \
|
|
- } \
|
|
- tmpbuf = newp; \
|
|
- malloc_tmpbuf = true; \
|
|
- tmpbuflen = 2 * tmpbuflen; \
|
|
+ result = -EAI_MEMORY; \
|
|
+ goto free_and_return; \
|
|
} \
|
|
} \
|
|
if (status == NSS_STATUS_SUCCESS && rc == 0) \
|
|
@@ -316,7 +308,10 @@ gaih_inet (const char *name, const struc
|
|
bool got_ipv6 = false;
|
|
const char *canon = NULL;
|
|
const char *orig_name = name;
|
|
- size_t alloca_used = 0;
|
|
+
|
|
+ /* Reserve stack memory for this function's buffer and the one in
|
|
+ gaih_inet_serv. */
|
|
+ size_t alloca_used = 2 * sizeof (struct scratch_buffer);
|
|
|
|
if (req->ai_protocol || req->ai_socktype)
|
|
{
|
|
@@ -437,9 +432,10 @@ gaih_inet (const char *name, const struc
|
|
struct gaih_addrtuple *addrmem = NULL;
|
|
bool malloc_canonbuf = false;
|
|
char *canonbuf = NULL;
|
|
- bool malloc_tmpbuf = false;
|
|
- char *tmpbuf = NULL;
|
|
int result = 0;
|
|
+ struct scratch_buffer tmpbuf;
|
|
+ scratch_buffer_init (&tmpbuf);
|
|
+
|
|
if (name != NULL)
|
|
{
|
|
at = alloca_account (sizeof (struct gaih_addrtuple), alloca_used);
|
|
@@ -607,11 +603,8 @@ gaih_inet (const char *name, const struc
|
|
if (req->ai_family == AF_INET
|
|
&& (req->ai_flags & AI_CANONNAME) == 0)
|
|
{
|
|
- /* Allocate additional room for struct host_data. */
|
|
- size_t tmpbuflen = (512 + MAX_NR_ALIASES * sizeof(char*)
|
|
- + 16 * sizeof(char));
|
|
- assert (tmpbuf == NULL);
|
|
- tmpbuf = alloca_account (tmpbuflen, alloca_used);
|
|
+ /* tmpbuf must not have been used so far. */
|
|
+ assert (tmpbuf.data == tmpbuf.__space);
|
|
int rc;
|
|
struct hostent th;
|
|
struct hostent *h;
|
|
@@ -619,28 +612,15 @@ gaih_inet (const char *name, const struc
|
|
|
|
while (1)
|
|
{
|
|
- rc = __gethostbyname2_r (name, AF_INET, &th, tmpbuf,
|
|
- tmpbuflen, &h, &herrno);
|
|
+ rc = __gethostbyname2_r (name, AF_INET, &th,
|
|
+ tmpbuf.data, tmpbuf.length,
|
|
+ &h, &herrno);
|
|
if (rc != ERANGE || herrno != NETDB_INTERNAL)
|
|
break;
|
|
-
|
|
- if (!malloc_tmpbuf
|
|
- && __libc_use_alloca (alloca_used + 2 * tmpbuflen))
|
|
- tmpbuf = extend_alloca_account (tmpbuf, tmpbuflen,
|
|
- 2 * tmpbuflen,
|
|
- alloca_used);
|
|
- else
|
|
+ if (!scratch_buffer_grow (&tmpbuf))
|
|
{
|
|
- char *newp = realloc (malloc_tmpbuf ? tmpbuf : NULL,
|
|
- 2 * tmpbuflen);
|
|
- if (newp == NULL)
|
|
- {
|
|
- result = -EAI_MEMORY;
|
|
- goto free_and_return;
|
|
- }
|
|
- tmpbuf = newp;
|
|
- malloc_tmpbuf = true;
|
|
- tmpbuflen = 2 * tmpbuflen;
|
|
+ result = -EAI_MEMORY;
|
|
+ goto free_and_return;
|
|
}
|
|
}
|
|
|
|
@@ -834,21 +814,8 @@ gaih_inet (const char *name, const struc
|
|
old_res_options = _res.options;
|
|
_res.options &= ~RES_USE_INET6;
|
|
|
|
- size_t tmpbuflen = 1024 + sizeof(struct gaih_addrtuple);
|
|
- malloc_tmpbuf = !__libc_use_alloca (alloca_used + tmpbuflen);
|
|
- assert (tmpbuf == NULL);
|
|
- if (!malloc_tmpbuf)
|
|
- tmpbuf = alloca_account (tmpbuflen, alloca_used);
|
|
- else
|
|
- {
|
|
- tmpbuf = malloc (tmpbuflen);
|
|
- if (tmpbuf == NULL)
|
|
- {
|
|
- _res.options |= old_res_options & RES_USE_INET6;
|
|
- result = -EAI_MEMORY;
|
|
- goto free_and_return;
|
|
- }
|
|
- }
|
|
+ /* tmpbuf has not been used yet. */
|
|
+ assert (tmpbuf.data == tmpbuf.__space);
|
|
|
|
while (!no_more)
|
|
{
|
|
@@ -867,8 +834,9 @@ gaih_inet (const char *name, const struc
|
|
while (1)
|
|
{
|
|
rc = 0;
|
|
- status = DL_CALL_FCT (fct4, (name, pat, tmpbuf,
|
|
- tmpbuflen, &rc, &herrno,
|
|
+ status = DL_CALL_FCT (fct4, (name, pat,
|
|
+ tmpbuf.data, tmpbuf.length,
|
|
+ &rc, &herrno,
|
|
NULL));
|
|
if (status == NSS_STATUS_SUCCESS)
|
|
break;
|
|
@@ -882,24 +850,11 @@ gaih_inet (const char *name, const struc
|
|
break;
|
|
}
|
|
|
|
- if (!malloc_tmpbuf
|
|
- && __libc_use_alloca (alloca_used + 2 * tmpbuflen))
|
|
- tmpbuf = extend_alloca_account (tmpbuf, tmpbuflen,
|
|
- 2 * tmpbuflen,
|
|
- alloca_used);
|
|
- else
|
|
+ if (!scratch_buffer_grow (&tmpbuf))
|
|
{
|
|
- char *newp = realloc (malloc_tmpbuf ? tmpbuf : NULL,
|
|
- 2 * tmpbuflen);
|
|
- if (newp == NULL)
|
|
- {
|
|
- _res.options |= old_res_options & RES_USE_INET6;
|
|
- result = -EAI_MEMORY;
|
|
- goto free_and_return;
|
|
- }
|
|
- tmpbuf = newp;
|
|
- malloc_tmpbuf = true;
|
|
- tmpbuflen = 2 * tmpbuflen;
|
|
+ _res.options |= old_res_options & RES_USE_INET6;
|
|
+ result = -EAI_MEMORY;
|
|
+ goto free_and_return;
|
|
}
|
|
}
|
|
|
|
@@ -1286,8 +1241,7 @@ gaih_inet (const char *name, const struc
|
|
free (addrmem);
|
|
if (malloc_canonbuf)
|
|
free (canonbuf);
|
|
- if (malloc_tmpbuf)
|
|
- free (tmpbuf);
|
|
+ scratch_buffer_free (&tmpbuf);
|
|
|
|
return result;
|
|
}
|
|
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;
|
|
}
|
|
|