[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#731512: pu: package eglibc/2.13-38+deb7u1



Package: release.debian.org
Severity: normal
User: release.debian.org@packages.debian.org
Usertags: pu

Hi,

First of all I have to say I am a bit uncomfortable opening such a bug
report with a not so small changelog so close to the 7.3 release. I have
been problem to found time doing it, and it also took me longer than
expected due to the accumulated (security) things to fix since the
release of Wheezy. I would therefore understand you don't want to review
it now or you prefer to delay this for 7.4

Anyway let's go directly to the point an comment the changelog:

eglibc (2.13-38+deb7u1) wheezy; urgency=low

  [ Aurelien Jarno ]
  * debian/testsuite-checking/compare.sh: disable failing the build on test
    regressions to ease the pain of ongoing stable/security maintenance.

The glibc being a low level library tightly close to the kernel, some
tests might start to fail due to the buildd evolving after the release 
of Wheezy, mostly kernel upgrades to support new hardware. To avoid
FTBFS of a security or a stable upload, we usually disable the failure
in case of testsuite regression (the testsuite itself is *not*
disabled), avoiding a new upload just to ignore a false regression. That
said it's still a good idea to look at the testsuite in the build logs 
after touching some critical area.

  * patches/any/cvs-CVE-2012-44xx.diff: backport overflow fixes in strcoll,
    addressing CVE-2012-4412 and CVE-2012-4424 (Closes: #687530, #689423).
  * patches/any/CVE-2013-0242.diff: backport buffer overrun fix in regexp
    matcher, addressing CVE-2013-0242 (Closes: #699399).
  * patches/cvs-CVE-2013-1914.diff: backport stack overflow fixes in
    getaddrinfo(), addressing CVE-2013-1914 (Closes: #704623).
  * patches/any/cvs-CVE-2013-4237.diff: backport buffer overwrite fix in
    readdir_r for file systems returning file names longer than NAME_MAX
    characters, addressing CVE-2013-4237 (Closes: #719558).
    patches/kfreebsd/local-readdir_r.diff: remove superseded by the CVE
    patch.
  * patches/any/cvs-CVE-2013-4332.diff: backport integer overflow fixes
    in pvalloc, valloc, posix_memalign, memalign and aligned_alloc functions,
    addressing CVE-2013-4332 (Closes: #722536).
  * patches/any/cvs-CVE-2013-4458.diff: backport stack (frame) overflow fixes
    in getaddrinfo() when called with AF_INET6, addressing CVE-2013-4458
    (Closes: #727181).
  * patches/any/cvs-CVE-2013-4788.diff: backport patch to fix PTR_MANGLE
    ineffectivity for statically linked binaries, addressing CVE-2013-4788
    (Closes: #717178). *** Note that static binaries need to be recompiled
    to take advantage of the fix ***.

All of these patches fix security issues for which the security team has
considered it doesn't warrant a DSA, but that should still be fixed asap
in stable (and in oldstable, but that's another story). All of these
patches are taken from upstream, with a bit work of backporting for a few
of them. They are already in jessie and sid, except the one for
CVE-2013-4788 and some parts of CVE-2013-4332.


  * patches/any/cvs-findlocale-div-by-zero.diff: patch from upstream to fix
    a SIGFPE when locale-archive has been corrupted to all zeros (Closes:
    #718890, #730336).

This patch fixes an RC bug reported against the sid version, but which
also applies to stable, and which probably explain a few of the reports
we got about unbootable systems after an upgrade or a power failure and
which have been closed after a few months/years as nobody was really 
able to reproduce and/or understand the problem. The patch is commited
upstream, and is already in jessie/sid. It is also quite trivial.


  * patches/mips/cvs-prlimit64.diff: patch from upstream to fix getrlimit64
    and setrlimit64 with recent 64-bit kernels (Closes: #665897).

This patch fixes the long standing issue of setrlimit/getrlimit on MIPS,
which has been uncovered after the release of Wheezy, and which prevent
the GCC testsuite, gnupg2 and a few other programs to build. It's an
interface issue between the kernel and glibc and it took some time to 
agree on which side to fix it. This patch provides a compatibility
wrapper to fix the value passed or received by the prlimit64 syscall. It
is committed upstream, and is already in jessie/sid. It is needed to 
fully fix the buildds issue, as wrong limits are currently set by pam
outside of the chroot.


  [ Petr Salinger ]
  * patches/kfreebsd/local-initgroups-order.diff: always put supplied extra
    gid as the first entry of group list in setgroups(). Closes: #699593.

For what I understand, this has been pre-approved as part of bug#699818.

  * inline is not keyword in c89 mode, use __inline. Closes: #704598.

This patch is a small change that help a lot of code to compile.

  * sys_ktimer_settime have 4 parameters. Closes: #712196.

This fix a timer_settime on GNU/kFreeBSD due to a thinko.


All the three changes above are already in jessie/sid for a few months.

 -- Aurelien Jarno <aurel32@debian.org>  Fri, 29 Nov 2013 21:59:21 +0100


The package has been fully tested on amd64, and build tested on armhf, 
kfreebsd-i386 and mips, s390 and sparc. No regressions have been seen in
the testsuite, except on mips where some tests fails due to the
getrlimit/setrlimit bug being present on the buildds.

I am attaching the debdiff to this bug report, don't hesitate to poke me
if needed.

Thanks,
Aurelien


-- System Information:
Debian Release: jessie/sid
  APT prefers unstable
  APT policy: (500, 'unstable')
Architecture: amd64 (x86_64)
Foreign Architectures: i386

Kernel: Linux 3.11-1-amd64 (SMP w/4 CPU cores)
Locale: LANG=fr_FR.UTF-8, LC_CTYPE=fr_FR.UTF-8 (charmap=UTF-8)
Shell: /bin/sh linked to /bin/bash
Index: debian/changelog
===================================================================
--- debian/changelog	(.../tags/2.13-38)	(révision 5818)
+++ debian/changelog	(.../branches/glibc-branch-wheezy)	(révision 5872)
@@ -1,3 +1,43 @@
+eglibc (2.13-38+deb7u1) wheezy; urgency=low
+
+  [ Aurelien Jarno ]
+  * debian/testsuite-checking/compare.sh: disable failing the build on test
+    regressions to ease the pain of ongoing stable/security maintenance.
+  * patches/any/cvs-CVE-2012-44xx.diff: backport overflow fixes in strcoll,
+    addressing CVE-2012-4412 and CVE-2012-4424 (Closes: #687530, #689423).
+  * patches/any/CVE-2013-0242.diff: backport buffer overrun fix in regexp
+    matcher, addressing CVE-2013-0242 (Closes: #699399).
+  * patches/cvs-CVE-2013-1914.diff: backport stack overflow fixes in
+    getaddrinfo(), addressing CVE-2013-1914 (Closes: #704623).
+  * patches/any/cvs-CVE-2013-4237.diff: backport buffer overwrite fix in
+    readdir_r for file systems returning file names longer than NAME_MAX
+    characters, addressing CVE-2013-4237 (Closes: #719558).
+    patches/kfreebsd/local-readdir_r.diff: remove superseded by the CVE
+    patch.
+  * patches/any/cvs-CVE-2013-4332.diff: backport integer overflow fixes
+    in pvalloc, valloc, posix_memalign, memalign and aligned_alloc functions,
+    addressing CVE-2013-4332 (Closes: #722536).
+  * patches/any/cvs-CVE-2013-4458.diff: backport stack (frame) overflow fixes
+    in getaddrinfo() when called with AF_INET6, addressing CVE-2013-4458
+    (Closes: #727181).
+  * patches/any/cvs-CVE-2013-4788.diff: backport patch to fix PTR_MANGLE
+    ineffectivity for statically linked binaries, addressing CVE-2013-4788
+    (Closes: #717178). *** Note that static binaries need to be recompiled
+    to take advantage of the fix ***.
+  * patches/any/cvs-findlocale-div-by-zero.diff: patch from upstream to fix
+    a SIGFPE when locale-archive has been corrupted to all zeros (Closes:
+    #718890, #730336).
+  * patches/mips/cvs-prlimit64.diff: patch from upstream to fix getrlimit64
+    and setrlimit64 with recent 64-bit kernels (Closes: #665897).
+
+  [ Petr Salinger ]
+  * patches/kfreebsd/local-initgroups-order.diff: always put supplied extra
+    gid as the first entry of group list in setgroups(). Closes: #699593.
+  * inline is not keyword in c89 mode, use __inline. Closes: #704598.
+  * sys_ktimer_settime have 4 parameters. Closes: #712196.
+
+ -- Aurelien Jarno <aurel32@debian.org>  Thu, 05 Dec 2013 23:19:48 +0100
+
 eglibc (2.13-38) unstable; urgency=low
 
   [ Adam Conrad ]
Index: debian/testsuite-checking/compare.sh
===================================================================
--- debian/testsuite-checking/compare.sh	(.../tags/2.13-38)	(révision 5818)
+++ debian/testsuite-checking/compare.sh	(.../branches/glibc-branch-wheezy)	(révision 5872)
@@ -16,7 +16,8 @@
 if [ -n "$REGRESSIONS" ] ; then
   echo "Encountered regressions that don't match expected failures:"
   echo "$REGRESSIONS"
-  exit 1
+  # disable build failures on testsuite regressions to ease security updates:
+  exit 0
 else
   echo "Passed regression testing. No new failures, no changed error values."
   exit 0
Index: debian/patches/kfreebsd/local-readdir_r.diff
===================================================================
--- debian/patches/kfreebsd/local-readdir_r.diff	(.../tags/2.13-38)	(révision 5818)
+++ debian/patches/kfreebsd/local-readdir_r.diff	(.../branches/glibc-branch-wheezy)	(révision 5872)
@@ -1,47 +0,0 @@
----
- sysdeps/unix/readdir_r.c |   33 +++++++++++++++++++++++++--------
- 1 file changed, 25 insertions(+), 8 deletions(-)
-
---- a/sysdeps/unix/readdir_r.c
-+++ b/sysdeps/unix/readdir_r.c
-@@ -114,15 +114,32 @@
- 
-   if (dp != NULL)
-     {
--#ifdef GETDENTS_64BIT_ALIGNED
--      /* The d_reclen value might include padding which is not part of
--	 the DIRENT_TYPE data structure.  */
--      reclen = MIN (reclen,
--		    offsetof (DIRENT_TYPE, d_name) + sizeof (dp->d_name));
--#endif
-+	/* The required size of *entry, according to POSIX, is
-+	offsetof (DIRENT_TYPE, d_name[0]) + NAME_MAX + 1.
-+	We must not write beyond the end of *entry.  On some operating
-+	systems, dp->d_reclen may be larger; in this case, copy only as
-+	many bytes as needed.  Also give an error if d_name is too long.  */
-+#ifdef _DIRENT_HAVE_D_RECLEN
-+      /* DIRENT_TYPE is of variable size, with d_name as its last entry.  */
-+      size_t namelen;
-+# ifdef _DIRENT_HAVE_D_NAMLEN
-+      namelen = dp->d_namlen;
-+# else
-+      namelen = strlen (dp->d_name);
-+# endif
-+
-+      if (namelen <= NAME_MAX)
-+	*result = memcpy (entry, dp,
-+			  offsetof (DIRENT_TYPE, d_name[0]) + namelen + 1);
-+      else
-+	{
-+          errno = EOVERFLOW;
-+          dp = NULL;
-+          *result = NULL;
-+        }
-+#else
-+      /* DIRENT_TYPE is of fixed size.  */
-       *result = memcpy (entry, dp, reclen);
--#ifdef GETDENTS_64BIT_ALIGNED
--      entry->d_reclen = reclen;
- #endif
-     }
-   else
Index: debian/patches/kfreebsd/local-sysdeps.diff
===================================================================
--- debian/patches/kfreebsd/local-sysdeps.diff	(.../tags/2.13-38)	(révision 5818)
+++ debian/patches/kfreebsd/local-sysdeps.diff	(.../branches/glibc-branch-wheezy)	(révision 5872)
@@ -23159,7 +23159,7 @@
 + * Given a filesystem name, determine if it is resident in the kernel,
 + * and if it is resident, return its xvfsconf structure.
 + */
-+static inline int
++static __inline int
 +getvfsbyname(const char *fsname, struct xvfsconf *vfcp)
 +{
 +	struct xvfsconf *xvfsp;
@@ -24889,7 +24889,7 @@
 +sys_clock_settime	-	clock_settime		i:ip		__syscall_clock_settime
 +sys_ktimer_create	-	ktimer_create		i:iPp		__syscall_ktimer_create
 +sys_ktimer_gettime	-	ktimer_gettime		i:ip		__syscall_ktimer_gettime
-+sys_ktimer_settime	-	ktimer_settime		i:ip		__syscall_ktimer_settime
++sys_ktimer_settime	-	ktimer_settime		i:iipp		__syscall_ktimer_settime
 +sys_ktimer_getoverrun	-	ktimer_getoverrun	i:i		__syscall_ktimer_getoverrun
 +sys_ktimer_delete	-	ktimer_delete		i:i		__syscall_ktimer_delete
 +sys_execve		-	execve			i:ppp		__syscall_execve
Index: debian/patches/kfreebsd/local-initgroups-order.diff
===================================================================
--- debian/patches/kfreebsd/local-initgroups-order.diff	(.../tags/2.13-38)	(révision 0)
+++ debian/patches/kfreebsd/local-initgroups-order.diff	(.../branches/glibc-branch-wheezy)	(révision 5872)
@@ -0,0 +1,38 @@
+
+ setgroups(size, groups) changes egid on kfreebsd, 
+ precisely groups[0] is the new egid
+
+ initgroups(user, gid) prepares the "groups" list
+ via internal_getgrouplist(). 
+ It puts supplied gid as the first entry in all but NSCD cases.
+ Fix the remaining NSCD case, see #698102, #699593.
+
+
+--- a/nscd/nscd_initgroups.c
++++ b/nscd/nscd_initgroups.c
+@@ -145,15 +145,23 @@
+     }
+ 
+   /* Check whether GROUP is part of the mix.  If not, add it.  */
++  /* The GROUP have to be in the first entry */
+   if (retval >= 0)
+     {
+       int cnt;
++      gid_t sg, tg;
++      sg = group;
+       for (cnt = 0; cnt < retval; ++cnt)
+-	if ((*groupsp)[cnt] == group)
++      {
++        tg = (*groupsp)[cnt];
++        (*groupsp)[cnt] = sg;
++        if (tg == group)
+ 	  break;
++        sg = tg;
++      }  
+ 
+       if (cnt == retval)
+-	(*groupsp)[retval++] = group;
++	(*groupsp)[retval++] = sg;
+     }
+ 
+  out_close:
Index: debian/patches/series.kfreebsd-amd64
===================================================================
--- debian/patches/series.kfreebsd-amd64	(.../tags/2.13-38)	(révision 5818)
+++ debian/patches/series.kfreebsd-amd64	(.../branches/glibc-branch-wheezy)	(révision 5872)
@@ -4,9 +4,9 @@
 kfreebsd/local-nosavesse.diff
 kfreebsd/local-memusage_no_mremap.diff
 kfreebsd/local-pthread_at_fork.diff
-kfreebsd/local-readdir_r.diff
 kfreebsd/local-scripts.diff
 kfreebsd/local-sys_queue_h.diff
 kfreebsd/local-sysdeps.diff
 kfreebsd/local-undef-glibc.diff
 kfreebsd/local-use-thr-primitives.diff
+kfreebsd/local-initgroups-order.diff
Index: debian/patches/any/cvs-CVE-2013-0242.diff
===================================================================
--- debian/patches/any/cvs-CVE-2013-0242.diff	(.../tags/2.13-38)	(révision 0)
+++ debian/patches/any/cvs-CVE-2013-0242.diff	(.../branches/glibc-branch-wheezy)	(révision 5872)
@@ -0,0 +1,139 @@
+2013-02-12  Andreas Schwab  <schwab@suse.de>
+ 
+	[BZ #15078]
+	* posix/regexec.c (extend_buffers): Add parameter min_len.
+	(check_matching): Pass minimum needed length.
+	(clean_state_log_if_needed): Likewise.
+	(get_subexp): Likewise.
+	* posix/Makefile (tests): Add bug-regex34.
+	(bug-regex34-ENV): Define.
+	* posix/bug-regex34.c: New file.
+
+--- a/posix/bug-regex34.c
++++ b/posix/bug-regex34.c
+@@ -0,0 +1,46 @@
++/* Test re_search with multi-byte characters in UTF-8.
++   Copyright (C) 2013 Free Software Foundation, Inc.
++   This file is part of the GNU C Library.
++
++   The GNU C Library is free software; you can redistribute it and/or
++   modify it under the terms of the GNU Lesser General Public
++   License as published by the Free Software Foundation; either
++   version 2.1 of the License, or (at your option) any later version.
++
++   The GNU C Library is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++   Lesser General Public License for more details.
++
++   You should have received a copy of the GNU Lesser General Public
++   License along with the GNU C Library; if not, see
++   <http://www.gnu.org/licenses/>.  */
++
++#define _GNU_SOURCE 1
++#include <stdio.h>
++#include <string.h>
++#include <locale.h>
++#include <regex.h>
++
++static int
++do_test (void)
++{
++  struct re_pattern_buffer r;
++  /* ကျွန်ုပ်x */
++  const char *s = "\xe1\x80\x80\xe1\x80\xbb\xe1\x80\xbd\xe1\x80\x94\xe1\x80\xba\xe1\x80\xaf\xe1\x80\x95\xe1\x80\xbax";
++
++  if (setlocale (LC_ALL, "en_US.UTF-8") == NULL)
++    {
++      puts ("setlocale failed");
++      return 1;
++    }
++  memset (&r, 0, sizeof (r));
++
++  re_compile_pattern ("[^x]x", 5, &r);
++  /* This was triggering a buffer overflow.  */
++  re_search (&r, s, strlen (s), 0, strlen (s), 0);
++  return 0;
++}
++
++#define TEST_FUNCTION do_test ()
++#include "../test-skeleton.c"
+--- a/posix/Makefile
++++ b/posix/Makefile
+@@ -105,7 +105,7 @@
+ 		   tst-execvp3 tst-execvp4 \
+ 		   tst-fnmatch2 tst-cpucount tst-cpuset \
+ 		   bug-getopt1 bug-getopt2 bug-getopt3 bug-getopt4 \
+-		   bug-getopt5
++		   bug-getopt5 bug-regex34
+ tests-$(OPTION_EGLIBC_LOCALE_CODE)					    \
+ 		+= tst-fnmatch tst-regexloc bug-regex1 bug-regex5 \
+ 		   bug-regex23 bug-regex25
+@@ -240,6 +240,7 @@
+ bug-regex25-ENV = LOCPATH=$(common-objpfx)localedata
+ bug-regex26-ENV = LOCPATH=$(common-objpfx)localedata
+ bug-regex30-ENV = LOCPATH=$(common-objpfx)localedata
++bug-regex34-ENV = LOCPATH=$(common-objpfx)localedata
+ tst-rxspencer-ARGS = rxspencer/tests
+ ifeq (y,$(OPTION_EGLIBC_LOCALE_CODE))
+ tst-rxspencer-ARGS += --utf8 
+--- a/posix/regexec.c
++++ b/posix/regexec.c
+@@ -200,7 +200,7 @@
+ static int check_node_accept (const re_match_context_t *mctx,
+ 			      const re_token_t *node, int idx)
+      internal_function;
+-static reg_errcode_t extend_buffers (re_match_context_t *mctx)
++static reg_errcode_t extend_buffers (re_match_context_t *mctx, int min_len)
+      internal_function;
+ 
+ /* Entry point for POSIX code.  */
+@@ -1147,7 +1147,7 @@
+ 	  || (BE (next_char_idx >= mctx->input.valid_len, 0)
+ 	      && mctx->input.valid_len < mctx->input.len))
+ 	{
+-	  err = extend_buffers (mctx);
++	  err = extend_buffers (mctx, next_char_idx + 1);
+ 	  if (BE (err != REG_NOERROR, 0))
+ 	    {
+ 	      assert (err == REG_ESPACE);
+@@ -1725,7 +1725,7 @@
+ 	  && mctx->input.valid_len < mctx->input.len))
+     {
+       reg_errcode_t err;
+-      err = extend_buffers (mctx);
++      err = extend_buffers (mctx, next_state_log_idx + 1);
+       if (BE (err != REG_NOERROR, 0))
+ 	return err;
+     }
+@@ -2779,7 +2779,7 @@
+ 		  if (bkref_str_off >= mctx->input.len)
+ 		    break;
+ 
+-		  err = extend_buffers (mctx);
++		  err = extend_buffers (mctx, bkref_str_off + 1);
+ 		  if (BE (err != REG_NOERROR, 0))
+ 		    return err;
+ 
+@@ -4097,7 +4097,7 @@
+ 
+ static reg_errcode_t
+ internal_function __attribute_warn_unused_result__
+-extend_buffers (re_match_context_t *mctx)
++extend_buffers (re_match_context_t *mctx, int min_len)
+ {
+   reg_errcode_t ret;
+   re_string_t *pstr = &mctx->input;
+@@ -4106,8 +4106,10 @@
+   if (BE (INT_MAX / 2 / sizeof (re_dfastate_t *) <= pstr->bufs_len, 0))
+     return REG_ESPACE;
+ 
+-  /* Double the lengthes of the buffers.  */
+-  ret = re_string_realloc_buffers (pstr, MIN (pstr->len, pstr->bufs_len * 2));
++  /* Double the lengthes of the buffers, but allocate at least MIN_LEN.  */
++  ret = re_string_realloc_buffers (pstr,
++				   MAX (min_len,
++					MIN (pstr->len, pstr->bufs_len * 2)));
+   if (BE (ret != REG_NOERROR, 0))
+     return ret;
+ 
Index: debian/patches/any/cvs-findlocale-div-by-zero.diff
===================================================================
--- debian/patches/any/cvs-findlocale-div-by-zero.diff	(.../tags/2.13-38)	(révision 0)
+++ debian/patches/any/cvs-findlocale-div-by-zero.diff	(.../branches/glibc-branch-wheezy)	(révision 5872)
@@ -0,0 +1,33 @@
+commit 18d1425127e5712dda888bb280d5d1a038a45c7f
+Author: Aurelien Jarno <aurelien@aurel32.net>
+Date:   Tue Dec 3 11:16:16 2013 +0100
+
+    locale: don't crash if locale-archive contains all zeros
+
+    In case of power failure followed by filesystem issues locale-archive
+    can end-up containing all zeros. In that case all calls to setlocale()
+    generate a SIGFPE. This renders a system with a default non-C locale
+    unbootable.
+
+    Avoid this by ignoring the locale instead of generating a SIGFPE.
+
+2013-12-03  Aurelien Jarno  <aurelien@aurel32.net>
+
+	* locale/loadarchive.c (_nl_load_locale_from_archive): Avoid
+	division by 0.
+
+diff --git a/locale/loadarchive.c b/locale/loadarchive.c
+index 70136dc..f723780 100644
+--- a/locale/loadarchive.c
++++ b/locale/loadarchive.c
+@@ -274,6 +274,10 @@ _nl_load_locale_from_archive (int category, const char **namep)
+   namehashtab = (struct namehashent *) ((char *) head
+ 					+ head->namehash_offset);
+ 
++  /* Avoid division by 0 if the file is corrupted.  */
++  if (__glibc_unlikely (head->namehash_size == 0))
++    goto close_and_out;
++
+   idx = hval % head->namehash_size;
+   incr = 1 + hval % (head->namehash_size - 2);
+ 
Index: debian/patches/any/cvs-CVE-2013-4332.diff
===================================================================
--- debian/patches/any/cvs-CVE-2013-4332.diff	(.../tags/2.13-38)	(révision 0)
+++ debian/patches/any/cvs-CVE-2013-4332.diff	(.../branches/glibc-branch-wheezy)	(révision 5872)
@@ -0,0 +1,110 @@
+2013-10-30  Will Newton  <will.newton@linaro.org>
+
+	[BZ #16038]
+	* malloc/hooks.c (memalign_check): Limit alignment to the
+	maximum representable power of two.
+	* malloc/malloc.c (__libc_memalign): Likewise.
+
+2013-10-10  Will Newton  <will.newton@linaro.org>
+
+	* malloc/hooks.c (memalign_check): Ensure the value of bytes
+	passed to _int_memalign does not overflow.
+ 
+2013-09-11  Will Newton  <will.newton@linaro.org>
+ 
+	[BZ #15857]
+	* malloc/malloc.c (__libc_memalign): Check the value of bytes
+	does not overflow.
+
+2013-09-11  Will Newton  <will.newton@linaro.org>
+
+ 	[BZ #15856]
+ 	* malloc/malloc.c (__libc_valloc): Check the value of bytes
+ 	does not overflow.
+
+2013-09-11  Will Newton  <will.newton@linaro.org>
+
+	[BZ #15855]
+	* malloc/malloc.c (__libc_pvalloc): Check the value of bytes
+	does not overflow.
+
+--- a/malloc/malloc.c
++++ b/malloc/malloc.c
+@@ -3874,6 +3874,21 @@
+   /* Otherwise, ensure that it is at least a minimum chunk size */
+   if (alignment <  MINSIZE) alignment = MINSIZE;
+ 
++  /* If the alignment is greater than SIZE_MAX / 2 + 1 it cannot be a
++     power of 2 and will cause overflow in the check below.  */
++  if (alignment > SIZE_MAX / 2 + 1)
++    {
++      __set_errno (EINVAL);
++      return 0;
++    }
++
++  /* Check for overflow.  */
++  if (bytes > SIZE_MAX - alignment - MINSIZE)
++    {
++      __set_errno (ENOMEM);
++      return 0;
++    }
++
+   arena_get(ar_ptr, bytes + alignment + MINSIZE);
+   if(!ar_ptr)
+     return 0;
+@@ -3919,6 +3934,13 @@
+ 
+   size_t pagesz = mp_.pagesize;
+ 
++  /* Check for overflow.  */
++  if (bytes > SIZE_MAX - pagesz - MINSIZE)
++    {
++      __set_errno (ENOMEM);
++      return 0;
++    }
++
+   __malloc_ptr_t (*hook) __MALLOC_PMT ((size_t, size_t,
+ 					__const __malloc_ptr_t)) =
+     force_reg (__memalign_hook);
+@@ -3967,6 +3989,13 @@
+   size_t page_mask = mp_.pagesize - 1;
+   size_t rounded_bytes = (bytes + page_mask) & ~(page_mask);
+ 
++  /* Check for overflow.  */
++  if (bytes > SIZE_MAX - 2*pagesz - MINSIZE)
++    {
++      __set_errno (ENOMEM);
++      return 0;
++    }
++
+   __malloc_ptr_t (*hook) __MALLOC_PMT ((size_t, size_t,
+ 					__const __malloc_ptr_t)) =
+     force_reg (__memalign_hook);
+--- a/malloc/hooks.c
++++ b/malloc/hooks.c
+@@ -404,10 +404,21 @@
+   if (alignment <= MALLOC_ALIGNMENT) return malloc_check(bytes, NULL);
+   if (alignment <  MINSIZE) alignment = MINSIZE;
+ 
+-  if (bytes+1 == 0) {
+-    MALLOC_FAILURE_ACTION;
+-    return NULL;
+-  }
++  /* If the alignment is greater than SIZE_MAX / 2 + 1 it cannot be a
++     power of 2 and will cause overflow in the check below.  */
++  if (alignment > SIZE_MAX / 2 + 1)
++    {
++      __set_errno (EINVAL);
++      return 0;
++    }
++
++  /* Check for overflow.  */
++  if (bytes > SIZE_MAX - alignment - MINSIZE)
++    {
++      MALLOC_FAILURE_ACTION;
++      return 0;
++    }
++
+   checked_request2size(bytes+1, nb);
+   (void)mutex_lock(&main_arena.mutex);
+   mem = (top_check() >= 0) ? _int_memalign(&main_arena, alignment, bytes+1) :
Index: debian/patches/any/cvs-CVE-2013-1914.diff
===================================================================
--- debian/patches/any/cvs-CVE-2013-1914.diff	(.../tags/2.13-38)	(révision 0)
+++ debian/patches/any/cvs-CVE-2013-1914.diff	(.../branches/glibc-branch-wheezy)	(révision 5872)
@@ -0,0 +1,48 @@
+2013-04-03  Andreas Schwab  <schwab@suse.de>
+
+	[BZ #15330]
+	* sysdeps/posix/getaddrinfo.c (getaddrinfo): Allocate results and
+	order arrays from heap if bigger than alloca cutoff.
+
+--- a/sysdeps/posix/getaddrinfo.c
++++ b/sysdeps/posix/getaddrinfo.c
+@@ -2207,11 +2207,27 @@
+       __typeof (once) old_once = once;
+       __libc_once (once, gaiconf_init);
+       /* Sort results according to RFC 3484.  */
+-      struct sort_result results[nresults];
+-      size_t order[nresults];
++      struct sort_result *results;
++      size_t *order;
+       struct addrinfo *q;
+       struct addrinfo *last = NULL;
+       char *canonname = NULL;
++      bool malloc_results;
++
++      malloc_results
++	= !__libc_use_alloca (nresults * (sizeof (*results) + sizeof (size_t)));
++      if (malloc_results)
++	{
++	  results = malloc (nresults * (sizeof (*results) + sizeof (size_t)));
++	  if (results == NULL)
++	    {
++	      free (in6ai);
++	      return EAI_MEMORY;
++	    }
++	}
++      else
++	results = alloca (nresults * (sizeof (*results) + sizeof (size_t)));
++      order = (size_t *) (results + nresults);
+ 
+       /* If we have information about deprecated and temporary addresses
+ 	 sort the array now.  */
+@@ -2397,6 +2413,9 @@
+ 
+       /* Fill in the canonical name into the new first entry.  */
+       p->ai_canonname = canonname;
++
++      if (malloc_results)
++	free (results);
+     }
+ 
+   free (in6ai);
Index: debian/patches/any/cvs-CVE-2013-4788.diff
===================================================================
--- debian/patches/any/cvs-CVE-2013-4788.diff	(.../tags/2.13-38)	(révision 0)
+++ debian/patches/any/cvs-CVE-2013-4788.diff	(.../branches/glibc-branch-wheezy)	(révision 5872)
@@ -0,0 +1,420 @@
+2013-09-25  Adhemerval Zanella  <azanella@linux.vnet.ibm.com>
+
+	* sysdeps/powerpc/powerpc64/stackguard-macros.h (POINTER_CHK_GUARD:
+	Fix thread ID register.
+
+2013-09-23  Carlos O'Donell  <carlos@redhat.com>
+
+ 	[BZ #15754]
+	* sysdeps/generic/stackguard-macros.h: If PTRGUARD_LOCAL use
+	__pointer_chk_guard_local, otherwise __pointer_chk_guard.
+	* elf/Makefile: Define CFLAGS-tst-ptrguard1-static.c.
+
+	[BZ #15754]
+	* elf/Makefile (tests): Add tst-ptrguard1.
+	(tests-static): Add tst-ptrguard1-static.
+	(tst-ptrguard1-ARGS): Define.
+	(tst-ptrguard1-static-ARGS): Define.
+	* elf/tst-ptrguard1.c: New file.
+	* elf/tst-ptrguard1-static.c: New file.
+	* sysdeps/x86_64/stackguard-macros.h: Define POINTER_CHK_GUARD.
+	* sysdeps/i386/stackguard-macros.h: Likewise.
+	* sysdeps/powerpc/powerpc32/stackguard-macros.h: Likewise.
+	* sysdeps/powerpc/powerpc64/stackguard-macros.h: Likewise.
+	* sysdeps/s390/s390-32/stackguard-macros.h: Likewise.
+	* sysdeps/s390/s390-64/stackguard-macros.h: Likewise.
+	* sysdeps/sparc/sparc32/stackguard-macros.h: Likewise.
+	* sysdeps/sparc/sparc64/stackguard-macros.h: Likewise.
+
+2013-09-23  Hector Marco  <hecmargi@upv.es>
+	    Ismael Ripoll  <iripoll@disca.upv.es>
+	    Carlos O'Donell  <carlos@redhat.com>
+
+	[BZ #15754]
+	* sysdeps/generic/stackguard-macros.h: Define
+	__pointer_chk_guard_local and POINTER_CHK_GUARD.
+	* csu/libc-start.c [!SHARED && !THREAD_SET_POINTER_GUARD]:
+	Define __pointer_chk_guard_local.
+	(LIBC_START_MAIN) [!SHARED]: Call _dl_setup_pointer_guard.
+	Use THREAD_SET_POINTER_GUARD or set __pointer_chk_guard_local.
+
+2013-09-22  Carlos O'Donell  <carlos@redhat.com>
+
+	[BZ #15754]
+	* sysdeps/ia64/stackguard-macros.h: Define POINTER_CHK_GUARD.
+
+
+--- a/csu/libc-start.c
++++ b/csu/libc-start.c
+@@ -39,6 +39,12 @@
+    in thread local area.  */
+ uintptr_t __stack_chk_guard attribute_relro;
+ # endif
++# ifndef  THREAD_SET_POINTER_GUARD
++/* Only exported for architectures that don't store the pointer guard
++   value in thread local area.  */
++uintptr_t __pointer_chk_guard_local
++	attribute_relro attribute_hidden __attribute__ ((nocommon));
++# endif
+ #endif
+ 
+ #ifdef HAVE_PTR_NTHREADS
+@@ -154,6 +160,16 @@
+ # else
+   __stack_chk_guard = stack_chk_guard;
+ # endif
++
++  /* Set up the pointer guard value.  */
++  uintptr_t pointer_chk_guard = _dl_setup_pointer_guard (_dl_random,
++							 stack_chk_guard);
++# ifdef THREAD_SET_POINTER_GUARD
++  THREAD_SET_POINTER_GUARD (pointer_chk_guard);
++# else
++  __pointer_chk_guard_local = pointer_chk_guard;
++# endif
++
+ #endif
+ 
+   /* Register the destructor of the dynamic linker if there is any.  */
+--- a/elf/Makefile
++++ b/elf/Makefile
+@@ -179,7 +179,7 @@
+ tests += tst-array1 tst-array2 tst-array3 tst-array4 tst-array5
+ endif
+ ifeq (yes,$(build-static))
+-tests-static = tst-tls1-static tst-tls2-static tst-stackguard1-static
++tests-static = tst-tls1-static tst-tls2-static tst-stackguard1-static tst-ptrguard1-static
+ ifeq (yesyesyes,$(build-static)$(build-shared)$(elf))
+ tests-static += tst-tls9-static
+ tst-tls9-static-ENV = \
+@@ -208,7 +208,8 @@
+ 	 tst-audit1 tst-audit2 \
+ 	 tst-stackguard1 tst-addr1 tst-thrlock \
+ 	 tst-unique1 tst-unique2 \
+-	 tst-initorder
++	 tst-initorder \
++	 tst-ptrguard1
+ #	 reldep9
+ test-srcs = tst-pathopt
+ tests-execstack-yes = tst-execstack tst-execstack-needed tst-execstack-prog
+@@ -1076,6 +1077,12 @@
+ tst-stackguard1-ARGS = --command "$(local-built-program-cmd) --child"
+ tst-stackguard1-static-ARGS = --command "$(objpfx)tst-stackguard1-static --child"
+ 
++tst-ptrguard1-ARGS = --command "$(local-built-program-cmd) --child"
++# When built statically, the pointer guard interface uses
++# __pointer_chk_guard_local.
++CFLAGS-tst-ptrguard1-static.c = -DPTRGUARD_LOCAL
++tst-ptrguard1-static-ARGS = --command "$(objpfx)tst-ptrguard1-static --child"
++
+ $(objpfx)tst-leaks1: $(libdl)
+ $(objpfx)tst-leaks1-mem: $(objpfx)tst-leaks1.out
+ 	$(common-objpfx)malloc/mtrace $(objpfx)tst-leaks1.mtrace > $@
+--- /dev/null
++++ b/elf/tst-ptrguard1-static.c
+@@ -0,0 +1 @@
++#include "tst-ptrguard1.c"
+--- /dev/null
++++ b/elf/tst-ptrguard1.c
+@@ -0,0 +1,202 @@
++/* Copyright (C) 2013 Free Software Foundation, Inc.
++   This file is part of the GNU C Library.
++
++   The GNU C Library is free software; you can redistribute it and/or
++   modify it under the terms of the GNU Lesser General Public
++   License as published by the Free Software Foundation; either
++   version 2.1 of the License, or (at your option) any later version.
++
++   The GNU C Library is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++   Lesser General Public License for more details.
++
++   You should have received a copy of the GNU Lesser General Public
++   License along with the GNU C Library; if not, see
++   <http://www.gnu.org/licenses/>.  */
++
++#include <errno.h>
++#include <stdbool.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <sys/wait.h>
++#include <stackguard-macros.h>
++#include <tls.h>
++#include <unistd.h>
++
++#ifndef POINTER_CHK_GUARD
++extern uintptr_t __pointer_chk_guard;
++# define POINTER_CHK_GUARD __pointer_chk_guard
++#endif
++
++static const char *command;
++static bool child;
++static uintptr_t ptr_chk_guard_copy;
++static bool ptr_chk_guard_copy_set;
++static int fds[2];
++
++static void __attribute__ ((constructor))
++con (void)
++{
++  ptr_chk_guard_copy = POINTER_CHK_GUARD;
++  ptr_chk_guard_copy_set = true;
++}
++
++static int
++uintptr_t_cmp (const void *a, const void *b)
++{
++  if (*(uintptr_t *) a < *(uintptr_t *) b)
++    return 1;
++  if (*(uintptr_t *) a > *(uintptr_t *) b)
++    return -1;
++  return 0;
++}
++
++static int
++do_test (void)
++{
++  if (!ptr_chk_guard_copy_set)
++    {
++      puts ("constructor has not been run");
++      return 1;
++    }
++
++  if (ptr_chk_guard_copy != POINTER_CHK_GUARD)
++    {
++      puts ("POINTER_CHK_GUARD changed between constructor and do_test");
++      return 1;
++    }
++
++  if (child)
++    {
++      write (2, &ptr_chk_guard_copy, sizeof (ptr_chk_guard_copy));
++      return 0;
++    }
++
++  if (command == NULL)
++    {
++      puts ("missing --command or --child argument");
++      return 1;
++    }
++
++#define N 16
++  uintptr_t child_ptr_chk_guards[N + 1];
++  child_ptr_chk_guards[N] = ptr_chk_guard_copy;
++  int i;
++  for (i = 0; i < N; ++i)
++    {
++      if (pipe (fds) < 0)
++	{
++	  printf ("couldn't create pipe: %m\n");
++	  return 1;
++	}
++
++      pid_t pid = fork ();
++      if (pid < 0)
++	{
++	  printf ("fork failed: %m\n");
++	  return 1;
++	}
++
++      if (!pid)
++	{
++	  if (ptr_chk_guard_copy != POINTER_CHK_GUARD)
++	    {
++	      puts ("POINTER_CHK_GUARD changed after fork");
++	      exit (1);
++	    }
++
++	  close (fds[0]);
++	  close (2);
++	  dup2 (fds[1], 2);
++	  close (fds[1]);
++
++	  system (command);
++	  exit (0);
++	}
++
++      close (fds[1]);
++
++      if (TEMP_FAILURE_RETRY (read (fds[0], &child_ptr_chk_guards[i],
++				    sizeof (uintptr_t))) != sizeof (uintptr_t))
++	{
++	  puts ("could not read ptr_chk_guard value from child");
++	  return 1;
++	}
++
++      close (fds[0]);
++
++      pid_t termpid;
++      int status;
++      termpid = TEMP_FAILURE_RETRY (waitpid (pid, &status, 0));
++      if (termpid == -1)
++	{
++	  printf ("waitpid failed: %m\n");
++	  return 1;
++	}
++      else if (termpid != pid)
++	{
++	  printf ("waitpid returned %ld != %ld\n",
++		  (long int) termpid, (long int) pid);
++	  return 1;
++	}
++      else if (!WIFEXITED (status) || WEXITSTATUS (status))
++	{
++	  puts ("child hasn't exited with exit status 0");
++	  return 1;
++	}
++    }
++
++  qsort (child_ptr_chk_guards, N + 1, sizeof (uintptr_t), uintptr_t_cmp);
++
++  /* The default pointer guard is the same as the default stack guard.
++     They are only set to default if dl_random is NULL.  */
++  uintptr_t default_guard = 0;
++  unsigned char *p = (unsigned char *) &default_guard;
++  p[sizeof (uintptr_t) - 1] = 255;
++  p[sizeof (uintptr_t) - 2] = '\n';
++  p[0] = 0;
++
++  /* Test if the pointer guard canaries are either randomized,
++     or equal to the default pointer guard value.
++     Even with randomized pointer guards it might happen
++     that the random number generator generates the same
++     values, but if that happens in more than half from
++     the 16 runs, something is very wrong.  */
++  int ndifferences = 0;
++  int ndefaults = 0;
++  for (i = 0; i < N; ++i)
++    {
++      if (child_ptr_chk_guards[i] != child_ptr_chk_guards[i+1])
++	ndifferences++;
++      else if (child_ptr_chk_guards[i] == default_guard)
++	ndefaults++;
++    }
++
++  printf ("differences %d defaults %d\n", ndifferences, ndefaults);
++
++  if (ndifferences < N / 2 && ndefaults < N / 2)
++    {
++      puts ("pointer guard values are not randomized enough");
++      puts ("nor equal to the default value");
++      return 1;
++    }
++
++  return 0;
++}
++
++#define OPT_COMMAND	10000
++#define OPT_CHILD	10001
++#define CMDLINE_OPTIONS	\
++  { "command", required_argument, NULL, OPT_COMMAND },  \
++  { "child", no_argument, NULL, OPT_CHILD },
++#define CMDLINE_PROCESS	\
++  case OPT_COMMAND:	\
++    command = optarg;	\
++    break;		\
++  case OPT_CHILD:	\
++    child = true;	\
++    break;
++#define TEST_FUNCTION do_test ()
++#include "../test-skeleton.c"
+--- a/elf/stackguard-macros.h
++++ b/elf/stackguard-macros.h
+@@ -3,31 +3,96 @@
+ #ifdef __i386__
+ # define STACK_CHK_GUARD \
+   ({ uintptr_t x; asm ("movl %%gs:0x14, %0" : "=r" (x)); x; })
++#define POINTER_CHK_GUARD \
++  ({							\
++     uintptr_t x;					\
++     asm ("movl %%gs:%c1, %0" : "=r" (x)		\
++	  : "i" (offsetof (tcbhead_t, pointer_guard)));	\
++     x;							\
++   })
+ #elif defined __x86_64__
+ # define STACK_CHK_GUARD \
+   ({ uintptr_t x; asm ("movq %%fs:0x28, %0" : "=r" (x)); x; })
++#define POINTER_CHK_GUARD \
++  ({ uintptr_t x;						\
++     asm ("mov %%fs:%c1, %0" : "=r" (x)				\
++	  : "i" (offsetof (tcbhead_t, pointer_guard))); x; })
+ #elif defined __powerpc64__
+ # define STACK_CHK_GUARD \
+   ({ uintptr_t x; asm ("ld %0,-28688(13)" : "=r" (x)); x; })
++#define POINTER_CHK_GUARD \
++  ({												\
++     uintptr_t x;										\
++     asm ("ld %0,%1(13)"									\
++	  : "=r" (x)										\
++	  : "i" (offsetof (tcbhead_t, pointer_guard) - TLS_TCB_OFFSET - sizeof (tcbhead_t))	\
++         );											\
++     x;												\
++   })
+ #elif defined __powerpc__
+ # define STACK_CHK_GUARD \
+   ({ uintptr_t x; asm ("lwz %0,-28680(2)" : "=r" (x)); x; })
++#define POINTER_CHK_GUARD \
++  ({												\
++     uintptr_t x;										\
++     asm ("lwz %0,%1(2)"									\
++	  : "=r" (x)										\
++	  : "i" (offsetof (tcbhead_t, pointer_guard) - TLS_TCB_OFFSET - sizeof (tcbhead_t))	\
++         );											\
++     x;												\
++   })
+ #elif defined __sparc__ && defined __arch64__
+ # define STACK_CHK_GUARD \
+   ({ uintptr_t x; asm ("ldx [%%g7+0x28], %0" : "=r" (x)); x; })
++#define POINTER_CHK_GUARD \
++  ({ uintptr_t x; asm ("ldx [%%g7+0x30], %0" : "=r" (x)); x; })
+ #elif defined __sparc__
+ # define STACK_CHK_GUARD \
+   ({ uintptr_t x; asm ("ld [%%g7+0x14], %0" : "=r" (x)); x; })
++#define POINTER_CHK_GUARD \
++  ({ uintptr_t x; asm ("ld [%%g7+0x18], %0" : "=r" (x)); x; })
+ #elif defined __s390x__
+ # define STACK_CHK_GUARD \
+   ({ uintptr_t x; asm ("ear %0,%%a0; sllg %0,%0,32; ear %0,%%a1; lg %0,0x28(%0)" : "=a" (x)); x; })
++/* On s390/s390x there is no unique pointer guard, instead we use the
++   same value as the stack guard.  */
++#define POINTER_CHK_GUARD \
++  ({							\
++     uintptr_t x;					\
++     asm ("ear %0,%%a0;"				\
++	  "sllg %0,%0,32;"				\
++	  "ear %0,%%a1;"				\
++	  "lg %0,%1(%0)"				\
++	 : "=a" (x)					\
++	 : "i" (offsetof (tcbhead_t, stack_guard)));	\
++     x;							\
++   })
+ #elif defined __s390__
+ # define STACK_CHK_GUARD \
+   ({ uintptr_t x; asm ("ear %0,%%a0; l %0,0x14(%0)" : "=a" (x)); x; })
++/* On s390/s390x there is no unique pointer guard, instead we use the
++   same value as the stack guard.  */
++#define POINTER_CHK_GUARD \
++  ({							\
++     uintptr_t x;					\
++     asm ("ear %0,%%a0; l %0,%1(%0)"			\
++	  : "=a" (x)					\
++	  : "i" (offsetof (tcbhead_t, stack_guard)));	\
++     x;							\
++   })
+ #elif defined __ia64__
+ # define STACK_CHK_GUARD \
+   ({ uintptr_t x; asm ("adds %0 = -8, r13;; ld8 %0 = [%0]" : "=r" (x)); x; })
++#define POINTER_CHK_GUARD \
++  ({ uintptr_t x; asm ("adds %0 = -16, r13;; ld8 %0 = [%0]" : "=r" (x)); x; })
+ #else
+ extern uintptr_t __stack_chk_guard;
+ # define STACK_CHK_GUARD __stack_chk_guard
++#ifdef PTRGUARD_LOCAL
++extern uintptr_t __pointer_chk_guard_local;
++# define POINTER_CHK_GUARD __pointer_chk_guard_local
++#else
++extern uintptr_t __pointer_chk_guard;
++# define POINTER_CHK_GUARD __pointer_chk_guard
++#endif
+ #endif
Index: debian/patches/any/cvs-CVE-2013-4458.diff
===================================================================
--- debian/patches/any/cvs-CVE-2013-4458.diff	(.../tags/2.13-38)	(révision 0)
+++ debian/patches/any/cvs-CVE-2013-4458.diff	(.../branches/glibc-branch-wheezy)	(révision 5872)
@@ -0,0 +1,765 @@
+2013-10-25  Siddhesh Poyarekar  <siddhesh@redhat.com>
+
+	[BZ #16072]
+	* sysdeps/posix/getaddrinfo.c (gethosts): Allocate tmpbuf on
+	heap for large requests.
+
+2011-06-10  Andreas Schwab  <schwab@redhat.com>
+
+	* sysdeps/posix/getaddrinfo.c (gaih_inet): Fix logic allocating
+	tmpbuf.
+
+2011-05-20  Ulrich Drepper  <drepper@gmail.com>
+ 
+	[BZ #11869]
+	* sysdeps/posix/getaddrinfo.c (gaih_inet): Don't unconditionally use
+	alloca.
+	* include/alloca.h (extend_alloca_account): Define.
+
+2011-04-28  Maciej Babinski  <mbabinski@google.com>
+
+	[BZ #12714]
+	* sysdeps/posix/getaddrinfo.c (gaih_inet): Don't bypass
+	gethostbyname4_r when IPv6 results are possible.
+
+--- a/include/alloca.h
++++ b/include/alloca.h
+@@ -49,15 +49,24 @@
+ 
+ #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__);			\
++  ({ 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__;			    \
++  ({ 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
+--- a/sysdeps/posix/getaddrinfo.c
++++ b/sysdeps/posix/getaddrinfo.c
+@@ -196,7 +196,22 @@
+ 				&rc, &herrno, NULL, &localcanon));	      \
+     if (rc != ERANGE || herrno != NETDB_INTERNAL)			      \
+       break;								      \
+-    tmpbuf = extend_alloca (tmpbuf, tmpbuflen, 2 * tmpbuflen);		      \
++    if (!malloc_tmpbuf && __libc_use_alloca (alloca_used + 2 * tmpbuflen))    \
++      tmpbuf = extend_alloca_account (tmpbuf, tmpbuflen, 2 * tmpbuflen,	      \
++				      alloca_used);			      \
++    else								      \
++      {									      \
++	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;					      \
++      }									      \
+   }									      \
+   if (status == NSS_STATUS_SUCCESS && rc == 0)				      \
+     h = &th;								      \
+@@ -208,7 +223,8 @@
+ 	{								      \
+ 	  __set_h_errno (herrno);					      \
+ 	  _res.options |= old_res_options & RES_USE_INET6;		      \
+-	  return -EAI_SYSTEM;						      \
++	  result = -EAI_SYSTEM;						      \
++	  goto free_and_return;						      \
+ 	}								      \
+       if (herrno == TRY_AGAIN)						      \
+ 	no_data = EAI_AGAIN;						      \
+@@ -278,6 +294,7 @@
+   bool got_ipv6 = false;
+   const char *canon = NULL;
+   const char *orig_name = name;
++  size_t alloca_used = 0;
+ 
+   if (req->ai_protocol || req->ai_socktype)
+     {
+@@ -310,7 +327,7 @@
+ 	  if (tp->name[0])
+ 	    {
+ 	      st = (struct gaih_servtuple *)
+-		__alloca (sizeof (struct gaih_servtuple));
++		alloca_account (sizeof (struct gaih_servtuple), alloca_used);
+ 
+ 	      if ((rc = gaih_inet_serv (service->name, tp, req, st)))
+ 		return rc;
+@@ -334,7 +351,8 @@
+ 		    continue;
+ 
+ 		  newp = (struct gaih_servtuple *)
+-		    __alloca (sizeof (struct gaih_servtuple));
++		    alloca_account (sizeof (struct gaih_servtuple),
++				    alloca_used);
+ 
+ 		  if ((rc = gaih_inet_serv (service->name, tp, req, newp)))
+ 		    {
+@@ -362,7 +380,7 @@
+ 
+       if (req->ai_socktype || req->ai_protocol)
+ 	{
+-	  st = __alloca (sizeof (struct gaih_servtuple));
++	  st = alloca_account (sizeof (struct gaih_servtuple), alloca_used);
+ 	  st->next = NULL;
+ 	  st->socktype = tp->socktype;
+ 	  st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY)
+@@ -379,7 +397,8 @@
+ 	      {
+ 		struct gaih_servtuple *newp;
+ 
+-		newp = __alloca (sizeof (struct gaih_servtuple));
++		newp = alloca_account (sizeof (struct gaih_servtuple),
++				       alloca_used);
+ 		newp->next = NULL;
+ 		newp->socktype = tp->socktype;
+ 		newp->protocol = tp->protocol;
+@@ -391,10 +410,17 @@
+ 	}
+     }
+ 
++  bool malloc_name = false;
++  bool malloc_addrmem = false;
++  struct gaih_addrtuple *addrmem = NULL;
++  bool malloc_canonbuf = false;
++  char *canonbuf = NULL;
++  bool malloc_tmpbuf = false;
++  char *tmpbuf = NULL;
++  int result = 0;
+   if (name != NULL)
+     {
+-      at = __alloca (sizeof (struct gaih_addrtuple));
+-
++      at = alloca_account (sizeof (struct gaih_addrtuple), alloca_used);
+       at->family = AF_UNSPEC;
+       at->scopeid = 0;
+       at->next = NULL;
+@@ -412,6 +438,7 @@
+ 	  rc = __idna_to_ascii_lz (name, &p, idn_flags);
+ 	  if (rc != IDNA_SUCCESS)
+ 	    {
++	      /* No need to jump to free_and_return here.  */
+ 	      if (rc == IDNA_MALLOC_ERROR)
+ 		return -EAI_MEMORY;
+ 	      if (rc == IDNA_DLOPEN_ERROR)
+@@ -421,10 +448,7 @@
+ 	  /* In case the output string is the same as the input string
+ 	     no new string has been allocated.  */
+ 	  if (p != name)
+-	    {
+-	      name = strdupa (p);
+-	      free (p);
+-	    }
++	    malloc_name = true;
+ 	}
+ #endif
+ 
+@@ -441,23 +465,59 @@
+ 	      at->family = AF_INET6;
+ 	    }
+ 	  else
+-	    return -EAI_ADDRFAMILY;
++	    {
++	      result = -EAI_ADDRFAMILY;
++	      goto free_and_return;
++	    }
+ 
+ 	  if (req->ai_flags & AI_CANONNAME)
+ 	    canon = name;
+ 	}
+       else if (at->family == AF_UNSPEC)
+ 	{
+-	  char *namebuf = (char *) name;
+ 	  char *scope_delim = strchr (name, SCOPE_DELIMITER);
++	  int e;
+ 
+-	  if (__builtin_expect (scope_delim != NULL, 0))
+-	    {
+-	      namebuf = alloca (scope_delim - name + 1);
+-	      *((char *) __mempcpy (namebuf, name, scope_delim - name)) = '\0';
+-	    }
++	  {
++	    bool malloc_namebuf = false;
++	    char *namebuf = (char *) name;
+ 
+-	  if (inet_pton (AF_INET6, namebuf, at->addr) > 0)
++	    if (__builtin_expect (scope_delim != NULL, 0))
++	      {
++		if (malloc_name)
++		  *scope_delim = '\0';
++		else
++		  {
++		    if (__libc_use_alloca (alloca_used
++					   + scope_delim - name + 1))
++		      {
++			namebuf = alloca_account (scope_delim - name + 1,
++						  alloca_used);
++			*((char *) __mempcpy (namebuf, name,
++					      scope_delim - name)) = '\0';
++		      }
++		    else
++		      {
++			namebuf = strndup (name, scope_delim - name);
++			if (namebuf == NULL)
++			  {
++			    assert (!malloc_name);
++			    return -EAI_MEMORY;
++			  }
++			malloc_namebuf = true;
++		      }
++		  }
++	      }
++
++	    e = inet_pton (AF_INET6, namebuf, at->addr);
++
++	    if (malloc_namebuf)
++	      free (namebuf);
++	    else if (scope_delim != NULL && malloc_name)
++	      /* Undo what we did above.  */
++	      *scope_delim = SCOPE_DELIMITER;
++	  }
++	  if (e > 0)
+ 	    {
+ 	      if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)
+ 		at->family = AF_INET6;
+@@ -468,7 +528,10 @@
+ 		  at->family = AF_INET;
+ 		}
+ 	      else
+-		return -EAI_ADDRFAMILY;
++		{
++		  result = -EAI_ADDRFAMILY;
++		  goto free_and_return;
++		}
+ 
+ 	      if (scope_delim != NULL)
+ 		{
+@@ -490,7 +553,10 @@
+ 		      at->scopeid = (uint32_t) strtoul (scope_delim + 1, &end,
+ 							10);
+ 		      if (*end != '\0')
+-			return GAIH_OKIFUNSPEC | -EAI_NONAME;
++			{
++			  result = GAIH_OKIFUNSPEC | -EAI_NONAME;
++			  goto free_and_return;
++			}
+ 		    }
+ 		}
+ 
+@@ -510,53 +576,81 @@
+ 	  int no_more;
+ 	  int old_res_options;
+ 
+-	  /* If we do not have to look for IPv4 and IPv6 together, use
+-	     the simple, old functions.  */
+-	  if (req->ai_family == AF_INET
+-	      || (req->ai_family == AF_INET6
+-		  && ((req->ai_flags & AI_V4MAPPED) == 0
+-		      || (req->ai_flags & AI_ALL) == 0)))
++	  /* If we do not have to look for IPv6 addresses, use
++	     the simple, old functions, which do not support
++	     IPv6 scope ids. */
++	  if (req->ai_family == AF_INET)
+ 	    {
+ 	      int family = req->ai_family;
+ 	      size_t tmpbuflen = 512;
+-	      char *tmpbuf = alloca (tmpbuflen);
++	      assert (tmpbuf == NULL);
++	      tmpbuf = alloca_account (tmpbuflen, alloca_used);
+ 	      int rc;
+ 	      struct hostent th;
+ 	      struct hostent *h;
+ 	      int herrno;
+ 
+-	    simple_again:
+ 	      while (1)
+ 		{
+ 		  rc = __gethostbyname2_r (name, family, &th, tmpbuf,
+ 					   tmpbuflen, &h, &herrno);
+ 		  if (rc != ERANGE || herrno != NETDB_INTERNAL)
+ 		    break;
+-		  tmpbuf = extend_alloca (tmpbuf, tmpbuflen, 2 * tmpbuflen);
++
++		  if (!malloc_tmpbuf
++		      && __libc_use_alloca (alloca_used + 2 * tmpbuflen))
++		    tmpbuf = extend_alloca_account (tmpbuf, tmpbuflen,
++						    2 * tmpbuflen,
++						    alloca_used);
++		  else
++		    {
++		      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;
++		    }
+ 		}
+ 
+ 	      if (rc == 0)
+ 		{
+-		  if (h == NULL)
++		  if (h != NULL)
+ 		    {
+-		      if (req->ai_family == AF_INET6
+-			  && (req->ai_flags & AI_V4MAPPED)
+-			  && family == AF_INET6)
++		      int i;
++		      /* We found data, count the number of addresses.  */
++		      for (i = 0; h->h_addr_list[i]; ++i)
++			;
++		      if (i > 0 && *pat != NULL)
++			--i;
++
++		      if (__libc_use_alloca (alloca_used
++					     + i * sizeof (struct gaih_addrtuple)))
++			addrmem = alloca_account (i * sizeof (struct gaih_addrtuple),
++						  alloca_used);
++		      else
+ 			{
+-			  /* Try again, this time looking for IPv4
+-			     addresses.  */
+-			  family = AF_INET;
+-			  goto simple_again;
++			  addrmem = malloc (i
++					    * sizeof (struct gaih_addrtuple));
++			  if (addrmem == NULL)
++			    {
++			      result = -EAI_MEMORY;
++			      goto free_and_return;
++			    }
++			  malloc_addrmem = true;
+ 			}
+-		    }
+-		  else
+-		    {
+-		      /* We found data, now convert it into the list.  */
+-		      for (int i = 0; h->h_addr_list[i]; ++i)
++
++		      /* Now convert it into the list.  */
++		      struct gaih_addrtuple *addrfree = addrmem;
++		      for (i = 0; h->h_addr_list[i]; ++i)
+ 			{
+ 			  if (*pat == NULL)
+ 			    {
+-			      *pat = __alloca (sizeof (struct gaih_addrtuple));
++			      *pat = addrfree++;
+ 			      (*pat)->scopeid = 0;
+ 			    }
+ 			  (*pat)->next = NULL;
+@@ -581,15 +675,16 @@
+ 		  if (herrno == NETDB_INTERNAL)
+ 		    {
+ 		      __set_h_errno (herrno);
+-		      return -EAI_SYSTEM;
+-		    }
+-		  if (herrno == TRY_AGAIN)
+-		    {
+-		      return -EAI_AGAIN;
++		      result = -EAI_SYSTEM;
+ 		    }
+-		  /* We made requests but they turned out no data.
+-		     The name is known, though.  */
+-		  return GAIH_OKIFUNSPEC | -EAI_NODATA;
++		  else if (herrno == TRY_AGAIN)
++		    result = -EAI_AGAIN;
++		  else
++		    /* We made requests but they turned out no data.
++		       The name is known, though.  */
++		    result = GAIH_OKIFUNSPEC | -EAI_NODATA;
++
++		  goto free_and_return;
+ 		}
+ 
+ 	      goto process_list;
+@@ -613,21 +708,56 @@
+ 		  bool added_canon = (req->ai_flags & AI_CANONNAME) == 0;
+ 		  char *addrs = air->addrs;
+ 
++		  if (__libc_use_alloca (alloca_used
++					 + air->naddrs * sizeof (struct gaih_addrtuple)))
++		    addrmem = alloca_account (air->naddrs
++					      * sizeof (struct gaih_addrtuple),
++					      alloca_used);
++		  else
++		    {
++		      addrmem = malloc (air->naddrs
++					* sizeof (struct gaih_addrtuple));
++		      if (addrmem == NULL)
++			{
++			  result = -EAI_MEMORY;
++			  goto free_and_return;
++			}
++		      malloc_addrmem = true;
++		    }
++
++		  struct gaih_addrtuple *addrfree = addrmem;
+ 		  for (int i = 0; i < air->naddrs; ++i)
+ 		    {
+ 		      socklen_t size = (air->family[i] == AF_INET
+ 					? INADDRSZ : IN6ADDRSZ);
+ 		      if (*pat == NULL)
+ 			{
+-			  *pat = __alloca (sizeof (struct gaih_addrtuple));
++			  *pat = addrfree++;
+ 			  (*pat)->scopeid = 0;
+ 			}
+ 		      uint32_t *pataddr = (*pat)->addr;
+ 		      (*pat)->next = NULL;
+ 		      if (added_canon || air->canon == NULL)
+ 			(*pat)->name = NULL;
+-		      else
+-			canon = (*pat)->name = strdupa (air->canon);
++		      else if (canonbuf == NULL)
++			{
++			  size_t canonlen = strlen (air->canon) + 1;
++			  if ((req->ai_flags & AI_CANONIDN) != 0
++			      && __libc_use_alloca (alloca_used + canonlen))
++			    canonbuf = alloca_account (canonlen, alloca_used);
++			  else
++			    {
++			      canonbuf = malloc (canonlen);
++			      if (canonbuf == NULL)
++				{
++				  result = -EAI_MEMORY;
++				  goto free_and_return;
++				}
++			      malloc_canonbuf = true;
++			    }
++			  canon = (*pat)->name = memcpy (canonbuf, air->canon,
++							 canonlen);
++			}
+ 
+ 		      if (air->family[i] == AF_INET
+ 			  && req->ai_family == AF_INET6
+@@ -657,20 +787,26 @@
+ 		  free (air);
+ 
+ 		  if (at->family == AF_UNSPEC)
+-		    return GAIH_OKIFUNSPEC | -EAI_NONAME;
++		    {
++		      result = GAIH_OKIFUNSPEC | -EAI_NONAME;
++		      goto free_and_return;
++		    }
+ 
+ 		  goto process_list;
+ 		}
+ 	      else if (err == 0)
+ 		/* The database contains a negative entry.  */
+-		return 0;
++		goto free_and_return;
+ 	      else if (__nss_not_use_nscd_hosts == 0)
+ 		{
+ 		  if (herrno == NETDB_INTERNAL && errno == ENOMEM)
+-		    return -EAI_MEMORY;
+-		  if (herrno == TRY_AGAIN)
+-		    return -EAI_AGAIN;
+-		  return -EAI_SYSTEM;
++		    result = -EAI_MEMORY;
++		  else if (herrno == TRY_AGAIN)
++		    result = -EAI_AGAIN;
++		  else
++		    result = -EAI_SYSTEM;
++
++		  goto free_and_return;
+ 		}
+ 	    }
+ #endif
+@@ -699,7 +835,19 @@
+ 	  _res.options &= ~RES_USE_INET6;
+ 
+ 	  size_t tmpbuflen = 1024;
+-	  char *tmpbuf = alloca (tmpbuflen);
++	  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)
++		{
++		  result = -EAI_MEMORY;
++		  goto free_and_return;
++		}
++	    }
+ 
+ 	  while (!no_more)
+ 	    {
+@@ -728,8 +876,25 @@
+ 			    no_data = herrno == NO_DATA;
+ 			  break;
+ 			}
+-		      tmpbuf = extend_alloca (tmpbuf,
+-					      tmpbuflen, 2 * tmpbuflen);
++
++		      if (!malloc_tmpbuf
++			  && __libc_use_alloca (alloca_used + 2 * tmpbuflen))
++			tmpbuf = extend_alloca_account (tmpbuf, tmpbuflen,
++							2 * tmpbuflen,
++							alloca_used);
++		      else
++			{
++			  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;
++			}
+ 		    }
+ 
+ 		  if (status == NSS_STATUS_SUCCESS)
+@@ -832,18 +997,40 @@
+ 			      if (cfct != NULL)
+ 				{
+ 				  const size_t max_fqdn_len = 256;
+-				  char *buf = alloca (max_fqdn_len);
++				  if ((req->ai_flags & AI_CANONIDN) != 0
++				      && __libc_use_alloca (alloca_used
++							    + max_fqdn_len))
++				    canonbuf = alloca_account (max_fqdn_len,
++							       alloca_used);
++				  else
++				    {
++				      canonbuf = malloc (max_fqdn_len);
++				      if (canonbuf == NULL)
++					{
++					  result = -EAI_MEMORY;
++					  goto free_and_return;
++					}
++				      malloc_canonbuf = true;
++				    }
+ 				  char *s;
+ 
+ 				  if (DL_CALL_FCT (cfct, (at->name ?: name,
+-							  buf, max_fqdn_len,
++							  canonbuf,
++							  max_fqdn_len,
+ 							  &s, &rc, &herrno))
+ 				      == NSS_STATUS_SUCCESS)
+ 				    canon = s;
+ 				  else
+-				    /* Set to name now to avoid using
+-				       gethostbyaddr.  */
+-				    canon = name;
++				    {
++				      /* Set to name now to avoid using
++					 gethostbyaddr.  */
++				      if (malloc_canonbuf)
++					{
++					  free (canonbuf);
++					  malloc_canonbuf = false;
++					}
++				      canon = name;
++				    }
+ 				}
+ 			    }
+ 			  status = NSS_STATUS_SUCCESS;
+@@ -878,22 +1065,27 @@
+ 	    {
+ 	      /* If both requests timed out report this.  */
+ 	      if (no_data == EAI_AGAIN && no_inet6_data == EAI_AGAIN)
+-		return -EAI_AGAIN;
++		result = -EAI_AGAIN;
++	      else
++		/* We made requests but they turned out no data.  The name
++		   is known, though.  */
++		result = GAIH_OKIFUNSPEC | -EAI_NODATA;
+ 
+-	      /* We made requests but they turned out no data.  The name
+-		 is known, though.  */
+-	      return GAIH_OKIFUNSPEC | -EAI_NODATA;
++	      goto free_and_return;
+ 	    }
+ 	}
+ 
+     process_list:
+       if (at->family == AF_UNSPEC)
+-	return GAIH_OKIFUNSPEC | -EAI_NONAME;
++	{
++	  result = GAIH_OKIFUNSPEC | -EAI_NONAME;
++	  goto free_and_return;
++	}
+     }
+   else
+     {
+       struct gaih_addrtuple *atr;
+-      atr = at = __alloca (sizeof (struct gaih_addrtuple));
++      atr = at = alloca_account (sizeof (struct gaih_addrtuple), alloca_used);
+       memset (at, '\0', sizeof (struct gaih_addrtuple));
+ 
+       if (req->ai_family == AF_UNSPEC)
+@@ -932,30 +1124,56 @@
+ 	/* Only the first entry gets the canonical name.  */
+ 	if (at2 == at && (req->ai_flags & AI_CANONNAME) != 0)
+ 	  {
++	    char *tmpbuf2 = NULL;
++	    bool malloc_tmpbuf2 = false;
++
+ 	    if (canon == NULL)
+ 	      {
+ 		struct hostent *h = NULL;
+ 		int herrno;
+ 		struct hostent th;
+-		size_t tmpbuflen = 512;
+-		char *tmpbuf = NULL;
++		size_t tmpbuf2len = 512;
+ 
+ 		do
+ 		  {
+-		    tmpbuf = extend_alloca (tmpbuf, tmpbuflen, tmpbuflen * 2);
++		    if (__libc_use_alloca (alloca_used + 2 * tmpbuf2len))
++		      tmpbuf2 = extend_alloca_account (tmpbuf2, tmpbuf2len,
++						       tmpbuf2len * 2,
++						       alloca_used);
++		    else
++		      {
++			char *newp = realloc (malloc_tmpbuf2 ? tmpbuf2 : NULL,
++					      2 * tmpbuf2len);
++			if (newp == NULL)
++			  {
++			    if (malloc_tmpbuf2)
++			      free (tmpbuf2);
++			    result = -EAI_MEMORY;
++			    goto free_and_return;
++			  }
++
++			tmpbuf2 = newp;
++			tmpbuf2len = 2 * tmpbuf2len;
++			malloc_tmpbuf2 = true;
++		      }
++
+ 		    rc = __gethostbyaddr_r (at2->addr,
+ 					    ((at2->family == AF_INET6)
+ 					     ? sizeof (struct in6_addr)
+ 					     : sizeof (struct in_addr)),
+-					    at2->family, &th, tmpbuf,
+-					    tmpbuflen, &h, &herrno);
++					    at2->family, &th, tmpbuf2,
++					    tmpbuf2len, &h, &herrno);
+ 		  }
+ 		while (rc == ERANGE && herrno == NETDB_INTERNAL);
+ 
+ 		if (rc != 0 && herrno == NETDB_INTERNAL)
+ 		  {
++		    if (malloc_tmpbuf2)
++		      free (tmpbuf2);
++
+ 		    __set_h_errno (herrno);
+-		    return -EAI_SYSTEM;
++		    result = -EAI_SYSTEM;
++		    goto free_and_return;
+ 		  }
+ 
+ 		if (h != NULL)
+@@ -982,11 +1200,16 @@
+ 		int rc = __idna_to_unicode_lzlz (canon, &out, idn_flags);
+ 		if (rc != IDNA_SUCCESS)
+ 		  {
++		    if (malloc_tmpbuf2)
++		      free (tmpbuf2);
++
+ 		    if (rc == IDNA_MALLOC_ERROR)
+-		      return -EAI_MEMORY;
+-		    if (rc == IDNA_DLOPEN_ERROR)
+-		      return -EAI_SYSTEM;
+-		    return -EAI_IDN_ENCODE;
++		      result = -EAI_MEMORY;
++		    else if (rc == IDNA_DLOPEN_ERROR)
++		      result = -EAI_SYSTEM;
++		    else
++		      result = -EAI_IDN_ENCODE;
++		    goto free_and_return;
+ 		  }
+ 		/* In case the output string is the same as the input
+ 		   string no new string has been allocated and we
+@@ -1001,10 +1224,25 @@
+ #ifdef HAVE_LIBIDN
+ 	      make_copy:
+ #endif
+-		canon = strdup (canon);
+-		if (canon == NULL)
+-		  return -EAI_MEMORY;
++		if (malloc_canonbuf)
++		  /* We already allocated the string using malloc.  */
++		  malloc_canonbuf = false;
++		else
++		  {
++		    canon = strdup (canon);
++		    if (canon == NULL)
++		      {
++			if (malloc_tmpbuf2)
++			  free (tmpbuf2);
++
++			result = -EAI_MEMORY;
++			goto free_and_return;
++		      }
++		  }
+ 	      }
++
++	    if (malloc_tmpbuf2)
++	      free (tmpbuf2);
+ 	  }
+ 
+ 	family = at2->family;
+@@ -1030,7 +1268,8 @@
+ 	    if (ai == NULL)
+ 	      {
+ 		free ((char *) canon);
+-		return -EAI_MEMORY;
++		result = -EAI_MEMORY;
++		goto free_and_return;
+ 	      }
+ 
+ 	    ai->ai_flags = req->ai_flags;
+@@ -1083,7 +1322,18 @@
+ 	at2 = at2->next;
+       }
+   }
+-  return 0;
++
++ free_and_return:
++  if (malloc_name)
++    free ((char *) name);
++  if (malloc_addrmem)
++    free (addrmem);
++  if (malloc_canonbuf)
++    free (canonbuf);
++  if (malloc_tmpbuf)
++    free (tmpbuf);
++
++  return result;
+ }
+ 
+ 
Index: debian/patches/any/cvs-CVE-2012-44xx.diff
===================================================================
--- debian/patches/any/cvs-CVE-2012-44xx.diff	(.../tags/2.13-38)	(révision 0)
+++ debian/patches/any/cvs-CVE-2012-44xx.diff	(.../branches/glibc-branch-wheezy)	(révision 5872)
@@ -0,0 +1,1107 @@
+2013-09-23  Siddhesh Poyarekar  <siddhesh@redhat.com>
+ 
+	[BZ #14547]
+	* string/tst-strcoll-overflow.c: New test case.
+	* string/Makefile (xtests): Add tst-strcoll-overflow.
+	* string/strcoll_l.c (STRCOLL): Skip allocating memory for
+	cache if string sizes may cause integer overflow.
+
+	[BZ #14547]
+	* string/strcoll_l.c (coll_seq): New members rule, idx,
+	save_idx and back_us.
+	(get_next_seq_nocache): New function.
+	(do_compare_nocache): New function.
+	(STRCOLL): Use get_next_seq_nocache and do_compare_nocache
+	when malloc fails.
+
+2013-08-20  Siddhesh Poyarekar  <siddhesh@redhat.com>
+
+	* string/strcoll_l.c (coll_seq): New structure.
+	(get_next_seq_cached): New function.
+	(get_next_seq): New function.
+	(do_compare): New function.
+	(STRCOLL): Use GNU style definition.  Simplify implementation
+	by using get_next_seq, get_next_seq_cached and do_compare.
+
+--- a/string/Makefile
++++ b/string/Makefile
+@@ -67,6 +67,8 @@
+ 		   str-two-way.h
+ 
+ 
++xtests = tst-strcoll-overflow
++
+ include ../Rules
+ 
+ 
+--- a/string/strcoll_l.c
++++ b/string/strcoll_l.c
+@@ -26,6 +26,7 @@
+ #include <stdlib.h>
+ #include <string.h>
+ #include <gnu/option-groups.h>
++#include <sys/param.h>
+ 
+ #ifndef STRING_TYPE
+ # define STRING_TYPE char
+@@ -43,11 +44,434 @@
+ 
+ #include "../locale/localeinfo.h"
+ 
++/* Track status while looking for sequences in a string.  */
++typedef struct
++{
++  int len;			/* Length of the current sequence.  */
++  size_t val;			/* Position of the sequence relative to the
++				   previous non-ignored sequence.  */
++  size_t idxnow;		/* Current index in sequences.  */
++  size_t idxmax;		/* Maximum index in sequences.  */
++  size_t idxcnt;		/* Current count of indices.  */
++  size_t backw;			/* Current Backward sequence index.  */
++  size_t backw_stop;		/* Index where the backward sequences stop.  */
++  const USTRING_TYPE *us;	/* The string.  */
++  int32_t *idxarr;		/* Array to cache weight indices.  */
++  unsigned char *rulearr;	/* Array to cache rules.  */
++  unsigned char rule;		/* Saved rule for the first sequence.  */
++  int32_t idx;			/* Index to weight of the current sequence.  */
++  int32_t save_idx;		/* Save looked up index of a forward
++				   sequence after the last backward
++				   sequence.  */
++  const USTRING_TYPE *back_us;	/* Beginning of the backward sequence.  */
++} coll_seq;
++
++/* Get next sequence.  The weight indices are cached, so we don't need to
++   traverse the string.  */
++static void
++get_next_seq_cached (coll_seq *seq, int nrules, int pass,
++		     const unsigned char *rulesets,
++		     const USTRING_TYPE *weights)
++{
++  size_t val = seq->val = 0;
++  int len = seq->len;
++  size_t backw_stop = seq->backw_stop;
++  size_t backw = seq->backw;
++  size_t idxcnt = seq->idxcnt;
++  size_t idxmax = seq->idxmax;
++  size_t idxnow = seq->idxnow;
++  unsigned char *rulearr = seq->rulearr;
++  int32_t *idxarr = seq->idxarr;
++
++  while (len == 0)
++    {
++      ++val;
++      if (backw_stop != ~0ul)
++	{
++	  /* There is something pushed.  */
++	  if (backw == backw_stop)
++	    {
++	      /* The last pushed character was handled.  Continue
++		 with forward characters.  */
++	      if (idxcnt < idxmax)
++		{
++		  idxnow = idxcnt;
++		  backw_stop = ~0ul;
++		}
++	      else
++		{
++		  /* Nothing any more.  The backward sequence
++		     ended with the last sequence in the string.  */
++		  idxnow = ~0ul;
++		  break;
++		}
++	    }
++	  else
++	    idxnow = --backw;
++	}
++      else
++	{
++	  backw_stop = idxcnt;
++
++	  while (idxcnt < idxmax)
++	    {
++	      if ((rulesets[rulearr[idxcnt] * nrules + pass]
++		   & sort_backward) == 0)
++		/* No more backward characters to push.  */
++		break;
++	      ++idxcnt;
++	    }
++
++	  if (backw_stop == idxcnt)
++	    {
++	      /* No sequence at all or just one.  */
++	      if (idxcnt == idxmax)
++		/* Note that LEN is still zero.  */
++		break;
++
++	      backw_stop = ~0ul;
++	      idxnow = idxcnt++;
++	    }
++	  else
++	    /* We pushed backward sequences.  */
++	    idxnow = backw = idxcnt - 1;
++	}
++      len = weights[idxarr[idxnow]++];
++    }
++
++  /* Update the structure.  */
++  seq->val = val;
++  seq->len = len;
++  seq->backw_stop = backw_stop;
++  seq->backw = backw;
++  seq->idxcnt = idxcnt;
++  seq->idxnow = idxnow;
++}
++
++/* Get next sequence.  Traverse the string as required.  */
++static void
++get_next_seq (coll_seq *seq, int nrules, const unsigned char *rulesets,
++	      const USTRING_TYPE *weights, const int32_t *table,
++	      const USTRING_TYPE *extra, const int32_t *indirect)
++{
++#include WEIGHT_H
++  size_t val = seq->val = 0;
++  int len = seq->len;
++  size_t backw_stop = seq->backw_stop;
++  size_t backw = seq->backw;
++  size_t idxcnt = seq->idxcnt;
++  size_t idxmax = seq->idxmax;
++  size_t idxnow = seq->idxnow;
++  unsigned char *rulearr = seq->rulearr;
++  int32_t *idxarr = seq->idxarr;
++  const USTRING_TYPE *us = seq->us;
++
++  while (len == 0)
++    {
++      ++val;
++      if (backw_stop != ~0ul)
++	{
++	  /* There is something pushed.  */
++	  if (backw == backw_stop)
++	    {
++	      /* The last pushed character was handled.  Continue
++		 with forward characters.  */
++	      if (idxcnt < idxmax)
++		{
++		  idxnow = idxcnt;
++		  backw_stop = ~0ul;
++		}
++	      else
++		/* Nothing any more.  The backward sequence ended with
++		   the last sequence in the string.  Note that LEN
++		   is still zero.  */
++		break;
++	    }
++	  else
++	    idxnow = --backw;
++	}
++      else
++	{
++	  backw_stop = idxmax;
++
++	  while (*us != L('\0'))
++	    {
++	      int32_t tmp = findidx (&us, -1);
++	      rulearr[idxmax] = tmp >> 24;
++	      idxarr[idxmax] = tmp & 0xffffff;
++	      idxcnt = idxmax++;
++
++	      if ((rulesets[rulearr[idxcnt] * nrules]
++		   & sort_backward) == 0)
++		/* No more backward characters to push.  */
++		break;
++	      ++idxcnt;
++	    }
++
++	  if (backw_stop >= idxcnt)
++	    {
++	      /* No sequence at all or just one.  */
++	      if (idxcnt == idxmax || backw_stop > idxcnt)
++		/* Note that LEN is still zero.  */
++		break;
++
++	      backw_stop = ~0ul;
++	      idxnow = idxcnt;
++	    }
++	  else
++	    /* We pushed backward sequences.  */
++	    idxnow = backw = idxcnt - 1;
++	}
++      len = weights[idxarr[idxnow]++];
++    }
++
++  /* Update the structure.  */
++  seq->val = val;
++  seq->len = len;
++  seq->backw_stop = backw_stop;
++  seq->backw = backw;
++  seq->idxcnt = idxcnt;
++  seq->idxmax = idxmax;
++  seq->idxnow = idxnow;
++  seq->us = us;
++}
++
++/* Get next sequence.  Traverse the string as required.  This function does not
++   set or use any index or rule cache.  */
++static void
++get_next_seq_nocache (coll_seq *seq, int nrules, const unsigned char *rulesets,
++		      const USTRING_TYPE *weights, const int32_t *table,
++		      const USTRING_TYPE *extra, const int32_t *indirect,
++		      int pass)
++{
++#include WEIGHT_H
++  size_t val = seq->val = 0;
++  int len = seq->len;
++  size_t backw_stop = seq->backw_stop;
++  size_t backw = seq->backw;
++  size_t idxcnt = seq->idxcnt;
++  size_t idxmax = seq->idxmax;
++  int32_t idx = seq->idx;
++  const USTRING_TYPE *us = seq->us;
++
++  while (len == 0)
++    {
++      ++val;
++      if (backw_stop != ~0ul)
++	{
++	  /* There is something pushed.  */
++	  if (backw == backw_stop)
++	    {
++	      /* The last pushed character was handled.  Continue
++		 with forward characters.  */
++	      if (idxcnt < idxmax)
++		{
++		  idx = seq->save_idx;
++		  backw_stop = ~0ul;
++		}
++	      else
++		{
++		  /* Nothing anymore.  The backward sequence ended with
++		     the last sequence in the string.  Note that len is
++		     still zero.  */
++		  idx = 0;
++		  break;
++	        }
++	    }
++	  else
++	    {
++	      /* XXX Traverse BACKW sequences from the beginning of
++		 BACKW_STOP to get the next sequence.  Is ther a quicker way
++	         to do this?  */
++	      size_t i = backw_stop;
++	      us = seq->back_us;
++	      while (i < backw)
++		{
++		  int32_t tmp = findidx (&us, -1);
++		  idx = tmp & 0xffffff;
++		  i++;
++		}
++	      --backw;
++	      us = seq->us;
++	    }
++	}
++      else
++	{
++	  backw_stop = idxmax;
++	  int32_t prev_idx = idx;
++
++	  while (*us != L('\0'))
++	    {
++	      int32_t tmp = findidx (&us, -1);
++	      unsigned char rule = tmp >> 24;
++	      prev_idx = idx;
++	      idx = tmp & 0xffffff;
++	      idxcnt = idxmax++;
++
++	      /* Save the rule for the first sequence.  */
++	      if (__glibc_unlikely (idxcnt == 0))
++	        seq->rule = rule;
++
++	      if ((rulesets[rule * nrules + pass]
++		   & sort_backward) == 0)
++		/* No more backward characters to push.  */
++		break;
++	      ++idxcnt;
++	    }
++
++	  if (backw_stop >= idxcnt)
++	    {
++	      /* No sequence at all or just one.  */
++	      if (idxcnt == idxmax || backw_stop > idxcnt)
++		/* Note that len is still zero.  */
++		break;
++
++	      backw_stop = ~0ul;
++	    }
++	  else
++	    {
++	      /* We pushed backward sequences.  If the stream ended with the
++		 backward sequence, then we process the last sequence we
++		 found.  Otherwise we process the sequence before the last
++		 one since the last one was a forward sequence.  */
++	      seq->back_us = seq->us;
++	      seq->us = us;
++	      backw = idxcnt;
++	      if (idxmax > idxcnt)
++		{
++		  backw--;
++		  seq->save_idx = idx;
++		  idx = prev_idx;
++		}
++	      if (backw > backw_stop)
++		backw--;
++	    }
++	}
++
++      len = weights[idx++];
++      /* Skip over indices of previous levels.  */
++      for (int i = 0; i < pass; i++)
++	{
++	  idx += len;
++	  len = weights[idx];
++	  idx++;
++	}
++    }
++
++  /* Update the structure.  */
++  seq->val = val;
++  seq->len = len;
++  seq->backw_stop = backw_stop;
++  seq->backw = backw;
++  seq->idxcnt = idxcnt;
++  seq->idxmax = idxmax;
++  seq->us = us;
++  seq->idx = idx;
++}
++
++/* Compare two sequences.  This version does not use the index and rules
++   cache.  */
++static int
++do_compare_nocache (coll_seq *seq1, coll_seq *seq2, int position,
++		    const USTRING_TYPE *weights)
++{
++  int seq1len = seq1->len;
++  int seq2len = seq2->len;
++  size_t val1 = seq1->val;
++  size_t val2 = seq2->val;
++  int idx1 = seq1->idx;
++  int idx2 = seq2->idx;
++  int result = 0;
++
++  /* Test for position if necessary.  */
++  if (position && val1 != val2)
++    {
++      result = val1 > val2 ? 1 : -1;
++      goto out;
++    }
++
++  /* Compare the two sequences.  */
++  do
++    {
++      if (weights[idx1] != weights[idx2])
++	{
++	  /* The sequences differ.  */
++	  result = weights[idx1] - weights[idx2];
++	  goto out;
++	}
++
++      /* Increment the offsets.  */
++      ++idx1;
++      ++idx2;
++
++      --seq1len;
++      --seq2len;
++    }
++  while (seq1len > 0 && seq2len > 0);
++
++  if (position && seq1len != seq2len)
++    result = seq1len - seq2len;
++
++out:
++  seq1->len = seq1len;
++  seq2->len = seq2len;
++  seq1->idx = idx1;
++  seq2->idx = idx2;
++  return result;
++}
++
++/* Compare two sequences using the index cache.  */
++static int
++do_compare (coll_seq *seq1, coll_seq *seq2, int position,
++	    const USTRING_TYPE *weights)
++{
++  int seq1len = seq1->len;
++  int seq2len = seq2->len;
++  size_t val1 = seq1->val;
++  size_t val2 = seq2->val;
++  int32_t *idx1arr = seq1->idxarr;
++  int32_t *idx2arr = seq2->idxarr;
++  int idx1now = seq1->idxnow;
++  int idx2now = seq2->idxnow;
++  int result = 0;
++
++  /* Test for position if necessary.  */
++  if (position && val1 != val2)
++    {
++      result = val1 > val2 ? 1 : -1;
++      goto out;
++    }
++
++  /* Compare the two sequences.  */
++  do
++    {
++      if (weights[idx1arr[idx1now]] != weights[idx2arr[idx2now]])
++	{
++	  /* The sequences differ.  */
++	  result = weights[idx1arr[idx1now]] - weights[idx2arr[idx2now]];
++	  goto out;
++	}
++
++      /* Increment the offsets.  */
++      ++idx1arr[idx1now];
++      ++idx2arr[idx2now];
++
++      --seq1len;
++      --seq2len;
++    }
++  while (seq1len > 0 && seq2len > 0);
++
++  if (position && seq1len != seq2len)
++    result = seq1len - seq2len;
++
++out:
++  seq1->len = seq1len;
++  seq2->len = seq2len;
++  return result;
++}
++
+ int
+-STRCOLL (s1, s2, l)
+-     const STRING_TYPE *s1;
+-     const STRING_TYPE *s2;
+-     __locale_t l;
++STRCOLL (const STRING_TYPE *s1, const STRING_TYPE *s2, __locale_t l)
+ {
+   struct __locale_data *current = l->__locales[LC_COLLATE];
+ #if __OPTION_EGLIBC_LOCALE_CODE
+@@ -62,34 +486,6 @@
+   const USTRING_TYPE *weights;
+   const USTRING_TYPE *extra;
+   const int32_t *indirect;
+-  uint_fast32_t pass;
+-  int result = 0;
+-  const USTRING_TYPE *us1;
+-  const USTRING_TYPE *us2;
+-  size_t s1len;
+-  size_t s2len;
+-  int32_t *idx1arr;
+-  int32_t *idx2arr;
+-  unsigned char *rule1arr;
+-  unsigned char *rule2arr;
+-  size_t idx1max;
+-  size_t idx2max;
+-  size_t idx1cnt;
+-  size_t idx2cnt;
+-  size_t idx1now;
+-  size_t idx2now;
+-  size_t backw1_stop;
+-  size_t backw2_stop;
+-  size_t backw1;
+-  size_t backw2;
+-  int val1;
+-  int val2;
+-  int position;
+-  int seq1len;
+-  int seq2len;
+-  int use_malloc;
+-
+-#include WEIGHT_H
+ 
+   if (nrules == 0)
+     return STRCMP (s1, s2);
+@@ -104,7 +500,6 @@
+     current->values[_NL_ITEM_INDEX (CONCAT(_NL_COLLATE_EXTRA,SUFFIX))].string;
+   indirect = (const int32_t *)
+     current->values[_NL_ITEM_INDEX (CONCAT(_NL_COLLATE_INDIRECT,SUFFIX))].string;
+-  use_malloc = 0;
+ 
+   assert (((uintptr_t) table) % __alignof__ (table[0]) == 0);
+   assert (((uintptr_t) weights) % __alignof__ (weights[0]) == 0);
+@@ -112,18 +507,13 @@
+   assert (((uintptr_t) indirect) % __alignof__ (indirect[0]) == 0);
+ 
+   /* We need this a few times.  */
+-  s1len = STRLEN (s1);
+-  s2len = STRLEN (s2);
++  size_t s1len = STRLEN (s1);
++  size_t s2len = STRLEN (s2);
+ 
+   /* Catch empty strings.  */
+-  if (__builtin_expect (s1len == 0, 0) || __builtin_expect (s2len == 0, 0))
++  if (__glibc_unlikely (s1len == 0) || __glibc_unlikely (s2len == 0))
+     return (s1len != 0) - (s2len != 0);
+ 
+-  /* We need the elements of the strings as unsigned values since they
+-     are used as indeces.  */
+-  us1 = (const USTRING_TYPE *) s1;
+-  us2 = (const USTRING_TYPE *) s2;
+-
+   /* Perform the first pass over the string and while doing this find
+      and store the weights for each character.  Since we want this to
+      be as fast as possible we are using `alloca' to store the temporary
+@@ -133,411 +523,122 @@
+ 
+      Please note that the localedef programs makes sure that `position'
+      is not used at the first level.  */
+-  if (! __libc_use_alloca ((s1len + s2len) * (sizeof (int32_t) + 1)))
+-    {
+-      idx1arr = (int32_t *) malloc ((s1len + s2len) * (sizeof (int32_t) + 1));
+-      idx2arr = &idx1arr[s1len];
+-      rule1arr = (unsigned char *) &idx2arr[s2len];
+-      rule2arr = &rule1arr[s1len];
+ 
+-      if (idx1arr == NULL)
+-	/* No memory.  Well, go with the stack then.
++  coll_seq seq1, seq2;
++  bool use_malloc = false;
++  int result = 0;
+ 
+-	   XXX Once this implementation is stable we will handle this
+-	   differently.  Instead of precomputing the indeces we will
+-	   do this in time.  This means, though, that this happens for
+-	   every pass again.  */
+-	goto try_stack;
+-      use_malloc = 1;
+-    }
+-  else
++  memset (&seq1, 0, sizeof (seq1));
++  seq2 = seq1;
++
++  size_t size_max = SIZE_MAX / (sizeof (int32_t) + 1);
++
++  if (MIN (s1len, s2len) > size_max
++      || MAX (s1len, s2len) > size_max - MIN (s1len, s2len))
+     {
+-    try_stack:
+-      idx1arr = (int32_t *) alloca (s1len * sizeof (int32_t));
+-      idx2arr = (int32_t *) alloca (s2len * sizeof (int32_t));
+-      rule1arr = (unsigned char *) alloca (s1len);
+-      rule2arr = (unsigned char *) alloca (s2len);
++      /* If the strings are long enough to cause overflow in the size request,
++         then skip the allocation and proceed with the non-cached routines.  */
+     }
+-
+-  idx1cnt = 0;
+-  idx2cnt = 0;
+-  idx1max = 0;
+-  idx2max = 0;
+-  idx1now = 0;
+-  idx2now = 0;
+-  backw1_stop = ~0ul;
+-  backw2_stop = ~0ul;
+-  backw1 = ~0ul;
+-  backw2 = ~0ul;
+-  seq1len = 0;
+-  seq2len = 0;
+-  position = rulesets[0] & sort_position;
+-  while (1)
++  else if (! __libc_use_alloca ((s1len + s2len) * (sizeof (int32_t) + 1)))
+     {
+-      val1 = 0;
+-      val2 = 0;
+-
+-      /* Get the next non-IGNOREd element for string `s1'.  */
+-      if (seq1len == 0)
+-	do
+-	  {
+-	    ++val1;
+-
+-	    if (backw1_stop != ~0ul)
+-	      {
+-		/* The is something pushed.  */
+-		if (backw1 == backw1_stop)
+-		  {
+-		    /* The last pushed character was handled.  Continue
+-		       with forward characters.  */
+-		    if (idx1cnt < idx1max)
+-		      {
+-			idx1now = idx1cnt;
+-			backw1_stop = ~0ul;
+-		      }
+-		    else
+-		      /* Nothing anymore.  The backward sequence ended with
+-			 the last sequence in the string.  Note that seq1len
+-			 is still zero.  */
+-		      break;
+-		  }
+-		else
+-		  idx1now = --backw1;
+-	      }
+-	    else
+-	      {
+-		backw1_stop = idx1max;
+-
+-		while (*us1 != L('\0'))
+-		  {
+-		    int32_t tmp = findidx (&us1, -1);
+-		    rule1arr[idx1max] = tmp >> 24;
+-		    idx1arr[idx1max] = tmp & 0xffffff;
+-		    idx1cnt = idx1max++;
+-
+-		    if ((rulesets[rule1arr[idx1cnt] * nrules]
+-			 & sort_backward) == 0)
+-		      /* No more backward characters to push.  */
+-		      break;
+-		    ++idx1cnt;
+-		  }
+-
+-		if (backw1_stop >= idx1cnt)
+-		  {
+-		    /* No sequence at all or just one.  */
+-		    if (idx1cnt == idx1max || backw1_stop > idx1cnt)
+-		      /* Note that seq1len is still zero.  */
+-		      break;
+-
+-		    backw1_stop = ~0ul;
+-		    idx1now = idx1cnt;
+-		  }
+-		else
+-		  /* We pushed backward sequences.  */
+-		  idx1now = backw1 = idx1cnt - 1;
+-	      }
+-	  }
+-	while ((seq1len = weights[idx1arr[idx1now]++]) == 0);
+-
+-      /* And the same for string `s2'.  */
+-      if (seq2len == 0)
+-	do
+-	  {
+-	    ++val2;
+-
+-	    if (backw2_stop != ~0ul)
+-	      {
+-		/* The is something pushed.  */
+-		if (backw2 == backw2_stop)
+-		  {
+-		    /* The last pushed character was handled.  Continue
+-		       with forward characters.  */
+-		    if (idx2cnt < idx2max)
+-		      {
+-			idx2now = idx2cnt;
+-			backw2_stop = ~0ul;
+-		      }
+-		    else
+-		      /* Nothing anymore.  The backward sequence ended with
+-			 the last sequence in the string.  Note that seq2len
+-			 is still zero.  */
+-		      break;
+-		  }
+-		else
+-		  idx2now = --backw2;
+-	      }
+-	    else
+-	      {
+-		backw2_stop = idx2max;
+-
+-		while (*us2 != L('\0'))
+-		  {
+-		    int32_t tmp = findidx (&us2, -1);
+-		    rule2arr[idx2max] = tmp >> 24;
+-		    idx2arr[idx2max] = tmp & 0xffffff;
+-		    idx2cnt = idx2max++;
+-
+-		    if ((rulesets[rule2arr[idx2cnt] * nrules]
+-			 & sort_backward) == 0)
+-		      /* No more backward characters to push.  */
+-		      break;
+-		    ++idx2cnt;
+-		  }
+-
+-		if (backw2_stop >= idx2cnt)
+-		  {
+-		    /* No sequence at all or just one.  */
+-		    if (idx2cnt == idx2max || backw2_stop > idx2cnt)
+-		      /* Note that seq1len is still zero.  */
+-		      break;
+-
+-		    backw2_stop = ~0ul;
+-		    idx2now = idx2cnt;
+-		  }
+-		else
+-		  /* We pushed backward sequences.  */
+-		  idx2now = backw2 = idx2cnt - 1;
+-	      }
+-	  }
+-	while ((seq2len = weights[idx2arr[idx2now]++]) == 0);
+-
+-      /* See whether any or both strings are empty.  */
+-      if (seq1len == 0 || seq2len == 0)
+-	{
+-	  if (seq1len == seq2len)
+-	    /* Both ended.  So far so good, both strings are equal at the
+-	       first level.  */
+-	    break;
+-
+-	  /* This means one string is shorter than the other.  Find out
+-	     which one and return an appropriate value.  */
+-	  result = seq1len == 0 ? -1 : 1;
+-	  goto free_and_return;
+-	}
++      seq1.idxarr = (int32_t *) malloc ((s1len + s2len) * (sizeof (int32_t) + 1));
+ 
+-      /* Test for position if necessary.  */
+-      if (position && val1 != val2)
++      /* If we failed to allocate memory, we leave everything as NULL so that
++	 we use the nocache version of traversal and comparison functions.  */
++      if (seq1.idxarr != NULL)
+ 	{
+-	  result = val1 - val2;
+-	  goto free_and_return;
++	  seq2.idxarr = &seq1.idxarr[s1len];
++	  seq1.rulearr = (unsigned char *) &seq2.idxarr[s2len];
++	  seq2.rulearr = &seq1.rulearr[s1len];
++	  use_malloc = true;
+ 	}
++    }
++  else
++    {
++      seq1.idxarr = (int32_t *) alloca (s1len * sizeof (int32_t));
++      seq2.idxarr = (int32_t *) alloca (s2len * sizeof (int32_t));
++      seq1.rulearr = (unsigned char *) alloca (s1len);
++      seq2.rulearr = (unsigned char *) alloca (s2len);
++    }
+ 
+-      /* Compare the two sequences.  */
+-      do
+-	{
+-	  if (weights[idx1arr[idx1now]] != weights[idx2arr[idx2now]])
+-	    {
+-	      /* The sequences differ.  */
+-	      result = weights[idx1arr[idx1now]] - weights[idx2arr[idx2now]];
+-	      goto free_and_return;
+-	    }
+-
+-	  /* Increment the offsets.  */
+-	  ++idx1arr[idx1now];
+-	  ++idx2arr[idx2now];
++  int rule = 0;
+ 
+-	  --seq1len;
+-	  --seq2len;
+-	}
+-      while (seq1len > 0 && seq2len > 0);
++  /* Cache values in the first pass and if needed, use them in subsequent
++     passes.  */
++  for (int pass = 0; pass < nrules; ++pass)
++    {
++      seq1.idxcnt = 0;
++      seq1.idx = 0;
++      seq2.idx = 0;
++      seq1.backw_stop = ~0ul;
++      seq1.backw = ~0ul;
++      seq2.idxcnt = 0;
++      seq2.backw_stop = ~0ul;
++      seq2.backw = ~0ul;
+ 
+-      if (position && seq1len != seq2len)
+-	{
+-	  result = seq1len - seq2len;
+-	  goto free_and_return;
+-	}
+-    }
++      /* We need the elements of the strings as unsigned values since they
++	 are used as indices.  */
++      seq1.us = (const USTRING_TYPE *) s1;
++      seq2.us = (const USTRING_TYPE *) s2;
+ 
+-  /* Now the remaining passes over the weights.  We now use the
+-     indeces we found before.  */
+-  for (pass = 1; pass < nrules; ++pass)
+-    {
+       /* We assume that if a rule has defined `position' in one section
+ 	 this is true for all of them.  */
+-      idx1cnt = 0;
+-      idx2cnt = 0;
+-      backw1_stop = ~0ul;
+-      backw2_stop = ~0ul;
+-      backw1 = ~0ul;
+-      backw2 = ~0ul;
+-      position = rulesets[rule1arr[0] * nrules + pass] & sort_position;
++      int position = rulesets[rule * nrules + pass] & sort_position;
+ 
+       while (1)
+ 	{
+-	  val1 = 0;
+-	  val2 = 0;
+-
+-	  /* Get the next non-IGNOREd element for string `s1'.  */
+-	  if (seq1len == 0)
+-	    do
+-	      {
+-		++val1;
+-
+-		if (backw1_stop != ~0ul)
+-		  {
+-		    /* The is something pushed.  */
+-		    if (backw1 == backw1_stop)
+-		      {
+-			/* The last pushed character was handled.  Continue
+-			   with forward characters.  */
+-			if (idx1cnt < idx1max)
+-			  {
+-			    idx1now = idx1cnt;
+-			    backw1_stop = ~0ul;
+-			  }
+-			else
+-			  {
+-			    /* Nothing anymore.  The backward sequence
+-			       ended with the last sequence in the string.  */
+-			    idx1now = ~0ul;
+-			    break;
+-			  }
+-		      }
+-		    else
+-		      idx1now = --backw1;
+-		  }
+-		else
+-		  {
+-		    backw1_stop = idx1cnt;
+-
+-		    while (idx1cnt < idx1max)
+-		      {
+-			if ((rulesets[rule1arr[idx1cnt] * nrules + pass]
+-			     & sort_backward) == 0)
+-			  /* No more backward characters to push.  */
+-			  break;
+-			++idx1cnt;
+-		      }
+-
+-		    if (backw1_stop == idx1cnt)
+-		      {
+-			/* No sequence at all or just one.  */
+-			if (idx1cnt == idx1max)
+-			  /* Note that seq1len is still zero.  */
+-			  break;
+-
+-			backw1_stop = ~0ul;
+-			idx1now = idx1cnt++;
+-		      }
+-		    else
+-		      /* We pushed backward sequences.  */
+-		      idx1now = backw1 = idx1cnt - 1;
+-		  }
+-	      }
+-	    while ((seq1len = weights[idx1arr[idx1now]++]) == 0);
+-
+-	  /* And the same for string `s2'.  */
+-	  if (seq2len == 0)
+-	    do
+-	      {
+-		++val2;
+-
+-		if (backw2_stop != ~0ul)
+-		  {
+-		    /* The is something pushed.  */
+-		    if (backw2 == backw2_stop)
+-		      {
+-			/* The last pushed character was handled.  Continue
+-			   with forward characters.  */
+-			if (idx2cnt < idx2max)
+-			  {
+-			    idx2now = idx2cnt;
+-			    backw2_stop = ~0ul;
+-			  }
+-			else
+-			  {
+-			    /* Nothing anymore.  The backward sequence
+-			       ended with the last sequence in the string.  */
+-			    idx2now = ~0ul;
+-			    break;
+-			  }
+-		      }
+-		    else
+-		      idx2now = --backw2;
+-		  }
+-		else
+-		  {
+-		    backw2_stop = idx2cnt;
+-
+-		    while (idx2cnt < idx2max)
+-		      {
+-			if ((rulesets[rule2arr[idx2cnt] * nrules + pass]
+-			     & sort_backward) == 0)
+-			  /* No more backward characters to push.  */
+-			  break;
+-			++idx2cnt;
+-		      }
+-
+-		    if (backw2_stop == idx2cnt)
+-		      {
+-			/* No sequence at all or just one.  */
+-			if (idx2cnt == idx2max)
+-			  /* Note that seq2len is still zero.  */
+-			  break;
+-
+-			backw2_stop = ~0ul;
+-			idx2now = idx2cnt++;
+-		      }
+-		    else
+-		      /* We pushed backward sequences.  */
+-		      idx2now = backw2 = idx2cnt - 1;
+-		  }
+-	      }
+-	    while ((seq2len = weights[idx2arr[idx2now]++]) == 0);
++	  if (__glibc_unlikely (seq1.idxarr == NULL))
++	    {
++	      get_next_seq_nocache (&seq1, nrules, rulesets, weights, table,
++				    extra, indirect, pass);
++	      get_next_seq_nocache (&seq2, nrules, rulesets, weights, table,
++				    extra, indirect, pass);
++	    }
++	  else if (pass == 0)
++	    {
++	      get_next_seq (&seq1, nrules, rulesets, weights, table, extra,
++			    indirect);
++	      get_next_seq (&seq2, nrules, rulesets, weights, table, extra,
++			    indirect);
++	    }
++	  else
++	    {
++	      get_next_seq_cached (&seq1, nrules, pass, rulesets, weights);
++	      get_next_seq_cached (&seq2, nrules, pass, rulesets, weights);
++	    }
+ 
+ 	  /* See whether any or both strings are empty.  */
+-	  if (seq1len == 0 || seq2len == 0)
++	  if (seq1.len == 0 || seq2.len == 0)
+ 	    {
+-	      if (seq1len == seq2len)
++	      if (seq1.len == seq2.len)
+ 		/* Both ended.  So far so good, both strings are equal
+ 		   at this level.  */
+ 		break;
+ 
+ 	      /* This means one string is shorter than the other.  Find out
+ 		 which one and return an appropriate value.  */
+-	      result = seq1len == 0 ? -1 : 1;
+-	      goto free_and_return;
+-	    }
+-
+-	  /* Test for position if necessary.  */
+-	  if (position && val1 != val2)
+-	    {
+-	      result = val1 - val2;
++	      result = seq1.len == 0 ? -1 : 1;
+ 	      goto free_and_return;
+ 	    }
+ 
+-	  /* Compare the two sequences.  */
+-	  do
+-	    {
+-	      if (weights[idx1arr[idx1now]] != weights[idx2arr[idx2now]])
+-		{
+-		  /* The sequences differ.  */
+-		  result = (weights[idx1arr[idx1now]]
+-			    - weights[idx2arr[idx2now]]);
+-		  goto free_and_return;
+-		}
+-
+-	      /* Increment the offsets.  */
+-	      ++idx1arr[idx1now];
+-	      ++idx2arr[idx2now];
+-
+-	      --seq1len;
+-	      --seq2len;
+-	    }
+-	  while (seq1len > 0 && seq2len > 0);
+-
+-	  if (position && seq1len != seq2len)
+-	    {
+-	      result = seq1len - seq2len;
+-	      goto free_and_return;
+-	    }
++	  if (__glibc_unlikely (seq1.idxarr == NULL))
++	    result = do_compare_nocache (&seq1, &seq2, position, weights);
++	  else
++	    result = do_compare (&seq1, &seq2, position, weights);
++	  if (result != 0)
++	    goto free_and_return;
+ 	}
++
++      if (__builtin_expect ((seq1.rulearr != NULL), 1))
++	rule = seq1.rulearr[0];
++      else
++	rule = seq1.rule;
+     }
+ 
+   /* Free the memory if needed.  */
+  free_and_return:
+   if (use_malloc)
+-    free (idx1arr);
++    free (seq1.idxarr);
+ 
+   return result;
+ }
+--- a/string/tst-strcoll-overflow.c
++++ b/string/tst-strcoll-overflow.c
+@@ -0,0 +1,61 @@
++/* Copyright (C) 2013 Free Software Foundation, Inc.
++   This file is part of the GNU C Library.
++
++   The GNU C Library is free software; you can redistribute it and/or
++   modify it under the terms of the GNU Lesser General Public
++   License as published by the Free Software Foundation; either
++   version 2.1 of the License, or (at your option) any later version.
++
++   The GNU C Library is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++   Lesser General Public License for more details.
++
++   You should have received a copy of the GNU Lesser General Public
++   License along with the GNU C Library; if not, see
++   <http://www.gnu.org/licenses/>.  */
++
++#include <locale.h>
++#include <stdio.h>
++#include <stdint.h>
++#include <stdlib.h>
++#include <string.h>
++
++/* Verify that strcoll does not crash for large strings for which it cannot
++   cache weight lookup results.  The size is large enough to cause integer
++   overflows on 32-bit as well as buffer overflows on 64-bit.  The test should
++   work reasonably reliably when overcommit is disabled, but it obviously
++   depends on how much memory the system has.  There's a limitation to this
++   test in that it does not run to completion.  Actually collating such a
++   large string can take days and we can't have xcheck running that long.  For
++   that reason, we run the test for about 5 minutes and then assume that
++   everything is fine if there are no crashes.  */
++#define SIZE 0x40000000ul
++
++int
++do_test (void)
++{
++  if (setlocale (LC_COLLATE, "en_GB.UTF-8") == NULL)
++    {
++      puts ("setlocale failed, cannot test for overflow");
++      return 0;
++    }
++
++  char *p = malloc (SIZE);
++
++  if (p == NULL)
++    {
++      puts ("could not allocate memory");
++      return 1;
++    }
++
++  memset (p, 'x', SIZE - 1);
++  p[SIZE - 1] = 0;
++  printf ("%d\n", strcoll (p, p));
++  return 0;
++}
++
++#define TIMEOUT 300
++#define EXPECTED_SIGNAL SIGALRM
++#define TEST_FUNCTION do_test ()
++#include "../test-skeleton.c"
Index: debian/patches/any/cvs-CVE-2013-4237.diff
===================================================================
--- debian/patches/any/cvs-CVE-2013-4237.diff	(.../tags/2.13-38)	(révision 0)
+++ debian/patches/any/cvs-CVE-2013-4237.diff	(.../branches/glibc-branch-wheezy)	(révision 5872)
@@ -0,0 +1,164 @@
+2013-10-10  David S. Miller  <davem@davemloft.net>
+
+	* sysdeps/posix/dirstream.h (struct __dirstream): Fix alignment of
+	directory block.
+
+2013-08-16  Florian Weimer  <fweimer@redhat.com>
+
+	[BZ #14699]
+	CVE-2013-4237
+	* sysdeps/posix/dirstream.h (struct __dirstream): Add errcode
+	member.
+	* sysdeps/posix/opendir.c (__alloc_dir): Initialize errcode
+	member.
+	* sysdeps/posix/rewinddir.c (rewinddir): Reset errcode member.
+	* sysdeps/posix/readdir_r.c (__READDIR_R): Enforce NAME_MAX limit.
+	Return delayed error code.  Remove GETDENTS_64BIT_ALIGNED
+	conditional.
+	* sysdeps/unix/sysv/linux/wordsize-64/readdir_r.c: Do not define
+	GETDENTS_64BIT_ALIGNED.
+	* sysdeps/unix/sysv/linux/i386/readdir64_r.c: Likewise.
+	* manual/filesys.texi (Reading/Closing Directory): Document
+	ENAMETOOLONG return value of readdir_r.  Recommend readdir more
+	strongly.
+	* manual/conf.texi (Limits for Files): Add portability note to
+	NAME_MAX, PATH_MAX.
+	(Pathconf): Add portability note for _PC_NAME_MAX, _PC_PATH_MAX.
+
+--- a/sysdeps/unix/dirstream.h
++++ b/sysdeps/unix/dirstream.h
+@@ -40,8 +40,15 @@
+ 
+     off_t filepos;		/* Position of next entry to read.  */
+ 
+-    /* Directory block.  */
+-    char data[0] __attribute__ ((aligned (__alignof__ (void*))));
++    int errcode;		/* Delayed error code.  */
++
++    /* Directory block.  We must make sure that this block starts
++       at an address that is aligned adequately enough to store
++       dirent entries.  Using the alignment of "void *" is not
++       sufficient because dirents on 32-bit platforms can require
++       64-bit alignment.  We use "long double" here to be consistent
++       with what malloc uses.  */
++    char data[0] __attribute__ ((aligned (__alignof__ (long double))));
+   };
+ 
+ #define _DIR_dirfd(dirp)	((dirp)->fd)
+--- a/sysdeps/unix/opendir.c
++++ b/sysdeps/unix/opendir.c
+@@ -210,6 +210,7 @@
+   dirp->size = 0;
+   dirp->offset = 0;
+   dirp->filepos = 0;
++  dirp->errcode = 0;
+ 
+   return dirp;
+ }
+--- a/sysdeps/unix/readdir_r.c
++++ b/sysdeps/unix/readdir_r.c
+@@ -42,6 +42,7 @@
+   DIRENT_TYPE *dp;
+   size_t reclen;
+   const int saved_errno = errno;
++  int ret;
+ 
+   __libc_lock_lock (dirp->lock);
+ 
+@@ -72,10 +73,10 @@
+ 		  bytes = 0;
+ 		  __set_errno (saved_errno);
+ 		}
++	      if (bytes < 0)
++		dirp->errcode = errno;
+ 
+ 	      dp = NULL;
+-	      /* Reclen != 0 signals that an error occurred.  */
+-	      reclen = bytes != 0;
+ 	      break;
+ 	    }
+ 	  dirp->size = (size_t) bytes;
+@@ -108,29 +109,46 @@
+       dirp->filepos += reclen;
+ #endif
+ 
+-      /* Skip deleted files.  */
++#ifdef NAME_MAX
++      if (reclen > offsetof (DIRENT_TYPE, d_name) + NAME_MAX + 1)
++	{
++	  /* The record is very long.  It could still fit into the
++	     caller-supplied buffer if we can skip padding at the
++	     end.  */
++	  size_t namelen = _D_EXACT_NAMLEN (dp);
++	  if (namelen <= NAME_MAX)
++	    reclen = offsetof (DIRENT_TYPE, d_name) + namelen + 1;
++	  else
++	    {
++	      /* The name is too long.  Ignore this file.  */
++	      dirp->errcode = ENAMETOOLONG;
++	      dp->d_ino = 0;
++	      continue;
++	    }
++	}
++#endif
++
++      /* Skip deleted and ignored files.  */
+     }
+   while (dp->d_ino == 0);
+ 
+   if (dp != NULL)
+     {
+-#ifdef GETDENTS_64BIT_ALIGNED
+-      /* The d_reclen value might include padding which is not part of
+-	 the DIRENT_TYPE data structure.  */
+-      reclen = MIN (reclen,
+-		    offsetof (DIRENT_TYPE, d_name) + sizeof (dp->d_name));
+-#endif
+       *result = memcpy (entry, dp, reclen);
+-#ifdef GETDENTS_64BIT_ALIGNED
++#ifdef _DIRENT_HAVE_D_RECLEN
+       entry->d_reclen = reclen;
+ #endif
++      ret = 0;
+     }
+   else
+-    *result = NULL;
++    {
++      *result = NULL;
++      ret = dirp->errcode;
++    }
+ 
+   __libc_lock_unlock (dirp->lock);
+ 
+-  return dp != NULL ? 0 : reclen ? errno : 0;
++  return ret;
+ }
+ 
+ #ifdef __READDIR_R_ALIAS
+--- a/sysdeps/unix/rewinddir.c
++++ b/sysdeps/unix/rewinddir.c
+@@ -33,5 +33,6 @@
+   dirp->filepos = 0;
+   dirp->offset = 0;
+   dirp->size = 0;
++  dirp->errcode = 0;
+   __libc_lock_unlock (dirp->lock);
+ }
+--- a/sysdeps/unix/sysv/linux/i386/readdir64_r.c
++++ b/sysdeps/unix/sysv/linux/i386/readdir64_r.c
+@@ -19,7 +19,6 @@
+ #define __READDIR_R __readdir64_r
+ #define __GETDENTS __getdents64
+ #define DIRENT_TYPE struct dirent64
+-#define GETDENTS_64BIT_ALIGNED 1
+ 
+ #include <sysdeps/unix/readdir_r.c>
+ 
+--- a/sysdeps/unix/sysv/linux/wordsize-64/readdir_r.c
++++ b/sysdeps/unix/sysv/linux/wordsize-64/readdir_r.c
+@@ -1,5 +1,4 @@
+ #define readdir64_r __no_readdir64_r_decl
+-#define GETDENTS_64BIT_ALIGNED 1
+ #include <sysdeps/unix/readdir_r.c>
+ #undef readdir64_r
+ weak_alias (__readdir_r, readdir64_r)
Index: debian/patches/series
===================================================================
--- debian/patches/series	(.../tags/2.13-38)	(révision 5818)
+++ debian/patches/series	(.../branches/glibc-branch-wheezy)	(révision 5872)
@@ -244,6 +244,7 @@
 mips/submitted-rld_map.diff
 mips/submitted-dl-platform.diff
 mips/cvs-dlopen-lazy.diff
+mips/cvs-prlimit64.diff
 
 powerpc/local-libgcc_eh-ld.so.diff
 
@@ -374,3 +375,11 @@
 any/cvs-strtod-overflow.diff
 any/cvs-arch-lowlevellock.diff
 any/local-tst-eintr1-eagain.diff
+any/cvs-CVE-2012-44xx.diff
+any/cvs-CVE-2013-0242.diff
+any/cvs-CVE-2013-1914.diff
+any/cvs-CVE-2013-4237.diff
+any/cvs-CVE-2013-4332.diff
+any/cvs-CVE-2013-4458.diff
+any/cvs-CVE-2013-4788.diff
+any/cvs-findlocale-div-by-zero.diff
Index: debian/patches/series.kfreebsd-i386
===================================================================
--- debian/patches/series.kfreebsd-i386	(.../tags/2.13-38)	(révision 5818)
+++ debian/patches/series.kfreebsd-i386	(.../branches/glibc-branch-wheezy)	(révision 5872)
@@ -4,9 +4,9 @@
 kfreebsd/local-nosavesse.diff
 kfreebsd/local-memusage_no_mremap.diff
 kfreebsd/local-pthread_at_fork.diff
-kfreebsd/local-readdir_r.diff
 kfreebsd/local-scripts.diff
 kfreebsd/local-sys_queue_h.diff
 kfreebsd/local-sysdeps.diff
 kfreebsd/local-undef-glibc.diff
 kfreebsd/local-use-thr-primitives.diff
+kfreebsd/local-initgroups-order.diff
Index: debian/patches/mips/cvs-prlimit64.diff
===================================================================
--- debian/patches/mips/cvs-prlimit64.diff	(.../tags/2.13-38)	(révision 0)
+++ debian/patches/mips/cvs-prlimit64.diff	(.../branches/glibc-branch-wheezy)	(révision 5872)
@@ -0,0 +1,139 @@
+2013-11-27  Aurelien Jarno <aurelien@aurel32.net>
+
+	* sysdeps/unix/sysv/linux/mips/getrlimit64.c: On O32 and N32 ABIs,
+	include the generic getrlimit64 version as __internal_getrlimit64
+	and add a wrapper around it to convert the RLIM64_INFINITY constant
+	between the libc and the kernel version.
+	* sysdeps/unix/sysv/linux/mips/setrlimit64.c: Ditto with setrlimit64.
+
+diff --git a/ports/sysdeps/unix/sysv/linux/mips/getrlimit64.c b/ports/sysdeps/unix/sysv/linux/mips/getrlimit64.c
+new file mode 100644
+index 0000000..10a5495
+--- /dev/null
++++ b/ports/sysdeps/unix/sysv/linux/mips/getrlimit64.c
+@@ -0,0 +1,64 @@
++/* Copyright (C) 2013 Free Software Foundation, Inc.
++   This file is part of the GNU C Library.
++
++   The GNU C Library is free software; you can redistribute it and/or
++   modify it under the terms of the GNU Lesser General Public
++   License as published by the Free Software Foundation; either
++   version 2.1 of the License, or (at your option) any later version.
++
++   The GNU C Library is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++   Lesser General Public License for more details.
++
++   You should have received a copy of the GNU Lesser General Public
++   License along with the GNU C Library; if not, see
++   <http://www.gnu.org/licenses/>.  */
++
++#include <sys/resource.h>
++
++#if _MIPS_SIM == _ABIO32 || _MIPS_SIM == _ABIN32
++
++# define getrlimit64 static __internal_getrlimit64
++# undef libc_hidden_def
++# define libc_hidden_def(name)
++# include <sysdeps/unix/sysv/linux/getrlimit64.c>
++# undef getrlimit64
++# undef libc_hidden_def
++# define libc_hidden_def(name) hidden_def (name)
++
++/* RLIM64_INFINITY was supposed to be a glibc convention rather than
++   anything seen by the kernel, but it ended being passed to the kernel
++   through the prlimit64 syscall.  Given that a lot of binaries with
++   the wrong constant value are in the wild, provide a wrapper function
++   fixing the value after the syscall.  */
++
++# define GLIBC_RLIM64_INFINITY		0x7fffffffffffffffULL
++# define KERNEL_RLIM64_INFINITY		0xffffffffffffffffULL
++
++int
++getrlimit64 (enum __rlimit_resource resource,
++	     struct rlimit64 *rlimits)
++{
++  struct rlimit64 krlimits;
++
++  if (__internal_getrlimit64 (resource, &krlimits) < 0)
++    return -1;
++
++  if (krlimits.rlim_cur == KERNEL_RLIM64_INFINITY)
++    rlimits->rlim_cur = GLIBC_RLIM64_INFINITY;
++  else
++    rlimits->rlim_cur = krlimits.rlim_cur;
++  if (krlimits.rlim_max == KERNEL_RLIM64_INFINITY)
++    rlimits->rlim_max = GLIBC_RLIM64_INFINITY;
++  else
++    rlimits->rlim_max = krlimits.rlim_max;
++
++  return 0;
++}
++
++libc_hidden_def (getrlimit64)
++
++#else /* !_ABI_O32 && !_ABI_N32 */
++# include <sysdeps/unix/sysv/linux/getrlimit64.c>
++#endif
+diff --git a/ports/sysdeps/unix/sysv/linux/mips/setrlimit64.c b/ports/sysdeps/unix/sysv/linux/mips/setrlimit64.c
+new file mode 100644
+index 0000000..8609f69
+--- /dev/null
++++ b/ports/sysdeps/unix/sysv/linux/mips/setrlimit64.c
+@@ -0,0 +1,55 @@
++/* Copyright (C) 2013 Free Software Foundation, Inc.
++   This file is part of the GNU C Library.
++
++   The GNU C Library is free software; you can redistribute it and/or
++   modify it under the terms of the GNU Lesser General Public
++   License as published by the Free Software Foundation; either
++   version 2.1 of the License, or (at your option) any later version.
++
++   The GNU C Library is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++   Lesser General Public License for more details.
++
++   You should have received a copy of the GNU Lesser General Public
++   License along with the GNU C Library; if not, see
++   <http://www.gnu.org/licenses/>.  */
++
++#include <sys/resource.h>
++
++#if _MIPS_SIM == _ABIO32 || _MIPS_SIM == _ABIN32
++
++# define setrlimit64 static __internal_setrlimit64
++# include <sysdeps/unix/sysv/linux/setrlimit64.c>
++# undef setrlimit64
++
++/* RLIM64_INFINITY was supposed to be a glibc convention rather than
++   anything seen by the kernel, but it ended being passed to the kernel
++   through the prlimit64 syscall.  Given that a lot of binaries with
++   the wrong constant value are in the wild, provide a wrapper function
++   fixing the value before the syscall.  */
++
++# define GLIBC_RLIM64_INFINITY		0x7fffffffffffffffULL
++# define KERNEL_RLIM64_INFINITY		0xffffffffffffffffULL
++
++int
++setrlimit64 (enum __rlimit_resource resource,
++	     const struct rlimit64 *rlimits)
++{
++  struct rlimit64 krlimits;
++
++  if (rlimits->rlim_cur == GLIBC_RLIM64_INFINITY)
++    krlimits.rlim_cur = KERNEL_RLIM64_INFINITY;
++  else
++    krlimits.rlim_cur = rlimits->rlim_cur;
++  if (rlimits->rlim_max == GLIBC_RLIM64_INFINITY)
++    krlimits.rlim_max = KERNEL_RLIM64_INFINITY;
++  else
++    krlimits.rlim_max = rlimits->rlim_max;
++
++  return __internal_setrlimit64 (resource, &krlimits);
++}
++
++#else /* !_ABI_O32 && !_ABI_N32 */
++# include <sysdeps/unix/sysv/linux/setrlimit64.c>
++#endif

Reply to: