This is the mail archive of the glibc-cvs@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

GNU C Library master sources branch ibm/2.16/master created. glibc-2.16.0-58-gdfc25d7


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "GNU C Library master sources".

The branch, ibm/2.16/master has been created
        at  dfc25d72984eb5a3354e104612d0ca0129af3f98 (commit)

- Log -----------------------------------------------------------------
http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=dfc25d72984eb5a3354e104612d0ca0129af3f98

commit dfc25d72984eb5a3354e104612d0ca0129af3f98
Author: Adhemerval Zanella <azanella@linux.vnet.ibm.com>
Date:   Wed Sep 25 13:43:04 2013 -0500

    PowerPC: Fix POINTER_CHK_GUARD thread register for PPC64

diff --git a/ChangeLog b/ChangeLog
index 499d43c..6fc9ebc 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2013-09-25  Adhemerval Zanella  <azanella@linux.vnet.ibm.com>
+
+	* sysdeps/powerpc/powerpc64/stackguard-macros.h (POINTER_CHK_GUARD:
+	Fix thread ID register.
+
 2014-01-20  Adhemerval Zanella  <azanella@linux.vnet.ibm.com>
 
 	[BZ#16431]
diff --git a/sysdeps/powerpc/powerpc32/stackguard-macros.h b/sysdeps/powerpc/powerpc32/stackguard-macros.h
index b3d0af8..a4d771c 100644
--- a/sysdeps/powerpc/powerpc32/stackguard-macros.h
+++ b/sysdeps/powerpc/powerpc32/stackguard-macros.h
@@ -1,7 +1,14 @@
 #include <stdint.h>
 
 #define STACK_CHK_GUARD \
-  ({ uintptr_t x; asm ("lwz %0,-28680(2)" : "=r" (x)); x; })
+  ({												\
+     uintptr_t x;										\
+     asm ("lwz %0,%1(2)"									\
+	  : "=r" (x)										\
+	  : "i" (offsetof (tcbhead_t, stack_guard) - TLS_TCB_OFFSET - sizeof (tcbhead_t))	\
+         );											\
+     x;												\
+   })
 
 #define POINTER_CHK_GUARD \
   ({												\
diff --git a/sysdeps/powerpc/powerpc64/stackguard-macros.h b/sysdeps/powerpc/powerpc64/stackguard-macros.h
index 4620f96..308d3cd 100644
--- a/sysdeps/powerpc/powerpc64/stackguard-macros.h
+++ b/sysdeps/powerpc/powerpc64/stackguard-macros.h
@@ -1,12 +1,19 @@
 #include <stdint.h>
 
 #define STACK_CHK_GUARD \
-  ({ uintptr_t x; asm ("ld %0,-28688(13)" : "=r" (x)); x; })
+  ({												\
+     uintptr_t x;										\
+     asm ("ld %0,%1(13)"										\
+	  : "=r" (x)										\
+	  : "i" (offsetof (tcbhead_t, stack_guard) - TLS_TCB_OFFSET - sizeof (tcbhead_t))	\
+         );											\
+     x;												\
+   })
 
 #define POINTER_CHK_GUARD \
   ({												\
      uintptr_t x;										\
-     asm ("ld %0,%1(2)"										\
+     asm ("ld %0,%1(13)"										\
 	  : "=r" (x)										\
 	  : "i" (offsetof (tcbhead_t, pointer_guard) - TLS_TCB_OFFSET - sizeof (tcbhead_t))	\
          );											\

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=1442655ba419867ce1a045a97cdd7904ac1ad516

commit 1442655ba419867ce1a045a97cdd7904ac1ad516
Author: Adhemerval Zanella <azanella@linux.vnet.ibm.com>
Date:   Mon Jan 20 12:29:51 2014 -0600

    PowerPC: Fix gettimeofday ifunc selection
    
    The IFUNC selector for gettimeofday runs before _libc_vdso_platform_setup where
    __vdso_gettimeofday is set. The selector then sets __gettimeofday (the internal
    version used within GLIBC) to use the system call version instead of the vDSO one.
    This patch changes the check if vDSO is available to get its value directly
    instead of rely on __vdso_gettimeofday.
    
    This patch changes it by getting the vDSO value directly.
    
    It fixes BZ#16431.

diff --git a/ChangeLog b/ChangeLog
index aa456cf..499d43c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2014-01-20  Adhemerval Zanella  <azanella@linux.vnet.ibm.com>
+
+	[BZ#16431]
+	* sysdeps/unix/sysv/linux/powerpc/gettimeofday.c (__gettimeofday):
+	Adjust the vDSO correctly for internal calls.
+	* sysdeps/unix/sysv/linux/powerpc/time.c (time): Likewise.
+
 2014-01-16  Adhemerval Zanella  <azanella@linux.vnet.ibm.com>
 
 	[BZ#16430]
diff --git a/NEWS b/NEWS
index a2eb300..aa9544f 100644
--- a/NEWS
+++ b/NEWS
@@ -10,8 +10,8 @@ Version 2.16.1
 * The following bugs are resolved with this release:
 
   6530, 14195, 14547, 14459, 14476, 14562, 14621, 14648, 14699, 14756, 14831,
-  15078, 15754, 15755, 16072, 16617, 17048, 17137, 17187, 17325, 17625,
-  17630.
+  15078, 15754, 15755, 16072, 16431, 16617, 17048, 17137, 17187, 17325,
+  17625, 17630.
 
 * CVE-2104-7817 The wordexp function could ignore the WRDE_NOCMD flag
   under certain input conditions resulting in the execution of a shell for
diff --git a/sysdeps/unix/sysv/linux/powerpc/gettimeofday.c b/sysdeps/unix/sysv/linux/powerpc/gettimeofday.c
index cc5d82e..267fa1d 100644
--- a/sysdeps/unix/sysv/linux/powerpc/gettimeofday.c
+++ b/sysdeps/unix/sysv/linux/powerpc/gettimeofday.c
@@ -34,9 +34,12 @@ __gettimeofday_syscall (struct timeval *tv, struct timezone *tz)
 void *
 gettimeofday_ifunc (void)
 {
+  PREPARE_VERSION (linux2615, "LINUX_2.6.15", 123718565);
+
   /* If the vDSO is not available we fall back syscall.  */
-  return (__vdso_gettimeofday ? VDSO_IFUNC_RET (__vdso_gettimeofday)
-	  : __gettimeofday_syscall);
+  void *vdso_gettimeofday = _dl_vdso_vsym ("__kernel_gettimeofday", &linux2615);
+  return (vdso_gettimeofday ? VDSO_IFUNC_RET (vdso_gettimeofday)
+	  : (void*)__gettimeofday_syscall);
 }
 asm (".type __gettimeofday, %gnu_indirect_function");
 

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=1bdb6daceb10307543599df3b118afd2109d2ec8

commit 1bdb6daceb10307543599df3b118afd2109d2ec8
Author: Adhemerval Zanella <azanella@linux.vnet.ibm.com>
Date:   Thu Jan 16 06:53:18 2014 -0600

    PowerPC: Fix ftime gettimeofday internal call returning bogus data
    
    This patches fixes BZ#16430 by setting a different symbol for internal
    GLIBC calls that points to ifunc resolvers. For PPC32, if the symbol
    is defined as hidden (which is the case for gettimeofday and time) the
    compiler will create local branches (symbol@local) and linker will not
    create PLT calls (required for IFUNC). This will leads to internal symbol
    calling the IFUNC resolver instead of the resolved symbol.
    For PPC64 this behavior does not occur because a call to a function in
    another translation unit might use a different toc pointer thus requiring
    a PLT call.

diff --git a/ChangeLog b/ChangeLog
index 963a282..aa456cf 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2014-01-16  Adhemerval Zanella  <azanella@linux.vnet.ibm.com>
+
+	[BZ#16430]
+	* sysdeps/unix/sysv/linux/powerpc/gettimeofday.c
+	(__GI___gettimeofday): Alias for a different internal symbol to avoid
+	local calls issues by not having a PLT stub required for IFUNC calls.
+	* sysdeps/unix/sysv/linux/powerpc/time.c (__GI_time): Likewise.
+
 2013-11-08  Adhemerval Zanella  <azanella@linux.vnet.ibm.com>
 
 	* sysdeps/unix/sysv/linux/powerpc/bits/libc-vdso.h (VDSO_IFUNC_RET):
@@ -27,12 +35,6 @@
 	(parse_dollars): Remove check for WRDE_NOCMD.
 	(parse_dquote): Likewise.
 
-2014-12-16  Florian Weimer  <fweimer@redhat.com>
-
-	[BZ #17630]
-	* resolv/nss_dns/dns-network.c (getanswer_r): Iterate over alias
-	names.
-
 2014-12-15  Jeff Law  <law@redhat.com>
 
 	[BZ #16617]
diff --git a/sysdeps/unix/sysv/linux/powerpc/gettimeofday.c b/sysdeps/unix/sysv/linux/powerpc/gettimeofday.c
index 06aae83..cc5d82e 100644
--- a/sysdeps/unix/sysv/linux/powerpc/gettimeofday.c
+++ b/sysdeps/unix/sysv/linux/powerpc/gettimeofday.c
@@ -43,8 +43,24 @@ asm (".type __gettimeofday, %gnu_indirect_function");
 /* This is doing "libc_hidden_def (__gettimeofday)" but the compiler won't
    let us do it in C because it doesn't know we're defining __gettimeofday
    here in this file.  */
-asm (".globl __GI___gettimeofday\n"
-     "__GI___gettimeofday = __gettimeofday");
+asm (".globl __GI___gettimeofday");
+
+/* __GI___gettimeofday is defined as hidden and for ppc32 it enables the
+   compiler make a local call (symbol@local) for internal GLIBC usage. It
+   means the PLT won't be used and the ifunc resolver will be called directly.
+   For ppc64 a call to a function in another translation unit might use a
+   different toc pointer thus disallowing direct branchess and making internal
+   ifuncs calls safe.  */
+#ifdef __powerpc64__
+asm ("__GI___gettimeofday = __gettimeofday");
+#else
+int
+__gettimeofday_vsyscall (struct timeval *tv, struct timezone *tz)
+{
+  return INLINE_VSYSCALL (gettimeofday, 2, tv, tz);
+}
+asm ("__GI___gettimeofday = __gettimeofday_vsyscall");
+#endif
 
 #else
 

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=e3008132765936162552b15a77fe348c01074310

commit e3008132765936162552b15a77fe348c01074310
Author: Adhemerval Zanella <azanella@linux.vnet.ibm.com>
Date:   Thu Nov 7 05:34:22 2013 -0600

    PowerPC: Fix vDSO missing ODP entries
    
    This patch fixes the vDSO symbol used directed in IFUNC resolver where
    they do not have an associated ODP entry leading to undefined behavior
    in some cases. It adds an artificial OPD static entry to such cases
    and set its TOC to non 0 to avoid triggering lazy resolutions.

diff --git a/ChangeLog b/ChangeLog
index e3f16ea..963a282 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2013-11-08  Adhemerval Zanella  <azanella@linux.vnet.ibm.com>
+
+	* sysdeps/unix/sysv/linux/powerpc/bits/libc-vdso.h (VDSO_IFUNC_RET):
+	Add artificial ODP entry for vDSO symbol for PPC64.
+	* sysdeps/unix/sysv/linux/powerpc/gettimeofday.c: Adjust includes.
+	* sysdeps/unix/sysv/linux/powerpc/time.c: Likewise.
+
 2014-11-19  Carlos O'Donell  <carlos@redhat.com>
 	    Florian Weimer  <fweimer@redhat.com>
 	    Joseph Myers  <joseph@codesourcery.com>
diff --git a/sysdeps/unix/sysv/linux/powerpc/bits/libc-vdso.h b/sysdeps/unix/sysv/linux/powerpc/bits/libc-vdso.h
index 820079f..4f5268f 100644
--- a/sysdeps/unix/sysv/linux/powerpc/bits/libc-vdso.h
+++ b/sysdeps/unix/sysv/linux/powerpc/bits/libc-vdso.h
@@ -32,12 +32,34 @@ extern void *__vdso_get_tbfreq;
 
 extern void *__vdso_getcpu;
 
-/* Macro to return vdso_xxx value on IFUNC implementations.
-   On PPC64 the returned value is actually an OPD entry.  */
 #if defined(__PPC64__) || defined(__powerpc64__)
-#define PTR_IFUNC_RET(value)  &value
+/* The correct solution is for _dl_vdso_vsym to return the address of the OPD
+   for the kernel VDSO function.  That address would then be stored in the
+   __vdso_* variables and returned as the result of the IFUNC resolver function.
+   Yet, the kernel does not contain any OPD entries for the VDSO functions
+   (incomplete implementation).  However, PLT relocations for IFUNCs still expect
+   the address of an OPD to be returned from the IFUNC resolver function (since
+   PLT entries on PPC64 are just copies of OPDs).  The solution for now is to
+   create an artificial static OPD for each VDSO function returned by a resolver
+   function.  The TOC value is set to a non-zero value to avoid triggering lazy
+   symbol resolution via .glink0/.plt0 for a zero TOC (requires thread-safe PLT
+   sequences) when the dynamic linker isn't prepared for it e.g. RTLD_NOW.  None
+   of the kernel VDSO routines use the TOC or AUX values so any non-zero value
+   will work.  Note that function pointer comparisons will not use this artificial
+   static OPD since those are resolved via ADDR64 relocations and will point at
+   the non-IFUNC default OPD for the symbol.  Lastly, because the IFUNC relocations
+   are processed immediately at startup the resolver functions and this code need
+   not be thread-safe, but if the caller writes to a PLT slot it must do so in a
+   thread-safe manner with all the required barriers.  */
+#define VDSO_IFUNC_RET(value)                            \
+  ({                                                     \
+    static Elf64_FuncDesc vdso_opd = { .fd_toc = ~0x0 }; \
+    vdso_opd.fd_func = (Elf64_Addr)value;                \
+    &vdso_opd;                                           \
+  })
+
 #else
-#define PTR_IFUNC_RET(value)  value
+#define VDSO_IFUNC_RET(value)  ((void *) (value))
 #endif
 
 #endif
diff --git a/sysdeps/unix/sysv/linux/powerpc/gettimeofday.c b/sysdeps/unix/sysv/linux/powerpc/gettimeofday.c
index 5943be7..06aae83 100644
--- a/sysdeps/unix/sysv/linux/powerpc/gettimeofday.c
+++ b/sysdeps/unix/sysv/linux/powerpc/gettimeofday.c
@@ -21,6 +21,7 @@
 
 # include <dl-vdso.h>
 # include <bits/libc-vdso.h>
+# include <dl-machine.h>
 
 void *gettimeofday_ifunc (void) __asm__ ("__gettimeofday");
 
@@ -34,7 +35,7 @@ void *
 gettimeofday_ifunc (void)
 {
   /* If the vDSO is not available we fall back syscall.  */
-  return (__vdso_gettimeofday ? PTR_IFUNC_RET(__vdso_gettimeofday)
+  return (__vdso_gettimeofday ? VDSO_IFUNC_RET (__vdso_gettimeofday)
 	  : __gettimeofday_syscall);
 }
 asm (".type __gettimeofday, %gnu_indirect_function");

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=6ff69e1eb81719ee907642f615cef889d5bf8b2c

commit 6ff69e1eb81719ee907642f615cef889d5bf8b2c
Author: Carlos O'Donell <carlos@redhat.com>
Date:   Wed Nov 19 11:44:12 2014 -0500

    CVE-2014-7817: wordexp fails to honour WRDE_NOCMD.
    
    The function wordexp() fails to properly handle the WRDE_NOCMD
    flag when processing arithmetic inputs in the form of "$((... ``))"
    where "..." can be anything valid. The backticks in the arithmetic
    epxression are evaluated by in a shell even if WRDE_NOCMD forbade
    command substitution. This allows an attacker to attempt to pass
    dangerous commands via constructs of the above form, and bypass
    the WRDE_NOCMD flag. This patch fixes this by checking for WRDE_NOCMD
    in exec_comm(), the only place that can execute a shell. All other
    checks for WRDE_NOCMD are superfluous and removed.
    
    We expand the testsuite and add 3 new regression tests of roughly
    the same form but with a couple of nested levels.
    
    On top of the 3 new tests we add fork validation to the WRDE_NOCMD
    testing. If any forks are detected during the execution of a wordexp()
    call with WRDE_NOCMD, the test is marked as failed. This is slightly
    heuristic since vfork might be used in the future, but it provides a
    higher level of assurance that no shells were executed as part of
    command substitution with WRDE_NOCMD in effect. In addition it doesn't
    require libpthread or libdl, instead we use the public implementation
    namespace function __register_atfork (already part of the public ABI
    for libpthread).
    
    Tested on x86_64 with no regressions.

diff --git a/ChangeLog b/ChangeLog
index e64ffd1..e3f16ea 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,25 @@
+2014-11-19  Carlos O'Donell  <carlos@redhat.com>
+	    Florian Weimer  <fweimer@redhat.com>
+	    Joseph Myers  <joseph@codesourcery.com>
+	    Adam Conrad  <adconrad@0c3.net>
+	    Andreas Schwab  <schwab@suse.de>
+	    Brooks  <bmoses@google.com>
+
+	[BZ #17625]
+	* wordexp-test.c (__dso_handle): Add prototype.
+	(__register_atfork): Likewise.
+	(__app_register_atfork): New function.
+	(registered_forks): New global.
+	(register_fork): New function.
+	(test_case): Add 3 new tests for WRDE_CMDSUB.
+	(main): Call __app_register_atfork.
+	(testit): If WRDE_NOCMD set registered_forks to zero, run test, and if
+	fork count is non-zero fail the test.
+	* posix/wordexp.c (exec_comm): Return WRDE_CMDSUB if WRDE_NOCMD flag
+	is set.
+	(parse_dollars): Remove check for WRDE_NOCMD.
+	(parse_dquote): Likewise.
+
 2014-12-16  Florian Weimer  <fweimer@redhat.com>
 
 	[BZ #17630]
diff --git a/NEWS b/NEWS
index aece703..a2eb300 100644
--- a/NEWS
+++ b/NEWS
@@ -10,7 +10,14 @@ Version 2.16.1
 * The following bugs are resolved with this release:
 
   6530, 14195, 14547, 14459, 14476, 14562, 14621, 14648, 14699, 14756, 14831,
-  15078, 15754, 15755, 16072, 16617, 17048, 17137, 17187, 17325, 17630.
+  15078, 15754, 15755, 16072, 16617, 17048, 17137, 17187, 17325, 17625,
+  17630.
+
+* CVE-2104-7817 The wordexp function could ignore the WRDE_NOCMD flag
+  under certain input conditions resulting in the execution of a shell for
+  command substitution when the applicaiton did not request it. The
+  implementation now checks WRDE_NOCMD immediately before executing the
+  shell and returns the error WRDE_CMDSUB as expected.
 
 * CVE-2014-9402 The nss_dns implementation of getnetbyname could run into an
   infinite loop if the DNS response contained a PTR record of an unexpected
diff --git a/posix/wordexp-test.c b/posix/wordexp-test.c
index 1199c5b..8e0bced 100644
--- a/posix/wordexp-test.c
+++ b/posix/wordexp-test.c
@@ -27,6 +27,25 @@
 
 #define IFS " \n\t"
 
+extern void *__dso_handle __attribute__ ((__weak__, __visibility__ ("hidden")));
+extern int __register_atfork (void (*) (void), void (*) (void), void (*) (void), void *);
+
+static int __app_register_atfork (void (*prepare) (void), void (*parent) (void), void (*child) (void))
+{
+  return __register_atfork (prepare, parent, child,
+			    &__dso_handle == NULL ? NULL : __dso_handle);
+}
+
+/* Number of forks seen.  */
+static int registered_forks;
+
+/* For each fork increment the fork count.  */
+static void
+register_fork (void)
+{
+  registered_forks++;
+}
+
 struct test_case_struct
 {
   int retval;
@@ -206,6 +225,12 @@ struct test_case_struct
     { WRDE_SYNTAX, NULL, "$((2+))", 0, 0, { NULL, }, IFS },
     { WRDE_SYNTAX, NULL, "`", 0, 0, { NULL, }, IFS },
     { WRDE_SYNTAX, NULL, "$((010+4+))", 0, 0, { NULL }, IFS },
+    /* Test for CVE-2014-7817. We test 3 combinations of command
+       substitution inside an arithmetic expression to make sure that
+       no commands are executed and error is returned.  */
+    { WRDE_CMDSUB, NULL, "$((`echo 1`))", WRDE_NOCMD, 0, { NULL, }, IFS },
+    { WRDE_CMDSUB, NULL, "$((1+`echo 1`))", WRDE_NOCMD, 0, { NULL, }, IFS },
+    { WRDE_CMDSUB, NULL, "$((1+$((`echo 1`))))", WRDE_NOCMD, 0, { NULL, }, IFS },
 
     { -1, NULL, NULL, 0, 0, { NULL, }, IFS },
   };
@@ -258,6 +283,15 @@ main (int argc, char *argv[])
 	  return -1;
     }
 
+  /* If we are not allowed to do command substitution, we install
+     fork handlers to verify that no forks happened.  No forks should
+     happen at all if command substitution is disabled.  */
+  if (__app_register_atfork (register_fork, NULL, NULL) != 0)
+    {
+      printf ("Failed to register fork handler.\n");
+      return -1;
+    }
+
   for (test = 0; test_case[test].retval != -1; test++)
     if (testit (&test_case[test]))
       ++fail;
@@ -367,6 +401,9 @@ testit (struct test_case_struct *tc)
 
   printf ("Test %d (%s): ", ++tests, tc->words);
 
+  if (tc->flags & WRDE_NOCMD)
+    registered_forks = 0;
+
   if (tc->flags & WRDE_APPEND)
     {
       /* initial wordexp() call, to be appended to */
@@ -378,6 +415,13 @@ testit (struct test_case_struct *tc)
     }
   retval = wordexp (tc->words, &we, tc->flags);
 
+  if ((tc->flags & WRDE_NOCMD)
+      && (registered_forks > 0))
+    {
+	  printf ("FAILED fork called for WRDE_NOCMD\n");
+	  return 1;
+    }
+
   if (tc->flags & WRDE_DOOFFS)
       start_offs = sav_we.we_offs;
 
diff --git a/posix/wordexp.c b/posix/wordexp.c
index 5ace137..d58f6c5 100644
--- a/posix/wordexp.c
+++ b/posix/wordexp.c
@@ -892,6 +892,10 @@ exec_comm (char *comm, char **word, size_t *word_length, size_t *max_length,
   pid_t pid;
   int noexec = 0;
 
+  /* Do nothing if command substitution should not succeed.  */
+  if (flags & WRDE_NOCMD)
+    return WRDE_CMDSUB;
+
   /* Don't fork() unless necessary */
   if (!comm || !*comm)
     return 0;
@@ -2071,9 +2075,6 @@ parse_dollars (char **word, size_t *word_length, size_t *max_length,
 	    }
 	}
 
-      if (flags & WRDE_NOCMD)
-	return WRDE_CMDSUB;
-
       (*offset) += 2;
       return parse_comm (word, word_length, max_length, words, offset, flags,
 			 quoted? NULL : pwordexp, ifs, ifs_white);
@@ -2185,9 +2186,6 @@ parse_dquote (char **word, size_t *word_length, size_t *max_length,
 	  break;
 
 	case '`':
-	  if (flags & WRDE_NOCMD)
-	    return WRDE_CMDSUB;
-
 	  ++(*offset);
 	  error = parse_backtick (word, word_length, max_length, words,
 				  offset, flags, NULL, NULL, NULL);
@@ -2346,12 +2344,6 @@ wordexp (const char *words, wordexp_t *pwordexp, int flags)
 	break;
 
       case '`':
-	if (flags & WRDE_NOCMD)
-	  {
-	    error = WRDE_CMDSUB;
-	    goto do_error;
-	  }
-
 	++words_offset;
 	error = parse_backtick (&word, &word_length, &max_length, words,
 				&words_offset, flags, pwordexp, ifs,

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=3ded3d365f0237e92e8af90c878b233f265d7b4a

commit 3ded3d365f0237e92e8af90c878b233f265d7b4a
Author: Allan McRae <allan@archlinux.org>
Date:   Thu Dec 18 11:01:43 2014 +1000

    Label CVE-2014-9402 in NEWS

diff --git a/NEWS b/NEWS
index 49909f1..aece703 100644
--- a/NEWS
+++ b/NEWS
@@ -12,8 +12,9 @@ Version 2.16.1
   6530, 14195, 14547, 14459, 14476, 14562, 14621, 14648, 14699, 14756, 14831,
   15078, 15754, 15755, 16072, 16617, 17048, 17137, 17187, 17325, 17630.
 
-* The nss_dns implementation of getnetbyname could run into an infinite loop
-  if the DNS response contained a PTR record of an unexpected format.
+* CVE-2014-9402 The nss_dns implementation of getnetbyname could run into an
+  infinite loop if the DNS response contained a PTR record of an unexpected
+  format.
 
 * CVE-2012-3406 printf-style functions could run into a stack overflow when
   processing format strings with a large number of format specifiers.

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=c7093fd0fedd8a0b4ed5b01347e3798219ba22ec

commit c7093fd0fedd8a0b4ed5b01347e3798219ba22ec
Author: Florian Weimer <fweimer@redhat.com>
Date:   Mon Dec 15 17:41:13 2014 +0100

    Avoid infinite loop in nss_dns getnetbyname [BZ #17630]

diff --git a/ChangeLog b/ChangeLog
index 7e85983..e64ffd1 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2014-12-16  Florian Weimer  <fweimer@redhat.com>
+
+	[BZ #17630]
+	* resolv/nss_dns/dns-network.c (getanswer_r): Iterate over alias
+	names.
+
 2014-12-15  Jeff Law  <law@redhat.com>
 
 	[BZ #16617]
diff --git a/NEWS b/NEWS
index cbac492..49909f1 100644
--- a/NEWS
+++ b/NEWS
@@ -10,7 +10,10 @@ Version 2.16.1
 * The following bugs are resolved with this release:
 
   6530, 14195, 14547, 14459, 14476, 14562, 14621, 14648, 14699, 14756, 14831,
-  15078, 15754, 15755, 16072, 16617, 17048, 17137, 17187, 17325.
+  15078, 15754, 15755, 16072, 16617, 17048, 17137, 17187, 17325, 17630.
+
+* The nss_dns implementation of getnetbyname could run into an infinite loop
+  if the DNS response contained a PTR record of an unexpected format.
 
 * CVE-2012-3406 printf-style functions could run into a stack overflow when
   processing format strings with a large number of format specifiers.
diff --git a/resolv/nss_dns/dns-network.c b/resolv/nss_dns/dns-network.c
index 4c590ba..d101306 100644
--- a/resolv/nss_dns/dns-network.c
+++ b/resolv/nss_dns/dns-network.c
@@ -398,8 +398,8 @@ getanswer_r (const querybuf *answer, int anslen, struct netent *result,
 
 	case BYNAME:
 	  {
-	    char **ap = result->n_aliases++;
-	    while (*ap != NULL)
+	    char **ap;
+	    for (ap = result->n_aliases; *ap != NULL; ++ap)
 	      {
 		/* Check each alias name for being of the forms:
 		   4.3.2.1.in-addr.arpa		= net 1.2.3.4

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=c9b43ec3890d5c750a5127a543a55cd94aa73c94

commit c9b43ec3890d5c750a5127a543a55cd94aa73c94
Author: Jeff Law <law@redhat.com>
Date:   Mon Dec 15 10:09:32 2014 +0100

    CVE-2012-3406: Stack overflow in vfprintf [BZ #16617]
    
    A larger number of format specifiers coudld cause a stack overflow,
    potentially allowing to bypass _FORTIFY_SOURCE format string
    protection.

diff --git a/ChangeLog b/ChangeLog
index ed23b08..7e85983 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2014-12-15  Jeff Law  <law@redhat.com>
+
+	[BZ #16617]
+	* stdio-common/vfprintf.c (vfprintf): Allocate large specs array
+	on the heap.  (CVE-2012-3406)
+	* stdio-common/bug23-2.c, stdio-common/bug23-3.c: New file.
+	* stdio-common/bug23-4.c: New file.  Test case by Joseph Myers.
+	* stdio-common/Makefile (tests): Add bug23-2, bug23-3, bug23-4.
+
 2014-06-21  Allan McRae  <allan@archlinux.org>
 
 	* NEWS: Mention CVE-2014-4043.
diff --git a/NEWS b/NEWS
index a0bf400..cbac492 100644
--- a/NEWS
+++ b/NEWS
@@ -10,7 +10,10 @@ Version 2.16.1
 * The following bugs are resolved with this release:
 
   6530, 14195, 14547, 14459, 14476, 14562, 14621, 14648, 14699, 14756, 14831,
-  15078, 15754, 15755, 16072, 17048, 17137, 17187, 17325.
+  15078, 15754, 15755, 16072, 16617, 17048, 17137, 17187, 17325.
+
+* CVE-2012-3406 printf-style functions could run into a stack overflow when
+  processing format strings with a large number of format specifiers.
 
 * CVE-2014-4043 The posix_spawn_file_actions_addopen implementation did not
   copy the path argument.  This allowed programs to cause posix_spawn to
diff --git a/stdio-common/Makefile b/stdio-common/Makefile
index 42e45dc..9812108 100644
--- a/stdio-common/Makefile
+++ b/stdio-common/Makefile
@@ -57,7 +57,7 @@ tests := tstscanf test_rdwr test-popen tstgetln test-fseek \
 	 bug19 bug19a tst-popen2 scanf13 scanf14 scanf15 bug20 bug21 bug22 \
 	 scanf16 scanf17 tst-setvbuf1 tst-grouping bug23 bug24 \
 	 bug-vfprintf-nargs tst-long-dbl-fphex tst-fphex-wide tst-sprintf3 \
-	 bug25
+	 bug25 bug23-2 bug23-3 bug23-4
 
 test-srcs = tst-unbputc tst-printf
 
diff --git a/stdio-common/bug23-2.c b/stdio-common/bug23-2.c
new file mode 100644
index 0000000..9e0cfe6
--- /dev/null
+++ b/stdio-common/bug23-2.c
@@ -0,0 +1,70 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+static const char expected[] = "\
+\n\
+a\n\
+abbcd55\
+\n\
+a\n\
+abbcd55\
+\n\
+a\n\
+abbcd55\
+\n\
+a\n\
+abbcd55\
+\n\
+a\n\
+abbcd55\
+\n\
+a\n\
+abbcd55\
+\n\
+a\n\
+abbcd55\
+\n\
+a\n\
+abbcd55\
+\n\
+a\n\
+abbcd55\
+\n\
+a\n\
+abbcd55\
+\n\
+a\n\
+abbcd55\
+\n\
+a\n\
+abbcd55\
+\n\
+a\n\
+abbcd55%%%%%%%%%%%%%%%%%%%%%%%%%%\n";
+
+static int
+do_test (void)
+{
+  char *buf = malloc (strlen (expected) + 1);
+  snprintf (buf, strlen (expected) + 1,
+	    "\n%1$s\n" "%1$s" "%2$s" "%2$s" "%3$s" "%4$s" "%5$d" "%5$d"
+	    "\n%1$s\n" "%1$s" "%2$s" "%2$s" "%3$s" "%4$s" "%5$d" "%5$d"
+	    "\n%1$s\n" "%1$s" "%2$s" "%2$s" "%3$s" "%4$s" "%5$d" "%5$d"
+	    "\n%1$s\n" "%1$s" "%2$s" "%2$s" "%3$s" "%4$s" "%5$d" "%5$d"
+	    "\n%1$s\n" "%1$s" "%2$s" "%2$s" "%3$s" "%4$s" "%5$d" "%5$d"
+	    "\n%1$s\n" "%1$s" "%2$s" "%2$s" "%3$s" "%4$s" "%5$d" "%5$d"
+	    "\n%1$s\n" "%1$s" "%2$s" "%2$s" "%3$s" "%4$s" "%5$d" "%5$d"
+	    "\n%1$s\n" "%1$s" "%2$s" "%2$s" "%3$s" "%4$s" "%5$d" "%5$d"
+	    "\n%1$s\n" "%1$s" "%2$s" "%2$s" "%3$s" "%4$s" "%5$d" "%5$d"
+	    "\n%1$s\n" "%1$s" "%2$s" "%2$s" "%3$s" "%4$s" "%5$d" "%5$d"
+	    "\n%1$s\n" "%1$s" "%2$s" "%2$s" "%3$s" "%4$s" "%5$d" "%5$d"
+	    "\n%1$s\n" "%1$s" "%2$s" "%2$s" "%3$s" "%4$s" "%5$d" "%5$d"
+	    "\n%1$s\n" "%1$s" "%2$s" "%2$s" "%3$s" "%4$s" "%5$d" "%5$d"
+	    "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n",
+	    "a", "b", "c", "d", 5);
+  return strcmp (buf, expected) != 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/stdio-common/bug23-3.c b/stdio-common/bug23-3.c
new file mode 100644
index 0000000..57c8cef
--- /dev/null
+++ b/stdio-common/bug23-3.c
@@ -0,0 +1,50 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+int
+do_test (void)
+{
+  size_t instances = 16384;
+#define X0 "\n%1$s\n" "%1$s" "%2$s" "%2$s" "%3$s" "%4$s" "%5$d" "%5$d"
+  const char *item = "\na\nabbcd55";
+#define X3 X0 X0 X0 X0 X0 X0 X0 X0
+#define X6 X3 X3 X3 X3 X3 X3 X3 X3
+#define X9 X6 X6 X6 X6 X6 X6 X6 X6
+#define X12 X9 X9 X9 X9 X9 X9 X9 X9
+#define X14 X12 X12 X12 X12
+#define TRAILER "%%%%%%%%%%%%%%%%%%%%%%%%%%"
+#define TRAILER2 TRAILER TRAILER
+  size_t length = instances * strlen (item) + strlen (TRAILER) + 1;
+
+  char *buf = malloc (length + 1);
+  snprintf (buf, length + 1,
+	    X14 TRAILER2 "\n",
+	    "a", "b", "c", "d", 5);
+
+  const char *p = buf;
+  size_t i;
+  for (i = 0; i < instances; ++i)
+    {
+      const char *expected;
+      for (expected = item; *expected; ++expected)
+	{
+	  if (*p != *expected)
+	    {
+	      printf ("mismatch at offset %zu (%zu): expected %d, got %d\n",
+		      (size_t) (p - buf), i, *expected & 0xFF, *p & 0xFF);
+	      return 1;
+	    }
+	  ++p;
+	}
+    }
+  if (strcmp (p, TRAILER "\n") != 0)
+    {
+      printf ("mismatch at trailer: [%s]\n", p);
+      return 1;
+    }
+  free (buf);
+  return 0;
+}
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/stdio-common/bug23-4.c b/stdio-common/bug23-4.c
new file mode 100644
index 0000000..a478564
--- /dev/null
+++ b/stdio-common/bug23-4.c
@@ -0,0 +1,31 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/resource.h>
+
+#define LIMIT 1000000
+
+int
+main (void)
+{
+  struct rlimit lim;
+  getrlimit (RLIMIT_STACK, &lim);
+  lim.rlim_cur = 1048576;
+  setrlimit (RLIMIT_STACK, &lim);
+  char *fmtstr = malloc (4 * LIMIT + 1);
+  if (fmtstr == NULL)
+    abort ();
+  char *output = malloc (LIMIT + 1);
+  if (output == NULL)
+    abort ();
+  for (size_t i = 0; i < LIMIT; i++)
+    memcpy (fmtstr + 4 * i, "%1$d", 4);
+  fmtstr[4 * LIMIT] = '\0';
+  int ret = snprintf (output, LIMIT + 1, fmtstr, 0);
+  if (ret != LIMIT)
+    abort ();
+  for (size_t i = 0; i < LIMIT; i++)
+    if (output[i] != '0')
+      abort ();
+  return 0;
+}
diff --git a/stdio-common/vfprintf.c b/stdio-common/vfprintf.c
index 17d3f42..c661163 100644
--- a/stdio-common/vfprintf.c
+++ b/stdio-common/vfprintf.c
@@ -243,6 +243,12 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
   /* For the argument descriptions, which may be allocated on the heap.  */
   void *args_malloced = NULL;
 
+  /* For positional argument handling.  */
+  struct printf_spec *specs;
+
+  /* Track if we malloced the SPECS array and thus must free it.  */
+  bool specs_malloced = false;
+
   /* This table maps a character into a number representing a
      class.  In each step there is a destination label for each
      class.  */
@@ -1652,8 +1658,8 @@ do_positional:
     size_t nspecs = 0;
     /* A more or less arbitrary start value.  */
     size_t nspecs_size = 32 * sizeof (struct printf_spec);
-    struct printf_spec *specs = alloca (nspecs_size);
 
+    specs = alloca (nspecs_size);
     /* The number of arguments the format string requests.  This will
        determine the size of the array needed to store the argument
        attributes.  */
@@ -1693,11 +1699,39 @@ do_positional:
 	if (nspecs * sizeof (*specs) >= nspecs_size)
 	  {
 	    /* Extend the array of format specifiers.  */
+	    if (nspecs_size * 2 < nspecs_size)
+	      {
+		__set_errno (ENOMEM);
+		done = -1;
+		goto all_done;
+	      }
 	    struct printf_spec *old = specs;
-	    specs = extend_alloca (specs, nspecs_size, 2 * nspecs_size);
+	    if (__libc_use_alloca (2 * nspecs_size))
+	      specs = extend_alloca (specs, nspecs_size, 2 * nspecs_size);
+	    else
+	      {
+		nspecs_size *= 2;
+		specs = malloc (nspecs_size);
+		if (specs == NULL)
+		  {
+		    __set_errno (ENOMEM);
+		    specs = old;
+		    done = -1;
+		    goto all_done;
+		  }
+	      }
 
 	    /* Copy the old array's elements to the new space.  */
 	    memmove (specs, old, nspecs * sizeof (*specs));
+
+	    /* If we had previously malloc'd space for SPECS, then
+	       release it after the copy is complete.  */
+	    if (specs_malloced)
+	      free (old);
+
+	    /* Now set SPECS_MALLOCED if needed.  */
+	    if (!__libc_use_alloca (nspecs_size))
+	      specs_malloced = true;
 	  }
 
 	/* Parse the format specifier.  */
@@ -2012,8 +2046,12 @@ do_positional:
   }
 
 all_done:
-  free (args_malloced);
-  free (workstart);
+  if (specs_malloced)
+    free (specs);
+  if (__glibc_unlikely (args_malloced != NULL))
+    free (args_malloced);
+  if (__glibc_unlikely (workstart != NULL))
+    free (workstart);
   /* Unlock the stream.  */
   _IO_funlockfile (s);
   _IO_cleanup_region_end (0);

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=3b6ac4b1093333f364698ca3bb812c80b11c2f77

commit 3b6ac4b1093333f364698ca3bb812c80b11c2f77
Author: Allan McRae <allan@archlinux.org>
Date:   Sat Jun 21 17:23:55 2014 +1000

    Mention CVE-2014-4043 in NEWS

diff --git a/ChangeLog b/ChangeLog
index a101ac8..ed23b08 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2014-06-21  Allan McRae  <allan@archlinux.org>
+
+	* NEWS: Mention CVE-2014-4043.
+
 2014-06-11  Florian Weimer  <fweimer@redhat.com>
 
 	[BZ #17048]
diff --git a/NEWS b/NEWS
index 1745060..a0bf400 100644
--- a/NEWS
+++ b/NEWS
@@ -12,6 +12,12 @@ Version 2.16.1
   6530, 14195, 14547, 14459, 14476, 14562, 14621, 14648, 14699, 14756, 14831,
   15078, 15754, 15755, 16072, 17048, 17137, 17187, 17325.
 
+* CVE-2014-4043 The posix_spawn_file_actions_addopen implementation did not
+  copy the path argument.  This allowed programs to cause posix_spawn to
+  deference a dangling pointer, or use an unexpected pathname argument if
+  the string was modified after the posix_spawn_file_actions_addopen
+  invocation.
+
 * Decoding a crafted input sequence in the character sets IBM933, IBM935,
   IBM937, IBM939, IBM1364 could result in an out-of-bounds array read,
   resulting a denial-of-service security vulnerability in applications which

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=f7865ec21e8ad32929509796497fa3b44c3ef826

commit f7865ec21e8ad32929509796497fa3b44c3ef826
Author: Florian Weimer <fweimer@redhat.com>
Date:   Thu Jan 15 15:16:54 2015 -0500

    posix_spawn_file_actions_addopen needs to copy the path argument (BZ 17048)
    
    POSIX requires that we make a copy, so we allocate a new string
    and free it in posix_spawn_file_actions_destroy.
    
    Reported by David Reid, Alex Gaynor, and Glyph Lefkowitz.  This bug
    may have security implications.

diff --git a/ChangeLog b/ChangeLog
index 3f36650..a101ac8 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,16 @@
+2014-06-11  Florian Weimer  <fweimer@redhat.com>
+
+	[BZ #17048]
+	* posix/spawn_int.h (struct __spawn_action): Make the path string
+	non-const to support deallocation.
+	* posix/spawn_faction_addopen.c
+	(posix_spawn_file_actions_addopen): Make a copy of the pathname.
+	* posix/spawn_faction_destroy.c
+	(posix_spawn_file_actions_destroy): Adjust comment.  Deallocate
+	path in all spawn_do_open actions.
+	* posix/tst-spawn.c (do_test): Exercise the copy operation in
+	posix_spawn_file_actions_addopen.
+
 2014-07-02  Florian Weimer  <fweimer@redhat.com>
 
 	[BZ #17137]
diff --git a/NEWS b/NEWS
index fb66b4d..1745060 100644
--- a/NEWS
+++ b/NEWS
@@ -10,7 +10,12 @@ Version 2.16.1
 * The following bugs are resolved with this release:
 
   6530, 14195, 14547, 14459, 14476, 14562, 14621, 14648, 14699, 14756, 14831,
-  15078, 15754, 15755, 16072, 17137, 17187, 17325.
+  15078, 15754, 15755, 16072, 17048, 17137, 17187, 17325.
+
+* Decoding a crafted input sequence in the character sets IBM933, IBM935,
+  IBM937, IBM939, IBM1364 could result in an out-of-bounds array read,
+  resulting a denial-of-service security vulnerability in applications which
+  use functions related to iconv. (CVE-2014-6040)
 
 * Locale names, including those obtained from environment variables (LANG
   and the LC_* variables), are more tightly checked for proper syntax.
@@ -28,11 +33,6 @@ Version 2.16.1
   with //TRANSLIT is still possible, and the //IGNORE specifier
   continues to be  supported. (CVE-2014-5119)
 
-* Decoding a crafted input sequence in the character sets IBM933, IBM935,
-  IBM937, IBM939, IBM1364 could result in an out-of-bounds array read,
-  resulting a denial-of-service security vulnerability in applications which
-  use functions related to iconv. (CVE-2014-6040)
-
 * CVE-2013-4332 The pvalloc, valloc, memalign, posix_memalign and
   aligned_alloc functions could allocate too few bytes or corrupt the
   heap when passed very large allocation size values (Bugzilla #15855,
diff --git a/posix/spawn_faction_addopen.c b/posix/spawn_faction_addopen.c
index 86951ae..368da5a 100644
--- a/posix/spawn_faction_addopen.c
+++ b/posix/spawn_faction_addopen.c
@@ -35,17 +35,24 @@ posix_spawn_file_actions_addopen (posix_spawn_file_actions_t *file_actions,
   if (fd < 0 || fd >= maxfd)
     return EBADF;
 
+  char *path_copy = strdup (path);
+  if (path_copy == NULL)
+    return ENOMEM;
+
   /* Allocate more memory if needed.  */
   if (file_actions->__used == file_actions->__allocated
       && __posix_spawn_file_actions_realloc (file_actions) != 0)
-    /* This can only mean we ran out of memory.  */
-    return ENOMEM;
+    {
+      /* This can only mean we ran out of memory.  */
+      free (path_copy);
+      return ENOMEM;
+    }
 
   /* Add the new value.  */
   rec = &file_actions->__actions[file_actions->__used];
   rec->tag = spawn_do_open;
   rec->action.open_action.fd = fd;
-  rec->action.open_action.path = path;
+  rec->action.open_action.path = path_copy;
   rec->action.open_action.oflag = oflag;
   rec->action.open_action.mode = mode;
 
diff --git a/posix/spawn_faction_destroy.c b/posix/spawn_faction_destroy.c
index de43724..e120fba 100644
--- a/posix/spawn_faction_destroy.c
+++ b/posix/spawn_faction_destroy.c
@@ -18,11 +18,29 @@
 #include <spawn.h>
 #include <stdlib.h>
 
-/* Initialize data structure for file attribute for `spawn' call.  */
+#include "spawn_int.h"
+
+/* Deallocate the file actions.  */
 int
 posix_spawn_file_actions_destroy (posix_spawn_file_actions_t *file_actions)
 {
-  /* Free the memory allocated.  */
+  /* Free the paths in the open actions.  */
+  for (int i = 0; i < file_actions->__used; ++i)
+    {
+      struct __spawn_action *sa = &file_actions->__actions[i];
+      switch (sa->tag)
+	{
+	case spawn_do_open:
+	  free (sa->action.open_action.path);
+	  break;
+	case spawn_do_close:
+	case spawn_do_dup2:
+	  /* No cleanup required.  */
+	  break;
+	}
+    }
+
+  /* Free the array of actions.  */
   free (file_actions->__actions);
   return 0;
 }
diff --git a/posix/spawn_int.h b/posix/spawn_int.h
index 5609e58..861e3b4 100644
--- a/posix/spawn_int.h
+++ b/posix/spawn_int.h
@@ -22,7 +22,7 @@ struct __spawn_action
     struct
     {
       int fd;
-      const char *path;
+      char *path;
       int oflag;
       mode_t mode;
     } open_action;
diff --git a/posix/tst-spawn.c b/posix/tst-spawn.c
index 162fd72..71943f9 100644
--- a/posix/tst-spawn.c
+++ b/posix/tst-spawn.c
@@ -168,6 +168,7 @@ do_test (int argc, char *argv[])
   char fd2name[18];
   char fd3name[18];
   char fd4name[18];
+  char *name3_copy;
   char *spargv[12];
 
   /* We must have
@@ -221,9 +222,15 @@ do_test (int argc, char *argv[])
    if (posix_spawn_file_actions_addclose (&actions, fd1) != 0)
      error (EXIT_FAILURE, errno, "posix_spawn_file_actions_addclose");
    /* We want to open the third file.  */
-   if (posix_spawn_file_actions_addopen (&actions, fd3, name3,
+   name3_copy = strdup (name3);
+   if (name3_copy == NULL)
+     error (EXIT_FAILURE, errno, "strdup");
+   if (posix_spawn_file_actions_addopen (&actions, fd3, name3_copy,
 					 O_RDONLY, 0666) != 0)
      error (EXIT_FAILURE, errno, "posix_spawn_file_actions_addopen");
+   /* Overwrite the name to check that a copy has been made.  */
+   memset (name3_copy, 'X', strlen (name3_copy));
+
    /* We dup the second descriptor.  */
    fd4 = MAX (2, MAX (fd1, MAX (fd2, fd3))) + 1;
    if (posix_spawn_file_actions_adddup2 (&actions, fd2, fd4) != 0)
@@ -254,6 +261,7 @@ do_test (int argc, char *argv[])
    /* Cleanup.  */
    if (posix_spawn_file_actions_destroy (&actions) != 0)
      error (EXIT_FAILURE, errno, "posix_spawn_file_actions_destroy");
+   free (name3_copy);
 
   /* Wait for the child.  */
   if (waitpid (pid, &status, 0) != pid)

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=c7a91d241b095855e06e0bd00287968df2f6d87e

commit c7a91d241b095855e06e0bd00287968df2f6d87e
Author: Florian Weimer <fweimer@redhat.com>
Date:   Mon May 12 15:24:12 2014 +0200

    _nl_find_locale: Improve handling of crafted locale names [BZ #17137]
    
    Prevent directory traversal in locale-related environment variables
    (CVE-2014-0475).

diff --git a/ChangeLog b/ChangeLog
index a1cc122..3f36650 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2014-07-02  Florian Weimer  <fweimer@redhat.com>
+
+	[BZ #17137]
+	* locale/findlocale.c (name_present, valid_locale_name): New
+	functions.
+	(_nl_find_locale): Use the loc_name variable to store name
+	candidates.  Call name_present and valid_locale_name to check and
+	validate locale names.  Return an error if the locale is invalid.
+
 2014-08-26  Florian Weimer  <fweimer@redhat.com>
 
 	[BZ #17187]
diff --git a/NEWS b/NEWS
index 3665933..fb66b4d 100644
--- a/NEWS
+++ b/NEWS
@@ -10,7 +10,16 @@ Version 2.16.1
 * The following bugs are resolved with this release:
 
   6530, 14195, 14547, 14459, 14476, 14562, 14621, 14648, 14699, 14756, 14831,
-  15078, 15754, 15755, 16072, 17187, 17325.
+  15078, 15754, 15755, 16072, 17137, 17187, 17325.
+
+* Locale names, including those obtained from environment variables (LANG
+  and the LC_* variables), are more tightly checked for proper syntax.
+  setlocale will now fail (with EINVAL) for locale names that are overly
+  long, contain slashes without starting with a slash, or contain ".." path
+  components. (CVE-2014-0475)  Previously, some valid locale names were
+  silently replaced with the "C" locale when running in AT_SECURE mode
+  (e.g., in a SUID program).  This is no longer necessary because of the
+  additional checks.
 
 * Support for loadable gconv transliteration modules has been removed.
   The support for transliteration modules has been non-functional for
diff --git a/locale/findlocale.c b/locale/findlocale.c
index eb712fc..a16077d 100644
--- a/locale/findlocale.c
+++ b/locale/findlocale.c
@@ -17,6 +17,7 @@
    <http://www.gnu.org/licenses/>.  */
 
 #include <assert.h>
+#include <errno.h>
 #include <locale.h>
 #include <stdlib.h>
 #include <string.h>
@@ -57,6 +58,45 @@ struct loaded_l10nfile *_nl_locale_file_list[__LC_LAST];
 
 const char _nl_default_locale_path[] attribute_hidden = LOCALEDIR;
 
+/* Checks if the name is actually present, that is, not NULL and not
+   empty.  */
+static inline int
+name_present (const char *name)
+{
+  return name != NULL && name[0] != '\0';
+}
+
+/* Checks that the locale name neither extremely long, nor contains a
+   ".." path component (to prevent directory traversal).  */
+static inline int
+valid_locale_name (const char *name)
+{
+  /* Not set.  */
+  size_t namelen = strlen (name);
+  /* Name too long.  The limit is arbitrary and prevents stack overflow
+     issues later.  */
+  if (__glibc_unlikely (namelen > 255))
+    return 0;
+  /* Directory traversal attempt.  */
+  static const char slashdot[4] = {'/', '.', '.', '/'};
+  if (__glibc_unlikely (memmem (name, namelen,
+				slashdot, sizeof (slashdot)) != NULL))
+    return 0;
+  if (namelen == 2 && __glibc_unlikely (name[0] == '.' && name [1] == '.'))
+    return 0;
+  if (namelen >= 3
+      && __glibc_unlikely (((name[0] == '.'
+			     && name[1] == '.'
+			     && name[2] == '/')
+			    || (name[namelen - 3] == '/'
+				&& name[namelen - 2] == '.'
+				&& name[namelen - 1] == '.'))))
+    return 0;
+  /* If there is a slash in the name, it must start with one.  */
+  if (__glibc_unlikely (memchr (name, '/', namelen) != NULL) && name[0] != '/')
+    return 0;
+  return 1;
+}
 
 struct __locale_data *
 internal_function
@@ -65,7 +105,7 @@ _nl_find_locale (const char *locale_path, size_t locale_path_len,
 {
   int mask;
   /* Name of the locale for this category.  */
-  char *loc_name;
+  char *loc_name = (char *) *name;
   const char *language;
   const char *modifier;
   const char *territory;
@@ -73,31 +113,39 @@ _nl_find_locale (const char *locale_path, size_t locale_path_len,
   const char *normalized_codeset;
   struct loaded_l10nfile *locale_file;
 
-  if ((*name)[0] == '\0')
+  if (loc_name[0] == '\0')
     {
       /* The user decides which locale to use by setting environment
 	 variables.  */
-      *name = getenv ("LC_ALL");
-      if (*name == NULL || (*name)[0] == '\0')
-	*name = getenv (_nl_category_names.str
+      loc_name = getenv ("LC_ALL");
+      if (!name_present (loc_name))
+	loc_name = getenv (_nl_category_names.str
 			+ _nl_category_name_idxs[category]);
-      if (*name == NULL || (*name)[0] == '\0')
-	*name = getenv ("LANG");
+      if (!name_present (loc_name))
+	loc_name = getenv ("LANG");
+      if (!name_present (loc_name))
+	loc_name = (char *) _nl_C_name;
     }
 
-  if (*name == NULL || (*name)[0] == '\0'
-      || (__builtin_expect (__libc_enable_secure, 0)
-	  && strchr (*name, '/') != NULL))
-    *name = (char *) _nl_C_name;
+  /* We used to fall back to the C locale if the name contains a slash
+     character '/', but we now check for directory traversal in
+     valid_locale_name, so this is no longer necessary.  */
 
-  if (__builtin_expect (strcmp (*name, _nl_C_name), 1) == 0
-      || __builtin_expect (strcmp (*name, _nl_POSIX_name), 1) == 0)
+  if (__builtin_expect (strcmp (loc_name, _nl_C_name), 1) == 0
+      || __builtin_expect (strcmp (loc_name, _nl_POSIX_name), 1) == 0)
     {
       /* We need not load anything.  The needed data is contained in
 	 the library itself.  */
       *name = (char *) _nl_C_name;
       return _nl_C[category];
     }
+  else if (!valid_locale_name (loc_name))
+    {
+      __set_errno (EINVAL);
+      return NULL;
+    }
+
+  *name = loc_name;
 
   /* We really have to load some data.  First we try the archive,
      but only if there was no LOCPATH environment variable specified.  */
diff --git a/localedata/ChangeLog b/localedata/ChangeLog
index 248b009..3c9a37c 100644
--- a/localedata/ChangeLog
+++ b/localedata/ChangeLog
@@ -1,3 +1,9 @@
+2014-07-02  Florian Weimer  <fweimer@redhat.com>
+
+	* tst-setlocale3.c: New file.
+	* Makefile (tests): Add tst-setlocale3.
+	(tst-setlocale3-ENV): New variable.
+
 2012-06-20  Petr Baudis  <pasky@ucw.cz>
 
 	* locales/mag_IN: Fix comment character.
diff --git a/localedata/Makefile b/localedata/Makefile
index 0873a55..214671e 100644
--- a/localedata/Makefile
+++ b/localedata/Makefile
@@ -78,7 +78,7 @@ locale_test_suite := tst_iswalnum tst_iswalpha tst_iswcntrl            \
 
 tests = $(locale_test_suite) tst-digits tst-setlocale bug-iconv-trans \
 	tst-leaks tst-mbswcs6 tst-xlocale1 tst-xlocale2 bug-usesetlocale \
-	tst-strfmon1 tst-sscanf bug-setlocale1 tst-setlocale2
+	tst-strfmon1 tst-sscanf bug-setlocale1 tst-setlocale2 tst-setlocale3
 ifeq (yes,$(build-shared))
 ifneq (no,$(PERL))
 tests: $(objpfx)mtrace-tst-leaks
diff --git a/localedata/tst-setlocale3.c b/localedata/tst-setlocale3.c
new file mode 100644
index 0000000..e3b21a9
--- /dev/null
+++ b/localedata/tst-setlocale3.c
@@ -0,0 +1,203 @@
+/* Regression test for setlocale invalid environment variable handling.
+   Copyright (C) 2014 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 <stdlib.h>
+#include <string.h>
+
+/* The result of setlocale may be overwritten by subsequent calls, so
+   this wrapper makes a copy.  */
+static char *
+setlocale_copy (int category, const char *locale)
+{
+  const char *result = setlocale (category, locale);
+  if (result == NULL)
+    return NULL;
+  return strdup (result);
+}
+
+static char *de_locale;
+
+static void
+setlocale_fail (const char *envstring)
+{
+  setenv ("LC_CTYPE", envstring, 1);
+  if (setlocale (LC_CTYPE, "") != NULL)
+    {
+      printf ("unexpected setlocale success for \"%s\" locale\n", envstring);
+      exit (1);
+    }
+  const char *newloc = setlocale (LC_CTYPE, NULL);
+  if (strcmp (newloc, de_locale) != 0)
+    {
+      printf ("failed setlocale call \"%s\" changed locale to \"%s\"\n",
+	      envstring, newloc);
+      exit (1);
+    }
+}
+
+static void
+setlocale_success (const char *envstring)
+{
+  setenv ("LC_CTYPE", envstring, 1);
+  char *newloc = setlocale_copy (LC_CTYPE, "");
+  if (newloc == NULL)
+    {
+      printf ("setlocale for \"%s\": %m\n", envstring);
+      exit (1);
+    }
+  if (strcmp (newloc, de_locale) == 0)
+    {
+      printf ("setlocale with LC_CTYPE=\"%s\" left locale at \"%s\"\n",
+	      envstring, de_locale);
+      exit (1);
+    }
+  if (setlocale (LC_CTYPE, de_locale) == NULL)
+    {
+      printf ("restoring locale \"%s\" with LC_CTYPE=\"%s\": %m\n",
+	      de_locale, envstring);
+      exit (1);
+    }
+  char *newloc2 = setlocale_copy (LC_CTYPE, newloc);
+  if (newloc2 == NULL)
+    {
+      printf ("restoring locale \"%s\" following \"%s\": %m\n",
+	      newloc, envstring);
+      exit (1);
+    }
+  if (strcmp (newloc, newloc2) != 0)
+    {
+      printf ("representation of locale \"%s\" changed from \"%s\" to \"%s\"",
+	      envstring, newloc, newloc2);
+      exit (1);
+    }
+  free (newloc);
+  free (newloc2);
+
+  if (setlocale (LC_CTYPE, de_locale) == NULL)
+    {
+      printf ("restoring locale \"%s\" with LC_CTYPE=\"%s\": %m\n",
+	      de_locale, envstring);
+      exit (1);
+    }
+}
+
+/* Checks that a known-good locale still works if LC_ALL contains a
+   value which should be ignored.  */
+static void
+setlocale_ignore (const char *to_ignore)
+{
+  const char *fr_locale = "fr_FR.UTF-8";
+  setenv ("LC_CTYPE", fr_locale, 1);
+  char *expected_locale = setlocale_copy (LC_CTYPE, "");
+  if (expected_locale == NULL)
+    {
+      printf ("setlocale with LC_CTYPE=\"%s\" failed: %m\n", fr_locale);
+      exit (1);
+    }
+  if (setlocale (LC_CTYPE, de_locale) == NULL)
+    {
+      printf ("failed to restore locale: %m\n");
+      exit (1);
+    }
+  unsetenv ("LC_CTYPE");
+
+  setenv ("LC_ALL", to_ignore, 1);
+  setenv ("LC_CTYPE", fr_locale, 1);
+  const char *actual_locale = setlocale (LC_CTYPE, "");
+  if (actual_locale == NULL)
+    {
+      printf ("setlocale with LC_ALL, LC_CTYPE=\"%s\" failed: %m\n",
+	      fr_locale);
+      exit (1);
+    }
+  if (strcmp (actual_locale, expected_locale) != 0)
+    {
+      printf ("setlocale under LC_ALL failed: got \"%s\", expected \"%s\"\n",
+	      actual_locale, expected_locale);
+      exit (1);
+    }
+  unsetenv ("LC_CTYPE");
+  setlocale_success (fr_locale);
+  unsetenv ("LC_ALL");
+  free (expected_locale);
+}
+
+static int
+do_test (void)
+{
+  /* The glibc test harness sets this environment variable
+     uncondionally.  */
+  unsetenv ("LC_ALL");
+
+  de_locale = setlocale_copy (LC_CTYPE, "de_DE.UTF-8");
+  if (de_locale == NULL)
+    {
+      printf ("setlocale (LC_CTYPE, \"de_DE.UTF-8\"): %m\n");
+      return 1;
+    }
+  setlocale_success ("C");
+  setlocale_success ("en_US.UTF-8");
+  setlocale_success ("/en_US.UTF-8");
+  setlocale_success ("//en_US.UTF-8");
+  setlocale_ignore ("");
+
+  setlocale_fail ("does-not-exist");
+  setlocale_fail ("/");
+  setlocale_fail ("/../localedata/en_US.UTF-8");
+  setlocale_fail ("en_US.UTF-8/");
+  setlocale_fail ("en_US.UTF-8/..");
+  setlocale_fail ("en_US.UTF-8/../en_US.UTF-8");
+  setlocale_fail ("../localedata/en_US.UTF-8");
+  {
+    size_t large_length = 1024;
+    char *large_name = malloc (large_length + 1);
+    if (large_name == NULL)
+      {
+	puts ("malloc failure");
+	return 1;
+      }
+    memset (large_name, '/', large_length);
+    const char *suffix = "en_US.UTF-8";
+    strcpy (large_name + large_length - strlen (suffix), suffix);
+    setlocale_fail (large_name);
+    free (large_name);
+  }
+  {
+    size_t huge_length = 64 * 1024 * 1024;
+    char *huge_name = malloc (huge_length + 1);
+    if (huge_name == NULL)
+      {
+	puts ("malloc failure");
+	return 1;
+      }
+    memset (huge_name, 'X', huge_length);
+    huge_name[huge_length] = '\0';
+    /* Construct a composite locale specification. */
+    const char *prefix = "LC_CTYPE=de_DE.UTF-8;LC_TIME=";
+    memcpy (huge_name, prefix, strlen (prefix));
+    setlocale_fail (huge_name);
+    free (huge_name);
+  }
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=588b214bc7fa3e54d6b679ed4b755e6d1310e61d

commit 588b214bc7fa3e54d6b679ed4b755e6d1310e61d
Author: Florian Weimer <fweimer@redhat.com>
Date:   Tue Aug 26 19:38:59 2014 +0200

    __gconv_translit_find: Disable function [BZ #17187]
    
    This functionality has never worked correctly, and the implementation
    contained a security vulnerability (CVE-2014-5119).

diff --git a/ChangeLog b/ChangeLog
index 8423dd5..a1cc122 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2014-08-26  Florian Weimer  <fweimer@redhat.com>
+
+	[BZ #17187]
+	* iconv/gconv_trans.c (struct known_trans, search_tree, lock,
+	trans_compare, open_translit, __gconv_translit_find):
+	Remove module loading code.
+
 2014-09-03  Florian Weimer  <fweimer@redhat.com>
 
 	[BZ #17325]
diff --git a/NEWS b/NEWS
index 022da81..3665933 100644
--- a/NEWS
+++ b/NEWS
@@ -10,7 +10,14 @@ Version 2.16.1
 * The following bugs are resolved with this release:
 
   6530, 14195, 14547, 14459, 14476, 14562, 14621, 14648, 14699, 14756, 14831,
-  15078, 15754, 15755, 16072, 17325.
+  15078, 15754, 15755, 16072, 17187, 17325.
+
+* Support for loadable gconv transliteration modules has been removed.
+  The support for transliteration modules has been non-functional for
+  over a decade, and the removal is prompted by security defects.  The
+  normal gconv conversion modules are still supported.  Transliteration
+  with //TRANSLIT is still possible, and the //IGNORE specifier
+  continues to be  supported. (CVE-2014-5119)
 
 * Decoding a crafted input sequence in the character sets IBM933, IBM935,
   IBM937, IBM939, IBM1364 could result in an out-of-bounds array read,
diff --git a/iconv/gconv_trans.c b/iconv/gconv_trans.c
index 64ca97d..786c1af 100644
--- a/iconv/gconv_trans.c
+++ b/iconv/gconv_trans.c
@@ -238,181 +238,12 @@ __gconv_transliterate (struct __gconv_step *step,
   return __GCONV_ILLEGAL_INPUT;
 }
 
-
-/* Structure to represent results of found (or not) transliteration
-   modules.  */
-struct known_trans
-{
-  /* This structure must remain the first member.  */
-  struct trans_struct info;
-
-  char *fname;
-  void *handle;
-  int open_count;
-};
-
-
-/* Tree with results of previous calls to __gconv_translit_find.  */
-static void *search_tree;
-
-/* We modify global data.   */
-__libc_lock_define_initialized (static, lock);
-
-
-/* Compare two transliteration entries.  */
-static int
-trans_compare (const void *p1, const void *p2)
-{
-  const struct known_trans *s1 = (const struct known_trans *) p1;
-  const struct known_trans *s2 = (const struct known_trans *) p2;
-
-  return strcmp (s1->info.name, s2->info.name);
-}
-
-
-/* Open (maybe reopen) the module named in the struct.  Get the function
-   and data structure pointers we need.  */
-static int
-open_translit (struct known_trans *trans)
-{
-  __gconv_trans_query_fct queryfct;
-
-  trans->handle = __libc_dlopen (trans->fname);
-  if (trans->handle == NULL)
-    /* Not available.  */
-    return 1;
-
-  /* Find the required symbol.  */
-  queryfct = __libc_dlsym (trans->handle, "gconv_trans_context");
-  if (queryfct == NULL)
-    {
-      /* We cannot live with that.  */
-    close_and_out:
-      __libc_dlclose (trans->handle);
-      trans->handle = NULL;
-      return 1;
-    }
-
-  /* Get the context.  */
-  if (queryfct (trans->info.name, &trans->info.csnames, &trans->info.ncsnames)
-      != 0)
-    goto close_and_out;
-
-  /* Of course we also have to have the actual function.  */
-  trans->info.trans_fct = __libc_dlsym (trans->handle, "gconv_trans");
-  if (trans->info.trans_fct == NULL)
-    goto close_and_out;
-
-  /* Now the optional functions.  */
-  trans->info.trans_init_fct =
-    __libc_dlsym (trans->handle, "gconv_trans_init");
-  trans->info.trans_context_fct =
-    __libc_dlsym (trans->handle, "gconv_trans_context");
-  trans->info.trans_end_fct =
-    __libc_dlsym (trans->handle, "gconv_trans_end");
-
-  trans->open_count = 1;
-
-  return 0;
-}
-
-
 int
 internal_function
 __gconv_translit_find (struct trans_struct *trans)
 {
-  struct known_trans **found;
-  const struct path_elem *runp;
-  int res = 1;
-
-  /* We have to have a name.  */
-  assert (trans->name != NULL);
-
-  /* Acquire the lock.  */
-  __libc_lock_lock (lock);
-
-  /* See whether we know this module already.  */
-  found = __tfind (trans, &search_tree, trans_compare);
-  if (found != NULL)
-    {
-      /* Is this module available?  */
-      if ((*found)->handle != NULL)
-	{
-	  /* Maybe we have to reopen the file.  */
-	  if ((*found)->handle != (void *) -1)
-	    /* The object is not unloaded.  */
-	    res = 0;
-	  else if (open_translit (*found) == 0)
-	    {
-	      /* Copy the data.  */
-	      *trans = (*found)->info;
-	      (*found)->open_count++;
-	      res = 0;
-	    }
-	}
-    }
-  else
-    {
-      size_t name_len = strlen (trans->name) + 1;
-      int need_so = 0;
-      struct known_trans *newp;
-
-      /* We have to continue looking for the module.  */
-      if (__gconv_path_elem == NULL)
-	__gconv_get_path ();
-
-      /* See whether we have to append .so.  */
-      if (name_len <= 4 || memcmp (&trans->name[name_len - 4], ".so", 3) != 0)
-	need_so = 1;
-
-      /* Create a new entry.  */
-      newp = (struct known_trans *) malloc (sizeof (struct known_trans)
-					    + (__gconv_max_path_elem_len
-					       + name_len + 3)
-					    + name_len);
-      if (newp != NULL)
-	{
-	  char *cp;
-
-	  /* Clear the struct.  */
-	  memset (newp, '\0', sizeof (struct known_trans));
-
-	  /* Store a copy of the module name.  */
-	  newp->info.name = cp = (char *) (newp + 1);
-	  cp = __mempcpy (cp, trans->name, name_len);
-
-	  newp->fname = cp;
-
-	  /* Search in all the directories.  */
-	  for (runp = __gconv_path_elem; runp->name != NULL; ++runp)
-	    {
-	      cp = __mempcpy (__stpcpy ((char *) newp->fname, runp->name),
-			      trans->name, name_len);
-	      if (need_so)
-		memcpy (cp, ".so", sizeof (".so"));
-
-	      if (open_translit (newp) == 0)
-		{
-		  /* We found a module.  */
-		  res = 0;
-		  break;
-		}
-	    }
-
-	  if (res)
-	    newp->fname = NULL;
-
-	  /* In any case we'll add the entry to our search tree.  */
-	  if (__tsearch (newp, &search_tree, trans_compare) == NULL)
-	    {
-	      /* Yickes, this should not happen.  Unload the object.  */
-	      res = 1;
-	      /* XXX unload here.  */
-	    }
-	}
-    }
-
-  __libc_lock_unlock (lock);
-
-  return res;
+  /* Transliteration module loading has been removed because it never
+     worked as intended and suffered from a security vulnerability.
+     Consequently, this function always fails.  */
+  return 1;
 }

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=bd51e93f9305e37aa17e08dbdb86a2e146c09eff

commit bd51e93f9305e37aa17e08dbdb86a2e146c09eff
Author: Florian Weimer <fweimer@redhat.com>
Date:   Wed Sep 3 19:45:43 2014 +0200

    CVE-2014-6040: Crashes on invalid input in IBM gconv modules [BZ #17325]
    
    These changes are based on the fix for BZ #14134 in commit
    6e230d11837f3ae7b375ea69d7905f0d18eb79e5.

diff --git a/ChangeLog b/ChangeLog
index 1669b71..8423dd5 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,20 @@
+2014-09-03  Florian Weimer  <fweimer@redhat.com>
+
+	[BZ #17325]
+	* iconvdata/ibm1364.c (BODY): Fix check for sentinel.
+	* iconvdata/ibm932.c (BODY): Replace invalid sentinel check with
+	assert.
+	* iconvdata/ibm933.c (BODY): Fix check for sentinel.
+	* iconvdata/ibm935.c (BODY): Likewise.
+	* iconvdata/ibm937.c (BODY): Likewise.
+	* iconvdata/ibm939.c (BODY): Likewise.
+	* iconvdata/ibm943.c (BODY): Replace invalid sentinel check with
+	assert.
+	* iconvdata/Makefile (iconv-test.out): Pass module list to test
+	script.
+	* iconvdata/run-iconv-test.sh: New test loop for checking for
+	decoder crashers.
+
 2013-09-11  Will Newton  <will.newton@linaro.org>
 
 	[BZ #15857]
diff --git a/NEWS b/NEWS
index 86f3232..022da81 100644
--- a/NEWS
+++ b/NEWS
@@ -10,7 +10,12 @@ Version 2.16.1
 * The following bugs are resolved with this release:
 
   6530, 14195, 14547, 14459, 14476, 14562, 14621, 14648, 14699, 14756, 14831,
-  15078, 15754, 15755, 16072.
+  15078, 15754, 15755, 16072, 17325.
+
+* Decoding a crafted input sequence in the character sets IBM933, IBM935,
+  IBM937, IBM939, IBM1364 could result in an out-of-bounds array read,
+  resulting a denial-of-service security vulnerability in applications which
+  use functions related to iconv. (CVE-2014-6040)
 
 * CVE-2013-4332 The pvalloc, valloc, memalign, posix_memalign and
   aligned_alloc functions could allocate too few bytes or corrupt the
diff --git a/iconvdata/Makefile b/iconvdata/Makefile
index eac51ba..74d468f 100644
--- a/iconvdata/Makefile
+++ b/iconvdata/Makefile
@@ -299,7 +299,9 @@ $(objpfx)tst-iconv7.out: $(objpfx)gconv-modules \
 $(objpfx)iconv-test.out: run-iconv-test.sh $(objpfx)gconv-modules \
 			 $(addprefix $(objpfx),$(modules.so)) \
 			 $(common-objdir)/iconv/iconv_prog TESTS
-	$(SHELL) -e $< $(common-objdir) > $@
+	iconv_modules="$(modules)" \
+	$(SHELL) $< $(common-objdir) '$(test-wrapper-env)' \
+		 '$(run-program-env)' > $@
 
 $(objpfx)tst-tables.out: tst-tables.sh $(objpfx)gconv-modules \
 			 $(addprefix $(objpfx),$(modules.so)) \
diff --git a/iconvdata/ibm1364.c b/iconvdata/ibm1364.c
index 09202a2..dc71cd7 100644
--- a/iconvdata/ibm1364.c
+++ b/iconvdata/ibm1364.c
@@ -220,7 +220,8 @@ enum
 	  ++rp2;							      \
 									      \
 	uint32_t res;							      \
-	if (__builtin_expect (ch < rp2->start, 0)			      \
+	if (__builtin_expect (rp2->start == 0xffff, 0)			      \
+	    || __builtin_expect (ch < rp2->start, 0)			      \
 	    || (res = DB_TO_UCS4[ch + rp2->idx],			      \
 		__builtin_expect (res, L'\1') == L'\0' && ch != '\0'))	      \
 	  {								      \
diff --git a/iconvdata/ibm932.c b/iconvdata/ibm932.c
index bd070e1..d88185c 100644
--- a/iconvdata/ibm932.c
+++ b/iconvdata/ibm932.c
@@ -73,11 +73,12 @@
 	  }								      \
 									      \
 	ch = (ch * 0x100) + inptr[1];					      \
+	/* ch was less than 0xfd.  */					      \
+	assert (ch < 0xfd00);						      \
 	while (ch > rp2->end)						      \
 	  ++rp2;							      \
 									      \
-	if (__builtin_expect (rp2 == NULL, 0)				      \
-	    || __builtin_expect (ch < rp2->start, 0)			      \
+	if (__builtin_expect (ch < rp2->start, 0)			      \
 	    || (res = __ibm932db_to_ucs4[ch + rp2->idx],		      \
 	    __builtin_expect (res, '\1') == 0 && ch !=0))		      \
 	  {								      \
diff --git a/iconvdata/ibm933.c b/iconvdata/ibm933.c
index 12c2071..9d9886f 100644
--- a/iconvdata/ibm933.c
+++ b/iconvdata/ibm933.c
@@ -161,7 +161,7 @@ enum
 	while (ch > rp2->end)						      \
 	  ++rp2;							      \
 									      \
-	if (__builtin_expect (rp2 == NULL, 0)				      \
+	if (__builtin_expect (rp2->start == 0xffff, 0)			      \
 	    || __builtin_expect (ch < rp2->start, 0)			      \
 	    || (res = __ibm933db_to_ucs4[ch + rp2->idx],		      \
 		__builtin_expect (res, L'\1') == L'\0' && ch != '\0'))	      \
diff --git a/iconvdata/ibm935.c b/iconvdata/ibm935.c
index 110d513..966a092 100644
--- a/iconvdata/ibm935.c
+++ b/iconvdata/ibm935.c
@@ -161,7 +161,7 @@ enum
 	while (ch > rp2->end)						      \
 	  ++rp2;							      \
 									      \
-	if (__builtin_expect (rp2 == NULL, 0)				      \
+	if (__builtin_expect (rp2->start == 0xffff, 0)			      \
 	    || __builtin_expect (ch < rp2->start, 0)			      \
 	    || (res = __ibm935db_to_ucs4[ch + rp2->idx],		      \
 		__builtin_expect (res, L'\1') == L'\0' && ch != '\0'))	      \
diff --git a/iconvdata/ibm937.c b/iconvdata/ibm937.c
index c88f9e2..20dd9bf 100644
--- a/iconvdata/ibm937.c
+++ b/iconvdata/ibm937.c
@@ -161,7 +161,7 @@ enum
 	while (ch > rp2->end)						      \
 	  ++rp2;							      \
 									      \
-	if (__builtin_expect (rp2 == NULL, 0)				      \
+	if (__builtin_expect (rp2->start == 0xffff, 0)			      \
 	    || __builtin_expect (ch < rp2->start, 0)			      \
 	    || (res = __ibm937db_to_ucs4[ch + rp2->idx],		      \
 		__builtin_expect (res, L'\1') == L'\0' && ch != '\0'))	      \
diff --git a/iconvdata/ibm939.c b/iconvdata/ibm939.c
index 6eefabc..482f26a 100644
--- a/iconvdata/ibm939.c
+++ b/iconvdata/ibm939.c
@@ -161,7 +161,7 @@ enum
 	while (ch > rp2->end)						      \
 	  ++rp2;							      \
 									      \
-	if (__builtin_expect (rp2 == NULL, 0)				      \
+	if (__builtin_expect (rp2->start == 0xffff, 0)			      \
 	    || __builtin_expect (ch < rp2->start, 0)			      \
 	    || (res = __ibm939db_to_ucs4[ch + rp2->idx],		      \
 		__builtin_expect (res, L'\1') == L'\0' && ch != '\0'))	      \
diff --git a/iconvdata/ibm943.c b/iconvdata/ibm943.c
index bc2cec3..e020d09 100644
--- a/iconvdata/ibm943.c
+++ b/iconvdata/ibm943.c
@@ -74,11 +74,12 @@
 	  }								      \
 									      \
 	ch = (ch * 0x100) + inptr[1];					      \
+	/* ch was less than 0xfd.  */					      \
+	assert (ch < 0xfd00);						      \
 	while (ch > rp2->end)						      \
 	  ++rp2;							      \
 									      \
-	if (__builtin_expect (rp2 == NULL, 0)				      \
-	    || __builtin_expect (ch < rp2->start, 0)			      \
+	if (__builtin_expect (ch < rp2->start, 0)			      \
 	    || (res = __ibm943db_to_ucs4[ch + rp2->idx],		      \
 	    __builtin_expect (res, '\1') == 0 && ch !=0))		      \
 	  {								      \
diff --git a/iconvdata/run-iconv-test.sh b/iconvdata/run-iconv-test.sh
index 60be69f..f689b6f 100755
--- a/iconvdata/run-iconv-test.sh
+++ b/iconvdata/run-iconv-test.sh
@@ -185,6 +185,24 @@ while read utf8 from filename; do
 
 done < TESTS2
 
+# Check for crashes in decoders.
+printf '\016\377\377\377\377\377\377\377' > $temp1
+for from in $iconv_modules ; do
+    echo $ac_n "test decoder $from $ac_c"
+    PROG=`eval echo $ICONV`
+    if $PROG < $temp1 >/dev/null 2>&1 ; then
+	: # fall through
+    else
+	status=$?
+	if test $status -gt 1 ; then
+	    echo "/FAILED"
+	    failed=1
+	    continue
+	fi
+    fi
+    echo "OK"
+done
+
 exit $failed
 # Local Variables:
 #  mode:shell-script

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=97ef0b2223e10fe3053494defd8a008d7dd9d6d8

commit 97ef0b2223e10fe3053494defd8a008d7dd9d6d8
Author: Will Newton <will.newton@linaro.org>
Date:   Fri Sep 13 09:26:02 2013 +0100

    Add CVE-2013-4332 to NEWS.

diff --git a/NEWS b/NEWS
index b254318..86f3232 100644
--- a/NEWS
+++ b/NEWS
@@ -12,6 +12,11 @@ Version 2.16.1
   6530, 14195, 14547, 14459, 14476, 14562, 14621, 14648, 14699, 14756, 14831,
   15078, 15754, 15755, 16072.
 
+* CVE-2013-4332 The pvalloc, valloc, memalign, posix_memalign and
+  aligned_alloc functions could allocate too few bytes or corrupt the
+  heap when passed very large allocation size values (Bugzilla #15855,
+  #15856, #15857).
+
 * CVE-2013-4237 The readdir_r function could write more than NAME_MAX bytes
   to the d_name member of struct dirent, or omit the terminating NUL
   character.  (Bugzilla #14699).

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=ccb8f6bab96cfcc7aedf5cd0d1946f26b028d733

commit ccb8f6bab96cfcc7aedf5cd0d1946f26b028d733
Author: Will Newton <will.newton@linaro.org>
Date:   Fri Aug 16 12:54:29 2013 +0100

    malloc: Check for integer overflow in memalign.
    
    A large bytes parameter to memalign could cause an integer overflow
    and corrupt allocator internals. Check the overflow does not occur
    before continuing with the allocation.
    
    ChangeLog:
    
    2013-09-11  Will Newton  <will.newton@linaro.org>
    
    	[BZ #15857]
    	* malloc/malloc.c (__libc_memalign): Check the value of bytes
    	does not overflow.

diff --git a/ChangeLog b/ChangeLog
index bd8deaf..1669b71 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,11 @@
 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.
diff --git a/malloc/malloc.c b/malloc/malloc.c
index d5dacbf..d04cae8 100644
--- a/malloc/malloc.c
+++ b/malloc/malloc.c
@@ -3030,6 +3030,13 @@ __libc_memalign(size_t alignment, size_t bytes)
   /* Otherwise, ensure that it is at least a minimum chunk size */
   if (alignment <  MINSIZE) alignment = MINSIZE;
 
+  /* 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;

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=f1292792799a507711ce24b497e40f8fea8f9c9c

commit f1292792799a507711ce24b497e40f8fea8f9c9c
Author: Will Newton <will.newton@linaro.org>
Date:   Fri Aug 16 11:59:37 2013 +0100

    malloc: Check for integer overflow in valloc.
    
    A large bytes parameter to valloc could cause an integer overflow
    and corrupt allocator internals. Check the overflow does not occur
    before continuing with the allocation.
    
    ChangeLog:
    
    2013-09-11  Will Newton  <will.newton@linaro.org>
    
    	[BZ #15856]
    	* malloc/malloc.c (__libc_valloc): Check the value of bytes
    	does not overflow.

diff --git a/ChangeLog b/ChangeLog
index edf1a9c..bd8deaf 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,11 @@
 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.
diff --git a/malloc/malloc.c b/malloc/malloc.c
index ee89a67..d5dacbf 100644
--- a/malloc/malloc.c
+++ b/malloc/malloc.c
@@ -3073,8 +3073,14 @@ __libc_valloc(size_t bytes)
 
   size_t pagesz = GLRO(dl_pagesize);
 
-  __malloc_ptr_t (*hook) __MALLOC_PMT ((size_t, size_t,
-					const __malloc_ptr_t)) =
+  /* Check for overflow.  */
+  if (bytes > SIZE_MAX - pagesz - MINSIZE)
+    {
+      __set_errno (ENOMEM);
+      return 0;
+    }
+
+  void *(*hook) (size_t, size_t, const void *) =
     force_reg (__memalign_hook);
   if (__builtin_expect (hook != NULL, 0))
     return (*hook)(pagesz, bytes, RETURN_ADDRESS (0));

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=b1e934aed5170eb8948e0f3c6618c9431d6810ad

commit b1e934aed5170eb8948e0f3c6618c9431d6810ad
Author: Will Newton <will.newton@linaro.org>
Date:   Mon Aug 12 15:08:02 2013 +0100

    malloc: Check for integer overflow in pvalloc.
    
    A large bytes parameter to pvalloc could cause an integer overflow
    and corrupt allocator internals. Check the overflow does not occur
    before continuing with the allocation.
    
    ChangeLog:
    
    2013-09-11  Will Newton  <will.newton@linaro.org>
    
    	[BZ #15855]
    	* malloc/malloc.c (__libc_pvalloc): Check the value of bytes
    	does not overflow.

diff --git a/ChangeLog b/ChangeLog
index 9997c1c..edf1a9c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2013-09-11  Will Newton  <will.newton@linaro.org>
+
+	[BZ #15855]
+	* malloc/malloc.c (__libc_pvalloc): Check the value of bytes
+	does not overflow.
+
 2013-08-16  Florian Weimer  <fweimer@redhat.com>
 
 	[BZ #14699]
diff --git a/malloc/malloc.c b/malloc/malloc.c
index 28039b4..ee89a67 100644
--- a/malloc/malloc.c
+++ b/malloc/malloc.c
@@ -3119,6 +3119,13 @@ __libc_pvalloc(size_t bytes)
   size_t page_mask = GLRO(dl_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);

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=bcd619797e785f90cc9fd67208267c26c8e4b40d

commit bcd619797e785f90cc9fd67208267c26c8e4b40d
Author: Florian Weimer <fweimer@redhat.com>
Date:   Fri Aug 16 09:38:52 2013 +0200

    CVE-2013-4237, BZ #14699: Buffer overflow in readdir_r
    
    	* 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.

diff --git a/ChangeLog b/ChangeLog
index 05c13c0..9997c1c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,25 @@
+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.
+
 2013-09-23  Carlos O'Donell  <carlos@redhat.com>
 
 	[BZ #15754]
diff --git a/NEWS b/NEWS
index ceebbbb..b254318 100644
--- a/NEWS
+++ b/NEWS
@@ -9,8 +9,12 @@ Version 2.16.1
 
 * The following bugs are resolved with this release:
 
-  6530, 14195, 14547, 14459, 14476, 14562, 14621, 14648, 14756, 14831, 15078,
-  15754, 15755, 16072.
+  6530, 14195, 14547, 14459, 14476, 14562, 14621, 14648, 14699, 14756, 14831,
+  15078, 15754, 15755, 16072.
+
+* CVE-2013-4237 The readdir_r function could write more than NAME_MAX bytes
+  to the d_name member of struct dirent, or omit the terminating NUL
+  character.  (Bugzilla #14699).
 
 * CVE-2013-4788 The pointer guard used for pointer mangling was not
   initialized for static applications resulting in the security feature
diff --git a/manual/conf.texi b/manual/conf.texi
index 61dc260..f2bd33a 100644
--- a/manual/conf.texi
+++ b/manual/conf.texi
@@ -1474,6 +1474,9 @@ Inquire about the value of @code{POSIX_REC_MIN_XFER_SIZE}.
 Inquire about the value of @code{POSIX_REC_XFER_ALIGN}.
 @end table
 
+@strong{Portability Note:} On some systems, @theglibc{} does not
+enforce @code{_PC_NAME_MAX} or @code{_PC_PATH_MAX} limits.
+
 @node Utility Limits
 @section Utility Program Capacity Limits
 
diff --git a/manual/filesys.texi b/manual/filesys.texi
index 7003f9c..e278468 100644
--- a/manual/filesys.texi
+++ b/manual/filesys.texi
@@ -444,9 +444,9 @@ symbols are declared in the header file @file{dirent.h}.
 @comment POSIX.1
 @deftypefun {struct dirent *} readdir (DIR *@var{dirstream})
 This function reads the next entry from the directory.  It normally
-returns a pointer to a structure containing information about the file.
-This structure is statically allocated and can be rewritten by a
-subsequent call.
+returns a pointer to a structure containing information about the
+file.  This structure is associated with the @var{dirstream} handle
+and can be rewritten by a subsequent call.
 
 @strong{Portability Note:} On some systems @code{readdir} may not
 return entries for @file{.} and @file{..}, even though these are always
@@ -461,19 +461,61 @@ conditions are defined for this function:
 The @var{dirstream} argument is not valid.
 @end table
 
-@code{readdir} is not thread safe.  Multiple threads using
-@code{readdir} on the same @var{dirstream} may overwrite the return
-value.  Use @code{readdir_r} when this is critical.
+To distinguish between an end-of-directory condition or an error, you
+must set @code{errno} to zero before calling @code{readdir}.  To avoid
+entering an infinite loop, you should stop reading from the directory
+after the first error.
+
+In POSIX.1-2008, @code{readdir} is not thread-safe.  In @theglibc{}
+implementation, it is safe to call @code{readdir} concurrently on
+different @var{dirstream}s, but multiple threads accessing the same
+@var{dirstream} result in undefined behavior.  @code{readdir_r} is a
+fully thread-safe alternative, but suffers from poor portability (see
+below).  It is recommended that you use @code{readdir}, with external
+locking if multiple threads access the same @var{dirstream}.
 @end deftypefun
 
 @comment dirent.h
 @comment GNU
 @deftypefun int readdir_r (DIR *@var{dirstream}, struct dirent *@var{entry}, struct dirent **@var{result})
-This function is the reentrant version of @code{readdir}.  Like
-@code{readdir} it returns the next entry from the directory.  But to
-prevent conflicts between simultaneously running threads the result is
-not stored in statically allocated memory.  Instead the argument
-@var{entry} points to a place to store the result.
+This function is a version of @code{readdir} which performs internal
+locking.  Like @code{readdir} it returns the next entry from the
+directory.  To prevent conflicts between simultaneously running
+threads the result is stored inside the @var{entry} object.
+
+@strong{Portability Note:} It is recommended to use @code{readdir}
+instead of @code{readdir_r} for the following reasons:
+
+@itemize @bullet
+@item
+On systems which do not define @code{NAME_MAX}, it may not be possible
+to use @code{readdir_r} safely because the caller does not specify the
+length of the buffer for the directory entry.
+
+@item
+On some systems, @code{readdir_r} cannot read directory entries with
+very long names.  If such a name is encountered, @theglibc{}
+implementation of @code{readdir_r} returns with an error code of
+@code{ENAMETOOLONG} after the final directory entry has been read.  On
+other systems, @code{readdir_r} may return successfully, but the
+@code{d_name} member may not be NUL-terminated or may be truncated.
+
+@item
+POSIX-1.2008 does not guarantee that @code{readdir} is thread-safe,
+even when access to the same @var{dirstream} is serialized.  But in
+current implementations (including @theglibc{}), it is safe to call
+@code{readdir} concurrently on different @var{dirstream}s, so there is
+no need to use @code{readdir_r} in most multi-threaded programs.  In
+the rare case that multiple threads need to read from the same
+@var{dirstream}, it is still better to use @code{readdir} and external
+synchronization.
+
+@item
+It is expected that future versions of POSIX will obsolete
+@code{readdir_r} and mandate the level of thread safety for
+@code{readdir} which is provided by @theglibc{} and other
+implementations today.
+@end itemize
 
 Normally @code{readdir_r} returns zero and sets @code{*@var{result}}
 to @var{entry}.  If there are no more entries in the directory or an
@@ -481,15 +523,6 @@ error is detected, @code{readdir_r} sets @code{*@var{result}} to a
 null pointer and returns a nonzero error code, also stored in
 @code{errno}, as described for @code{readdir}.
 
-@strong{Portability Note:} On some systems @code{readdir_r} may not
-return a NUL terminated string for the file name, even when there is no
-@code{d_reclen} field in @code{struct dirent} and the file
-name is the maximum allowed size.  Modern systems all have the
-@code{d_reclen} field, and on old systems multi-threading is not
-critical.  In any case there is no such problem with the @code{readdir}
-function, so that even on systems without the @code{d_reclen} member one
-could use multiple threads by using external locking.
-
 It is also important to look at the definition of the @code{struct
 dirent} type.  Simply passing a pointer to an object of this type for
 the second parameter of @code{readdir_r} might not be enough.  Some
diff --git a/sysdeps/unix/dirstream.h b/sysdeps/unix/dirstream.h
index 6ca2904..e31cdf3 100644
--- a/sysdeps/unix/dirstream.h
+++ b/sysdeps/unix/dirstream.h
@@ -39,6 +39,8 @@ struct __dirstream
 
     off_t filepos;		/* Position of next entry to read.  */
 
+    int errcode;		/* Delayed error code.  */
+
     /* Directory block.  */
     char data[0] __attribute__ ((aligned (__alignof__ (void*))));
   };
diff --git a/sysdeps/unix/opendir.c b/sysdeps/unix/opendir.c
index e093142..916d7bc 100644
--- a/sysdeps/unix/opendir.c
+++ b/sysdeps/unix/opendir.c
@@ -223,6 +223,7 @@ __alloc_dir (int fd, bool close_fd, int flags, const struct stat64 *statp)
   dirp->size = 0;
   dirp->offset = 0;
   dirp->filepos = 0;
+  dirp->errcode = 0;
 
   return dirp;
 }
diff --git a/sysdeps/unix/readdir_r.c b/sysdeps/unix/readdir_r.c
index bfa2c0b..878693b 100644
--- a/sysdeps/unix/readdir_r.c
+++ b/sysdeps/unix/readdir_r.c
@@ -41,6 +41,7 @@ __READDIR_R (DIR *dirp, DIRENT_TYPE *entry, DIRENT_TYPE **result)
   DIRENT_TYPE *dp;
   size_t reclen;
   const int saved_errno = errno;
+  int ret;
 
   __libc_lock_lock (dirp->lock);
 
@@ -71,10 +72,10 @@ __READDIR_R (DIR *dirp, DIRENT_TYPE *entry, DIRENT_TYPE **result)
 		  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;
@@ -107,29 +108,46 @@ __READDIR_R (DIR *dirp, DIRENT_TYPE *entry, DIRENT_TYPE **result)
       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
diff --git a/sysdeps/unix/rewinddir.c b/sysdeps/unix/rewinddir.c
index f8eefea..5e99cb0 100644
--- a/sysdeps/unix/rewinddir.c
+++ b/sysdeps/unix/rewinddir.c
@@ -33,6 +33,7 @@ rewinddir (dirp)
   dirp->filepos = 0;
   dirp->offset = 0;
   dirp->size = 0;
+  dirp->errcode = 0;
 #ifndef NOT_IN_libc
   __libc_lock_unlock (dirp->lock);
 #endif
diff --git a/sysdeps/unix/sysv/linux/i386/readdir64_r.c b/sysdeps/unix/sysv/linux/i386/readdir64_r.c
index 3b3116c..bc1f7e5 100644
--- a/sysdeps/unix/sysv/linux/i386/readdir64_r.c
+++ b/sysdeps/unix/sysv/linux/i386/readdir64_r.c
@@ -18,7 +18,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>
 
diff --git a/sysdeps/unix/sysv/linux/wordsize-64/readdir_r.c b/sysdeps/unix/sysv/linux/wordsize-64/readdir_r.c
index 12ca1a1..adb92db 100644
--- 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)

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=6fd8e941423354e6c7a951d37a60d2f1424d568e

commit 6fd8e941423354e6c7a951d37a60d2f1424d568e
Author: Carlos O'Donell <carlos@redhat.com>
Date:   Mon Sep 23 00:52:09 2013 -0400

    BZ #15754: CVE-2013-4788
    
    The pointer guard used for pointer mangling was not initialized for
    static applications resulting in the security feature being disabled.
    The pointer guard is now correctly initialized to a random value for
    static applications. Existing static applications need to be
    recompiled to take advantage of the fix.
    
    The test tst-ptrguard1-static and tst-ptrguard1 add regression
    coverage to ensure the pointer guards are sufficiently random
    and initialized to a default value.

diff --git a/ChangeLog b/ChangeLog
index 846b7b4..05c13c0 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,33 @@
+2013-09-23  Carlos O'Donell  <carlos@redhat.com>
+
+	[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-23  Siddhesh Poyarekar  <siddhesh@redhat.com>
 
 	[BZ #14547]
diff --git a/NEWS b/NEWS
index 9339139..ceebbbb 100644
--- a/NEWS
+++ b/NEWS
@@ -10,7 +10,13 @@ Version 2.16.1
 * The following bugs are resolved with this release:
 
   6530, 14195, 14547, 14459, 14476, 14562, 14621, 14648, 14756, 14831, 15078,
-  15755, 16072.
+  15754, 15755, 16072.
+
+* CVE-2013-4788 The pointer guard used for pointer mangling was not
+  initialized for static applications resulting in the security feature
+  being disabled. The pointer guard is now correctly initialized to a
+  random value for static applications. Existing static applications need
+  to be recompiled to take advantage of the fix (bug 15754).
 
 * CVE-2012-4412 The strcoll implementation caches indices and rules for
   large collation sequences to optimize multiple passes.  This cache
diff --git a/csu/libc-start.c b/csu/libc-start.c
index 0f9bfd7..3d684ea 100644
--- a/csu/libc-start.c
+++ b/csu/libc-start.c
@@ -38,6 +38,12 @@ extern void __pthread_initialize_minimal (void);
    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
@@ -151,6 +157,16 @@ LIBC_START_MAIN (int (*main) (int, char **, char ** MAIN_AUXVEC_DECL),
 # 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.  */
diff --git a/elf/Makefile b/elf/Makefile
index a621a1c..0500905 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -114,7 +114,8 @@ tests = tst-tls1 tst-tls2 tst-tls9 tst-leaks1
 ifeq (yes,$(have-initfini-array))
 tests += tst-array1 tst-array2 tst-array3 tst-array4 tst-array5
 endif
-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 (yes,$(build-shared))
 tests-static += tst-tls9-static
 tst-tls9-static-ENV = \
@@ -141,7 +142,8 @@ tests += loadtest restest1 preloadtest loadfail multiload origtest resolvfail \
 	 tst-audit1 tst-audit2 tst-audit8 \
 	 tst-stackguard1 tst-addr1 tst-thrlock \
 	 tst-unique1 tst-unique2 tst-unique3 tst-unique4 \
-	 tst-initorder tst-initorder2 tst-relsort1
+	 tst-initorder tst-initorder2 tst-relsort1 \
+	 tst-ptrguard1
 #	 reldep9
 test-srcs = tst-pathopt
 selinux-enabled := $(shell cat /selinux/enforce 2> /dev/null)
@@ -1048,6 +1050,9 @@ LDFLAGS-order2mod2.so = $(no-as-needed)
 tst-stackguard1-ARGS = --command "$(built-program-cmd) --child"
 tst-stackguard1-static-ARGS = --command "$(objpfx)tst-stackguard1-static --child"
 
+tst-ptrguard1-ARGS = --command "$(host-test-program-cmd) --child"
+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 > $@
diff --git a/elf/tst-ptrguard1-static.c b/elf/tst-ptrguard1-static.c
new file mode 100644
index 0000000..7aff3b7
--- /dev/null
+++ b/elf/tst-ptrguard1-static.c
@@ -0,0 +1 @@
+#include "tst-ptrguard1.c"
diff --git a/elf/tst-ptrguard1.c b/elf/tst-ptrguard1.c
new file mode 100644
index 0000000..c344a04
--- /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"
diff --git a/sysdeps/generic/stackguard-macros.h b/sysdeps/generic/stackguard-macros.h
index ababf65..4fa3d96 100644
--- a/sysdeps/generic/stackguard-macros.h
+++ b/sysdeps/generic/stackguard-macros.h
@@ -2,3 +2,6 @@
 
 extern uintptr_t __stack_chk_guard;
 #define STACK_CHK_GUARD __stack_chk_guard
+
+extern uintptr_t __pointer_chk_guard_local;
+#define POINTER_CHK_GUARD __pointer_chk_guard_local
diff --git a/sysdeps/i386/stackguard-macros.h b/sysdeps/i386/stackguard-macros.h
index 8c31e19..0397629 100644
--- a/sysdeps/i386/stackguard-macros.h
+++ b/sysdeps/i386/stackguard-macros.h
@@ -2,3 +2,11 @@
 
 #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;							\
+   })
diff --git a/sysdeps/powerpc/powerpc32/stackguard-macros.h b/sysdeps/powerpc/powerpc32/stackguard-macros.h
index 839f6a4..b3d0af8 100644
--- a/sysdeps/powerpc/powerpc32/stackguard-macros.h
+++ b/sysdeps/powerpc/powerpc32/stackguard-macros.h
@@ -2,3 +2,13 @@
 
 #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;												\
+   })
diff --git a/sysdeps/powerpc/powerpc64/stackguard-macros.h b/sysdeps/powerpc/powerpc64/stackguard-macros.h
index 9da879c..4620f96 100644
--- a/sysdeps/powerpc/powerpc64/stackguard-macros.h
+++ b/sysdeps/powerpc/powerpc64/stackguard-macros.h
@@ -2,3 +2,13 @@
 
 #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(2)"										\
+	  : "=r" (x)										\
+	  : "i" (offsetof (tcbhead_t, pointer_guard) - TLS_TCB_OFFSET - sizeof (tcbhead_t))	\
+         );											\
+     x;												\
+   })
diff --git a/sysdeps/s390/s390-32/stackguard-macros.h b/sysdeps/s390/s390-32/stackguard-macros.h
index b74c579..449e8d4 100644
--- a/sysdeps/s390/s390-32/stackguard-macros.h
+++ b/sysdeps/s390/s390-32/stackguard-macros.h
@@ -2,3 +2,14 @@
 
 #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;							\
+   })
diff --git a/sysdeps/s390/s390-64/stackguard-macros.h b/sysdeps/s390/s390-64/stackguard-macros.h
index 0cebb5f..c8270fb 100644
--- a/sysdeps/s390/s390-64/stackguard-macros.h
+++ b/sysdeps/s390/s390-64/stackguard-macros.h
@@ -2,3 +2,17 @@
 
 #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;							\
+   })
diff --git a/sysdeps/sparc/sparc32/stackguard-macros.h b/sysdeps/sparc/sparc32/stackguard-macros.h
index c0b02b0..1eef0f1 100644
--- a/sysdeps/sparc/sparc32/stackguard-macros.h
+++ b/sysdeps/sparc/sparc32/stackguard-macros.h
@@ -2,3 +2,6 @@
 
 #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; })
diff --git a/sysdeps/sparc/sparc64/stackguard-macros.h b/sysdeps/sparc/sparc64/stackguard-macros.h
index 80f0635..cc0c12c 100644
--- a/sysdeps/sparc/sparc64/stackguard-macros.h
+++ b/sysdeps/sparc/sparc64/stackguard-macros.h
@@ -2,3 +2,6 @@
 
 #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; })
diff --git a/sysdeps/x86_64/stackguard-macros.h b/sysdeps/x86_64/stackguard-macros.h
index d7fedb3..1948800 100644
--- a/sysdeps/x86_64/stackguard-macros.h
+++ b/sysdeps/x86_64/stackguard-macros.h
@@ -4,3 +4,8 @@
   ({ uintptr_t x;						\
      asm ("mov %%fs:%c1, %0" : "=r" (x)				\
 	  : "i" (offsetof (tcbhead_t, stack_guard))); x; })
+
+#define POINTER_CHK_GUARD \
+  ({ uintptr_t x;						\
+     asm ("mov %%fs:%c1, %0" : "=r" (x)				\
+	  : "i" (offsetof (tcbhead_t, pointer_guard))); x; })

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=a243b1a0797180e142d525d1325a173c758c3714

commit a243b1a0797180e142d525d1325a173c758c3714
Author: Siddhesh Poyarekar <siddhesh@redhat.com>
Date:   Mon Sep 23 11:24:30 2013 +0530

    Check for integer overflow in cache size computation in strcoll
    
    strcoll is implemented using a cache for indices and weights of
    collation sequences in the strings so that subsequent passes do not
    have to search through collation data again.  For very large string
    inputs, the cache size computation could overflow.  In such a case,
    use the fallback function that does not cache indices and weights of
    collation sequences.
    
    Fixes CVE-2012-4412.

diff --git a/ChangeLog b/ChangeLog
index bf25e12..846b7b4 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,6 +1,12 @@
 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.
diff --git a/NEWS b/NEWS
index 5601a9a..9339139 100644
--- a/NEWS
+++ b/NEWS
@@ -12,6 +12,12 @@ Version 2.16.1
   6530, 14195, 14547, 14459, 14476, 14562, 14621, 14648, 14756, 14831, 15078,
   15755, 16072.
 
+* CVE-2012-4412 The strcoll implementation caches indices and rules for
+  large collation sequences to optimize multiple passes.  This cache
+  computation may overflow for large collation sequences and may cause a
+  stack or buffer overflow.  This is now fixed to use a slower algorithm
+  which does not use a cache if there is an integer overflow.
+
 * CVE-2012-4424 The strcoll implementation uses malloc to cache indices and
   rules for large collation sequences to optimize multiple passes and falls
   back to alloca if malloc fails, resulting in a possible stack overflow.
diff --git a/string/Makefile b/string/Makefile
index 1628b6a..a81c889 100644
--- a/string/Makefile
+++ b/string/Makefile
@@ -59,6 +59,8 @@ tests		:= tester inl-tester noinl-tester testcopy test-ffs	\
 		   bug-strstr1 bug-strchr1 tst-strtok_r
 
 
+xtests = tst-strcoll-overflow
+
 include ../Rules
 
 tester-ENV = LANGUAGE=C
diff --git a/string/strcoll_l.c b/string/strcoll_l.c
index 8469f97..92ab542 100644
--- a/string/strcoll_l.c
+++ b/string/strcoll_l.c
@@ -524,7 +524,15 @@ STRCOLL (const STRING_TYPE *s1, const STRING_TYPE *s2, __locale_t l)
   memset (&seq1, 0, sizeof (seq1));
   seq2 = seq1;
 
-  if (! __libc_use_alloca ((s1len + s2len) * (sizeof (int32_t) + 1)))
+  size_t size_max = SIZE_MAX / (sizeof (int32_t) + 1);
+
+  if (MIN (s1len, s2len) > size_max
+      || MAX (s1len, s2len) > size_max - MIN (s1len, 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.  */
+    }
+  else if (! __libc_use_alloca ((s1len + s2len) * (sizeof (int32_t) + 1)))
     {
       seq1.idxarr = (int32_t *) malloc ((s1len + s2len) * (sizeof (int32_t) + 1));
 
diff --git a/string/tst-strcoll-overflow.c b/string/tst-strcoll-overflow.c
new file mode 100644
index 0000000..bb665ac
--- /dev/null
+++ 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"

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=c1132021659d22753104762a074d6339ae6cbd01

commit c1132021659d22753104762a074d6339ae6cbd01
Author: Siddhesh Poyarekar <siddhesh@redhat.com>
Date:   Mon Sep 23 11:20:02 2013 +0530

    Fall back to non-cached sequence traversal and comparison on malloc fail
    
    strcoll currently falls back to alloca if malloc fails, resulting in a
    possible stack overflow.  This patch implements sequence traversal and
    comparison without caching indices and rules.
    
    Fixes CVE-2012-4424.

diff --git a/ChangeLog b/ChangeLog
index fa9e404..bf25e12 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2013-09-23  Siddhesh Poyarekar  <siddhesh@redhat.com>
+
+	[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.
diff --git a/NEWS b/NEWS
index 5aa982b..5601a9a 100644
--- a/NEWS
+++ b/NEWS
@@ -9,9 +9,15 @@ Version 2.16.1
 
 * The following bugs are resolved with this release:
 
-  6530, 14195, 14459, 14476, 14562, 14621, 14648, 14756, 14831, 15078.,
+  6530, 14195, 14547, 14459, 14476, 14562, 14621, 14648, 14756, 14831, 15078,
   15755, 16072.
 
+* CVE-2012-4424 The strcoll implementation uses malloc to cache indices and
+  rules for large collation sequences to optimize multiple passes and falls
+  back to alloca if malloc fails, resulting in a possible stack overflow.
+  The implementation now falls back to an uncached collation sequence lookup
+  if malloc fails.
+
 * CVE-2013-4458 Stack overflow in getaddrinfo with large number of results
   for AF_INET6 has been fixed (Bugzilla #16072).
 
diff --git a/string/strcoll_l.c b/string/strcoll_l.c
index ff8ed48..8469f97 100644
--- a/string/strcoll_l.c
+++ b/string/strcoll_l.c
@@ -45,7 +45,7 @@
 typedef struct
 {
   int len;			/* Length of the current sequence.  */
-  int val;			/* Position of the sequence relative to the
+  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.  */
@@ -55,6 +55,12 @@ typedef struct
   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
@@ -64,7 +70,7 @@ get_next_seq_cached (coll_seq *seq, int nrules, int pass,
 		     const unsigned char *rulesets,
 		     const USTRING_TYPE *weights)
 {
-  int val = seq->val = 0;
+  size_t val = seq->val = 0;
   int len = seq->len;
   size_t backw_stop = seq->backw_stop;
   size_t backw = seq->backw;
@@ -146,7 +152,7 @@ get_next_seq (coll_seq *seq, int nrules, const unsigned char *rulesets,
 	      const USTRING_TYPE *extra, const int32_t *indirect)
 {
 #include WEIGHT_H
-  int val = seq->val = 0;
+  size_t val = seq->val = 0;
   int len = seq->len;
   size_t backw_stop = seq->backw_stop;
   size_t backw = seq->backw;
@@ -162,7 +168,7 @@ get_next_seq (coll_seq *seq, int nrules, const unsigned char *rulesets,
       ++val;
       if (backw_stop != ~0ul)
 	{
-	  /* The is something pushed.  */
+	  /* There is something pushed.  */
 	  if (backw == backw_stop)
 	    {
 	      /* The last pushed character was handled.  Continue
@@ -227,15 +233,199 @@ get_next_seq (coll_seq *seq, int nrules, const unsigned char *rulesets,
   seq->us = us;
 }
 
-/* Compare two sequences.  */
+/* 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;
-  int val1 = seq1->val;
-  int val2 = seq2->val;
+  size_t val1 = seq1->val;
+  size_t val2 = seq2->val;
   int32_t *idx1arr = seq1->idxarr;
   int32_t *idx2arr = seq2->idxarr;
   int idx1now = seq1->idxnow;
@@ -245,7 +435,7 @@ do_compare (coll_seq *seq1, coll_seq *seq2, int position,
   /* Test for position if necessary.  */
   if (position && val1 != val2)
     {
-      result = val1 - val2;
+      result = val1 > val2 ? 1 : -1;
       goto out;
     }
 
@@ -334,57 +524,62 @@ STRCOLL (const STRING_TYPE *s1, const STRING_TYPE *s2, __locale_t l)
   memset (&seq1, 0, sizeof (seq1));
   seq2 = seq1;
 
-  /* 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;
-
   if (! __libc_use_alloca ((s1len + s2len) * (sizeof (int32_t) + 1)))
     {
       seq1.idxarr = (int32_t *) malloc ((s1len + s2len) * (sizeof (int32_t) + 1));
-      seq2.idxarr = &seq1.idxarr[s1len];
-      seq1.rulearr = (unsigned char *) &seq2.idxarr[s2len];
-      seq2.rulearr = &seq1.rulearr[s1len];
-
-      if (seq1.idxarr == NULL)
-	/* No memory.  Well, go with the stack then.
-
-	   XXX Once this implementation is stable we will handle this
-	   differently.  Instead of precomputing the indices we will
-	   do this in time.  This means, though, that this happens for
-	   every pass again.  */
-	goto try_stack;
-      use_malloc = true;
+
+      /* 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)
+	{
+	  seq2.idxarr = &seq1.idxarr[s1len];
+	  seq1.rulearr = (unsigned char *) &seq2.idxarr[s2len];
+	  seq2.rulearr = &seq1.rulearr[s1len];
+	  use_malloc = true;
+	}
     }
   else
     {
-    try_stack:
       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);
     }
 
-  seq1.rulearr[0] = 0;
+  int rule = 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;
 
+      /* 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;
+
       /* We assume that if a rule has defined `position' in one section
 	 this is true for all of them.  */
-      int position = rulesets[seq1.rulearr[0] * nrules + pass] & sort_position;
+      int position = rulesets[rule * nrules + pass] & sort_position;
 
       while (1)
 	{
-	  if (pass == 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);
@@ -411,10 +606,18 @@ STRCOLL (const STRING_TYPE *s1, const STRING_TYPE *s2, __locale_t l)
 	      goto free_and_return;
 	    }
 
-	  result = do_compare (&seq1, &seq2, position, weights);
+	  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.  */

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=2dc811b78adc97b5f5d951716df30053a24da1a1

commit 2dc811b78adc97b5f5d951716df30053a24da1a1
Author: Siddhesh Poyarekar <siddhesh@redhat.com>
Date:   Tue Aug 20 08:40:05 2013 +0530

    Simplify strcoll implementation
    
    Break up strcoll into simpler functions so that the logic is easier to
    follow and maintain.

diff --git a/ChangeLog b/ChangeLog
index f68d42e..fa9e404 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+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.
+
 2013-10-25  Siddhesh Poyarekar  <siddhesh@redhat.com>
 
 	[BZ #16072]
diff --git a/string/strcoll_l.c b/string/strcoll_l.c
index 4cee76a..ff8ed48 100644
--- a/string/strcoll_l.c
+++ b/string/strcoll_l.c
@@ -41,11 +41,244 @@
 
 #include "../locale/localeinfo.h"
 
+/* Track status while looking for sequences in a string.  */
+typedef struct
+{
+  int len;			/* Length of the current sequence.  */
+  int 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.  */
+} 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)
+{
+  int 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
+  int 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)
+	{
+	  /* The 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;
+}
+
+/* Compare two sequences.  */
+static int
+do_compare (coll_seq *seq1, coll_seq *seq2, int position,
+	    const USTRING_TYPE *weights)
+{
+  int seq1len = seq1->len;
+  int seq2len = seq2->len;
+  int val1 = seq1->val;
+  int 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;
+      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];
   uint_fast32_t nrules = current->values[_NL_ITEM_INDEX (_NL_COLLATE_NRULES)].word;
@@ -56,34 +289,6 @@ STRCOLL (s1, s2, l)
   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);
@@ -98,7 +303,6 @@ STRCOLL (s1, s2, l)
     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);
@@ -106,18 +310,13 @@ STRCOLL (s1, s2, l)
   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
@@ -127,411 +326,101 @@ STRCOLL (s1, s2, l)
 
      Please note that the localedef programs makes sure that `position'
      is not used at the first level.  */
+
+  coll_seq seq1, seq2;
+  bool use_malloc = false;
+  int result = 0;
+
+  memset (&seq1, 0, sizeof (seq1));
+  seq2 = seq1;
+
+  /* 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;
+
   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];
+      seq1.idxarr = (int32_t *) malloc ((s1len + s2len) * (sizeof (int32_t) + 1));
+      seq2.idxarr = &seq1.idxarr[s1len];
+      seq1.rulearr = (unsigned char *) &seq2.idxarr[s2len];
+      seq2.rulearr = &seq1.rulearr[s1len];
 
-      if (idx1arr == NULL)
+      if (seq1.idxarr == NULL)
 	/* No memory.  Well, go with the stack then.
 
 	   XXX Once this implementation is stable we will handle this
-	   differently.  Instead of precomputing the indeces we will
+	   differently.  Instead of precomputing the indices we will
 	   do this in time.  This means, though, that this happens for
 	   every pass again.  */
 	goto try_stack;
-      use_malloc = 1;
+      use_malloc = true;
     }
   else
     {
     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);
+      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);
     }
 
-  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)
-    {
-      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;
-	}
-
-      /* Test for position if necessary.  */
-      if (position && val1 != val2)
-	{
-	  result = val1 - val2;
-	  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];
+  seq1.rulearr[0] = 0;
 
-	  --seq1len;
-	  --seq2len;
-	}
-      while (seq1len > 0 && seq2len > 0);
-
-      if (position && seq1len != seq2len)
-	{
-	  result = seq1len - seq2len;
-	  goto free_and_return;
-	}
-    }
-
-  /* Now the remaining passes over the weights.  We now use the
-     indeces we found before.  */
-  for (pass = 1; pass < nrules; ++pass)
+  /* 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.backw_stop = ~0ul;
+      seq1.backw = ~0ul;
+      seq2.idxcnt = 0;
+      seq2.backw_stop = ~0ul;
+      seq2.backw = ~0ul;
+
       /* 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[seq1.rulearr[0] * 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 (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;
+	      result = seq1.len == 0 ? -1 : 1;
 	      goto free_and_return;
 	    }
 
-	  /* Test for position if necessary.  */
-	  if (position && val1 != val2)
-	    {
-	      result = val1 - val2;
-	      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;
-	    }
+	  result = do_compare (&seq1, &seq2, position, weights);
+	  if (result != 0)
+	    goto free_and_return;
 	}
     }
 
   /* Free the memory if needed.  */
  free_and_return:
   if (use_malloc)
-    free (idx1arr);
+    free (seq1.idxarr);
 
   return result;
 }

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=9b951f59aa3c2f2d58d398aab146951216f9ff8d

commit 9b951f59aa3c2f2d58d398aab146951216f9ff8d
Author: Siddhesh Poyarekar <siddhesh@redhat.com>
Date:   Fri Oct 25 10:22:12 2013 +0530

    Fix stack overflow due to large AF_INET6 requests
    
    Resolves #16072 (CVE-2013-4458).
    
    This patch fixes another stack overflow in getaddrinfo when it is
    called with AF_INET6.  The AF_UNSPEC case was fixed as CVE-2013-1914,
    but the AF_INET6 case went undetected back then.

diff --git a/ChangeLog b/ChangeLog
index 98203d0..f68d42e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2013-10-25  Siddhesh Poyarekar  <siddhesh@redhat.com>
+
+	[BZ #16072]
+	* sysdeps/posix/getaddrinfo.c (gethosts): Allocate tmpbuf on
+	heap for large requests.
+
 2013-02-12  Andreas Schwab  <schwab@suse.de>
 
 	[BZ #15078]
diff --git a/NEWS b/NEWS
index 5d8a855..5aa982b 100644
--- a/NEWS
+++ b/NEWS
@@ -10,7 +10,10 @@ Version 2.16.1
 * The following bugs are resolved with this release:
 
   6530, 14195, 14459, 14476, 14562, 14621, 14648, 14756, 14831, 15078.,
-  15755.
+  15755, 16072.
+
+* CVE-2013-4458 Stack overflow in getaddrinfo with large number of results
+  for AF_INET6 has been fixed (Bugzilla #16072).
 
 * CVE-2013-2207 Incorrectly granting access to another user's pseudo-terminal
   has been fixed by disabling the use of pt_chown (Bugzilla #15755).
diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
index 2eca2ae..0146eb9 100644
--- a/sysdeps/posix/getaddrinfo.c
+++ b/sysdeps/posix/getaddrinfo.c
@@ -196,7 +196,22 @@ gaih_inet_serv (const char *servicename, const struct gaih_typeproto *tp,
 				&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 @@ gaih_inet_serv (const char *servicename, const struct gaih_typeproto *tp,
 	{								      \
 	  __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;						      \

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=302c61e2d3536a6ff99d518499771afd6a951b0c

commit 302c61e2d3536a6ff99d518499771afd6a951b0c
Author: Andreas Schwab <schwab@suse.de>
Date:   Tue Jan 29 14:45:15 2013 +0100

    Fix buffer overrun in regexp matcher

diff --git a/ChangeLog b/ChangeLog
index 26e3868..98203d0 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+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.
+
 2013-07-21  Siddhesh Poyarekar  <siddhesh@redhat.com>
 	    Andreas Schwab  <schwab@suse.de>
 	    Roland McGrath  <roland@hack.frob.com>
diff --git a/NEWS b/NEWS
index bbcb024..5d8a855 100644
--- a/NEWS
+++ b/NEWS
@@ -9,7 +9,8 @@ Version 2.16.1
 
 * The following bugs are resolved with this release:
 
-  6530, 14195, 14459, 14476, 14562, 14621, 14648, 14756, 14831, 15755.
+  6530, 14195, 14459, 14476, 14562, 14621, 14648, 14756, 14831, 15078.,
+  15755.
 
 * CVE-2013-2207 Incorrectly granting access to another user's pseudo-terminal
   has been fixed by disabling the use of pt_chown (Bugzilla #15755).
diff --git a/posix/Makefile b/posix/Makefile
index 922f9c0..6102be7 100644
--- a/posix/Makefile
+++ b/posix/Makefile
@@ -86,7 +86,7 @@ tests		:= tstgetopt testfnm runtests runptests	     \
 		   tst-rfc3484-3 \
 		   tst-getaddrinfo3 tst-fnmatch2 tst-cpucount tst-cpuset \
 		   bug-getopt1 bug-getopt2 bug-getopt3 bug-getopt4 \
-		   bug-getopt5 tst-getopt_long1
+		   bug-getopt5 tst-getopt_long1 bug-regex34
 xtests		:= bug-ga2
 ifeq (yes,$(build-shared))
 test-srcs	:= globtest
@@ -194,6 +194,7 @@ bug-regex26-ENV = LOCPATH=$(common-objpfx)localedata
 bug-regex30-ENV = LOCPATH=$(common-objpfx)localedata
 bug-regex32-ENV = LOCPATH=$(common-objpfx)localedata
 bug-regex33-ENV = LOCPATH=$(common-objpfx)localedata
+bug-regex34-ENV = LOCPATH=$(common-objpfx)localedata
 tst-rxspencer-ARGS = --utf8 rxspencer/tests
 tst-rxspencer-ENV = LOCPATH=$(common-objpfx)localedata
 tst-pcre-ARGS = PCRE.tests
diff --git a/posix/bug-regex34.c b/posix/bug-regex34.c
new file mode 100644
index 0000000..bb3b613
--- /dev/null
+++ 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"
diff --git a/posix/regexec.c b/posix/regexec.c
index ec4ae13..5b31f5b 100644
--- a/posix/regexec.c
+++ b/posix/regexec.c
@@ -197,7 +197,7 @@ static int group_nodes_into_DFAstates (const re_dfa_t *dfa,
 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.  */
@@ -1160,7 +1160,7 @@ check_matching (re_match_context_t *mctx, int fl_longest_match,
 	  || (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);
@@ -1738,7 +1738,7 @@ clean_state_log_if_needed (re_match_context_t *mctx, int next_state_log_idx)
 	  && 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;
     }
@@ -2792,7 +2792,7 @@ get_subexp (re_match_context_t *mctx, int bkref_node, int bkref_str_idx)
 		  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;
 
@@ -4102,7 +4102,7 @@ check_node_accept (const re_match_context_t *mctx, const re_token_t *node,
 
 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;
@@ -4111,8 +4111,10 @@ extend_buffers (re_match_context_t *mctx)
   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;
 

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=b7e0492e183efc24e5658c860ca5711e00524dd7

commit b7e0492e183efc24e5658c860ca5711e00524dd7
Author: Carlos O'Donell <carlos@redhat.com>
Date:   Fri Jul 19 02:42:03 2013 -0400

    CVE-2013-2207, BZ #15755: Disable pt_chown.
    
    The helper binary pt_chown tricked into granting access to another
    user's pseudo-terminal.
    
    Pre-conditions for the attack:
    
     * Attacker with local user account
     * Kernel with FUSE support
     * "user_allow_other" in /etc/fuse.conf
     * Victim with allocated slave in /dev/pts
    
    Using the setuid installed pt_chown and a weak check on whether a file
    descriptor is a tty, an attacker could fake a pty check using FUSE and
    trick pt_chown to grant ownership of a pty descriptor that the current
    user does not own.  It cannot access /dev/pts/ptmx however.
    
    In most modern distributions pt_chown is not needed because devpts
    is enabled by default. The fix for this CVE is to disable building
    and using pt_chown by default. We still provide a configure option
    to enable hte use of pt_chown but distributions do so at their own
    risk.
    
    Cherry-pick of e4608715e6e1dd2adc91982fd151d5ba4f761d69.

diff --git a/ChangeLog b/ChangeLog
index ca203b4..26e3868 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,24 @@
+2013-07-21  Siddhesh Poyarekar  <siddhesh@redhat.com>
+	    Andreas Schwab  <schwab@suse.de>
+	    Roland McGrath  <roland@hack.frob.com>
+	    Joseph Myers  <joseph@codesourcery.com>
+	    Carlos O'Donell  <carlos@redhat.com>
+
+	[BZ #15755]
+	* config.h.in: Define HAVE_PT_CHOWN.
+	* config.make.in (build-pt-chown): New variable.
+	* configure.in (--enable-pt_chown): New configure option.
+	* configure: Regenerate.
+	* login/Makefile: Include Makeconfig.  Build pt_chown only if
+	build-pt-chown is enabled.
+	* sysdeps/unix/grantpt.c (grantpt) [HAVE_PT_CHOWN]: Spawn
+	pt_chown to fix pty ownership.
+	* sysdeps/unix/sysv/linux/grantpt.c [HAVE_PT_CHOWN]: Define
+	CLOSE_ALL_FDS.
+	* manual/install.texi (Configuring and compiling): Mention
+	--enable-pt_chown. Add @findex for grantpt.
+	* INSTALL: Regenerate.
+
 2012-11-28  Jeff Law <law@redhat.com>
 	    Martin Osvald <mosvald@redhat.com>
 
diff --git a/INSTALL b/INSTALL
index d4fabe9..2f83f2a 100644
--- a/INSTALL
+++ b/INSTALL
@@ -128,6 +128,18 @@ will be used, and CFLAGS sets optimization options for the compiler.
      this can be prevented though there generally is no reason since it
      creates compatibility problems.
 
+`--enable-pt_chown'
+     The file `pt_chown' is a helper binary for `grantpt' (*note
+     Pseudo-Terminals: Allocation.) that is installed setuid root to
+     fix up pseudo-terminal ownership.  It is not built by default
+     because systems using the Linux kernel are commonly built with the
+     `devpts' filesystem enabled and mounted at `/dev/pts', which
+     manages pseudo-terminal ownership automatically.  By using
+     `--enable-pt_chown', you may build `pt_chown' and install it
+     setuid and owned by `root'.  The use of `pt_chown' introduces
+     additional security risks to the system and you should enable it
+     only if you understand and accept those risks.
+
 `--build=BUILD-SYSTEM'
 `--host=HOST-SYSTEM'
      These options are for cross-compiling.  If you specify both
diff --git a/NEWS b/NEWS
index cab722b..bbcb024 100644
--- a/NEWS
+++ b/NEWS
@@ -9,7 +9,14 @@ Version 2.16.1
 
 * The following bugs are resolved with this release:
 
-  6530, 14195, 14459, 14476, 14562, 14621, 14648, 14756, 14831
+  6530, 14195, 14459, 14476, 14562, 14621, 14648, 14756, 14831, 15755.
+
+* CVE-2013-2207 Incorrectly granting access to another user's pseudo-terminal
+  has been fixed by disabling the use of pt_chown (Bugzilla #15755).
+  Distributions can re-enable building and using pt_chown via the new configure
+  option `--enable-pt_chown'.  Enabling the use of pt_chown carries with it
+  considerable security risks and should only be used if the distribution
+  understands and accepts the risks.
 
 * CVE-2011-4609 svc_run() produces high cpu usage when accept fails with
   EMFILE has been fixed (Bugzilla #14889).
diff --git a/config.h.in b/config.h.in
index dd184b0..8a78e84 100644
--- a/config.h.in
+++ b/config.h.in
@@ -228,4 +228,7 @@
 /* The ARM hard-float ABI is being used.  */
 #undef HAVE_ARM_PCS_VFP
 
+/* The pt_chown binary is being built and used by grantpt.  */
+#undef HAVE_PT_CHOWN
+
 #endif
diff --git a/config.make.in b/config.make.in
index 65410ab..ce5a60e 100644
--- a/config.make.in
+++ b/config.make.in
@@ -99,6 +99,7 @@ sysdeps-add-ons = @sysdeps_add_ons@
 cross-compiling = @cross_compiling@
 force-install = @force_install@
 link-obsolete-rpc = @link_obsolete_rpc@
+build-pt-chown = @build_pt_chown@
 
 # Build tools.
 CC = @CC@
diff --git a/configure b/configure
index aa7869f..d25e2e6 100755
--- a/configure
+++ b/configure
@@ -654,6 +654,7 @@ multi_arch
 base_machine
 add_on_subdirs
 add_ons
+build_pt_chown
 link_obsolete_rpc
 libc_cv_nss_crypt
 all_warnings
@@ -749,6 +750,7 @@ enable_multi_arch
 enable_nss_crypt
 enable_obsolete_rpc
 enable_systemtap
+enable_pt_chown
 with_cpu
 '
       ac_precious_vars='build_alias
@@ -1407,6 +1409,7 @@ Optional Features:
   --enable-obsolete-rpc   build and install the obsolete RPC code for
                           link-time usage
   --enable-systemtap      enable systemtap static probe points [default=no]
+  --enable-pt_chown       Enable building and installing pt_chown
 
 Optional Packages:
   --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
@@ -3751,6 +3754,21 @@ See \`config.log' for more details" "$LINENO" 5; }
   fi
 fi
 
+
+
+# Check whether --enable-pt_chown was given.
+if test "${enable_pt_chown+set}" = set; then :
+  enableval=$enable_pt_chown; build_pt_chown=$enableval
+else
+  build_pt_chown=no
+fi
+
+
+if test $build_pt_chown = yes; then
+  $as_echo "#define HAVE_PT_CHOWN 1" >>confdefs.h
+
+fi
+
 # The way shlib-versions is used to generate soversions.mk uses a
 # fairly simplistic model for name recognition that can't distinguish
 # i486-pc-linux-gnu fully from i486-pc-gnu.  So we mutate a $host_os
diff --git a/configure.in b/configure.in
index 5028e64..7bac2f7 100644
--- a/configure.in
+++ b/configure.in
@@ -292,6 +292,16 @@ void foo (int i, void *p)
   fi
 fi
 
+AC_ARG_ENABLE([pt_chown],
+	      [AS_HELP_STRING([--enable-pt_chown],
+	       [Enable building and installing pt_chown])],
+	      [build_pt_chown=$enableval],
+	      [build_pt_chown=no])
+AC_SUBST(build_pt_chown)
+if test $build_pt_chown = yes; then
+  AC_DEFINE(HAVE_PT_CHOWN)
+fi
+
 # The way shlib-versions is used to generate soversions.mk uses a
 # fairly simplistic model for name recognition that can't distinguish
 # i486-pc-linux-gnu fully from i486-pc-gnu.  So we mutate a $host_os
diff --git a/login/Makefile b/login/Makefile
index 9b6d2bb..4ec17db 100644
--- a/login/Makefile
+++ b/login/Makefile
@@ -29,9 +29,15 @@ routines := getutent getutent_r getutid getutline getutid_r getutline_r \
 
 CFLAGS-grantpt.c = -DLIBEXECDIR='"$(libexecdir)"'
 
-others = utmpdump pt_chown
+others = utmpdump
+
+include ../Makeconfig
+
+ifeq (yes,$(build-pt-chown))
+others += pt_chown
 others-pie = pt_chown
 install-others-programs = $(inst_libexecdir)/pt_chown
+endif
 
 subdir-dirs = programs
 vpath %.c programs
diff --git a/manual/install.texi b/manual/install.texi
index 5aca058..66a34e0 100644
--- a/manual/install.texi
+++ b/manual/install.texi
@@ -154,6 +154,20 @@ if the used tools support it.  By using @samp{--without-tls} this can be
 prevented though there generally is no reason since it creates
 compatibility problems.
 
+@pindex pt_chown
+@findex grantpt
+@item --enable-pt_chown
+The file @file{pt_chown} is a helper binary for @code{grantpt}
+(@pxref{Allocation, Pseudo-Terminals}) that is installed setuid root to
+fix up pseudo-terminal ownership.  It is not built by default because
+systems using the Linux kernel are commonly built with the @code{devpts}
+filesystem enabled and mounted at @file{/dev/pts}, which manages
+pseudo-terminal ownership automatically.  By using
+@samp{--enable-pt_chown}, you may build @file{pt_chown} and install it
+setuid and owned by @code{root}.  The use of @file{pt_chown} introduces
+additional security risks to the system and you should enable it only if
+you understand and accept those risks.
+
 @item --build=@var{build-system}
 @itemx --host=@var{host-system}
 These options are for cross-compiling.  If you specify both options and
diff --git a/sysdeps/unix/grantpt.c b/sysdeps/unix/grantpt.c
index 06c35e7..66ff3d9 100644
--- a/sysdeps/unix/grantpt.c
+++ b/sysdeps/unix/grantpt.c
@@ -173,9 +173,10 @@ grantpt (int fd)
   retval = 0;
   goto cleanup;
 
-  /* We have to use the helper program.  */
+  /* We have to use the helper program if it is available.  */
  helper:;
 
+#ifdef HAVE_PT_CHOWN
   pid_t pid = __fork ();
   if (pid == -1)
     goto cleanup;
@@ -190,9 +191,9 @@ grantpt (int fd)
 	if (__dup2 (fd, PTY_FILENO) < 0)
 	  _exit (FAIL_EBADF);
 
-#ifdef CLOSE_ALL_FDS
+# ifdef CLOSE_ALL_FDS
       CLOSE_ALL_FDS ();
-#endif
+# endif
 
       execle (_PATH_PT_CHOWN, basename (_PATH_PT_CHOWN), NULL, NULL);
       _exit (FAIL_EXEC);
@@ -231,6 +232,7 @@ grantpt (int fd)
 	    assert(! "getpt: internal error: invalid exit code from pt_chown");
 	  }
     }
+#endif
 
  cleanup:
   if (buf != _buf)
diff --git a/sysdeps/unix/sysv/linux/grantpt.c b/sysdeps/unix/sysv/linux/grantpt.c
index 0a3cd47..8cebde3 100644
--- a/sysdeps/unix/sysv/linux/grantpt.c
+++ b/sysdeps/unix/sysv/linux/grantpt.c
@@ -11,7 +11,7 @@
 
 #include "pty-private.h"
 
-
+#if HAVE_PT_CHOWN
 /* Close all file descriptors except the one specified.  */
 static void
 close_all_fds (void)
@@ -38,6 +38,7 @@ close_all_fds (void)
       __dup2 (STDOUT_FILENO, STDERR_FILENO);
     }
 }
-#define CLOSE_ALL_FDS() close_all_fds()
+# define CLOSE_ALL_FDS() close_all_fds()
+#endif
 
 #include <sysdeps/unix/grantpt.c>

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=02a002fe9c0b65532643a88b01253e95ba8ba8c6

commit 02a002fe9c0b65532643a88b01253e95ba8ba8c6
Author: Jeff Law <law@redhat.com>
Date:   Wed Nov 28 14:12:28 2012 -0700

           [BZ #14889]
            * sunrpc/rpc/svc.h (__svc_accept_failed): New prototype.
            * sunrpc/svc.c: Include time.h.
            (__svc_accept_failed): New function.
            * sunrpc/svc_tcp.c (rendezvous_request): If the accept fails for
            any reason other than EINTR, call __svc_accept_failed.
            * sunrpc/svc_udp.c (svcudp_recv): Similarly.
            * sunrpc/svc_unix.c (rendezvous_request): Similarly.
    
    Cherry-pick of 14bc93a967e62abf8cf2704725b6f76619399f83

diff --git a/ChangeLog b/ChangeLog
index 96e1d81..ca203b4 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,15 @@
+2012-11-28  Jeff Law <law@redhat.com>
+	    Martin Osvald <mosvald@redhat.com>
+
+	[BZ #14889]
+	* sunrpc/rpc/svc.h (__svc_accept_failed): New prototype.
+	* sunrpc/svc.c: Include time.h.
+	(__svc_accept_failed): New function.
+	* sunrpc/svc_tcp.c (rendezvous_request): If the accept fails for
+	any reason other than EINTR, call __svc_accept_failed.
+	* sunrpc/svc_udp.c (svcudp_recv): Similarly.
+	* sunrpc/svc_unix.c (rendezvous_request): Similarly.
+
 2012-11-28  Andreas Schwab  <schwab@suse.de>
 
 	* scripts/abilist.awk: Also handle indirect functions in .opd
diff --git a/NEWS b/NEWS
index d898de6..cab722b 100644
--- a/NEWS
+++ b/NEWS
@@ -11,6 +11,9 @@ Version 2.16.1
 
   6530, 14195, 14459, 14476, 14562, 14621, 14648, 14756, 14831
 
+* CVE-2011-4609 svc_run() produces high cpu usage when accept fails with
+  EMFILE has been fixed (Bugzilla #14889).
+
 Version 2.16
 
 * The following bugs are resolved with this release:
diff --git a/sunrpc/rpc/svc.h b/sunrpc/rpc/svc.h
index 54d1ac1..58a5f7d 100644
--- a/sunrpc/rpc/svc.h
+++ b/sunrpc/rpc/svc.h
@@ -1,6 +1,23 @@
 /*
  * svc.h, Server-side remote procedure call interface.
  *
+ * Copyright (C) 2012 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/>.
+ *
  * Copyright (c) 2010, Oracle America, Inc.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -316,4 +333,5 @@ extern SVCXPRT *svcunix_create (int __sock, u_int __sendsize, u_int __recvsize,
 
 __END_DECLS
 
+extern void __svc_accept_failed (void) attribute_hidden;
 #endif /* rpc/svc.h */
diff --git a/sunrpc/svc.c b/sunrpc/svc.c
index 103770a..736d4a9 100644
--- a/sunrpc/svc.c
+++ b/sunrpc/svc.c
@@ -4,6 +4,23 @@
  * There are two sets of procedures here.  The xprt routines are
  * for handling transport handles.  The svc routines handle the
  * list of service routines.
+ *  Copyright (C) 2002-2012 Free Software Foundation, Inc.
+ *  This file is part of the GNU C Library.
+ *  Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+ *
+ *  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/>.
  *
  * Copyright (c) 2010, Oracle America, Inc.
  *
@@ -41,6 +58,7 @@
 #include <rpc/svc.h>
 #include <rpc/pmap_clnt.h>
 #include <sys/poll.h>
+#include <time.h>
 
 #ifdef _RPC_THREAD_SAFE_
 #define xports RPC_THREAD_VARIABLE(svc_xports_s)
@@ -544,6 +562,21 @@ svc_getreq_common (const int fd)
 }
 libc_hidden_nolink_sunrpc (svc_getreq_common, GLIBC_2_2)
 
+/* If there are no file descriptors available, then accept will fail.
+   We want to delay here so the connection request can be dequeued;
+   otherwise we can bounce between polling and accepting, never giving the
+   request a chance to dequeue and eating an enormous amount of cpu time
+   in svc_run if we're polling on many file descriptors.  */
+void
+__svc_accept_failed (void)
+{
+  if (errno == EMFILE)
+    {
+      struct timespec ts = { .tv_sec = 0, .tv_nsec = 50000000 };
+      __nanosleep (&ts, NULL);
+    }
+}
+
 #ifdef _RPC_THREAD_SAFE_
 
 void
diff --git a/sunrpc/svc_tcp.c b/sunrpc/svc_tcp.c
index eb61549..1fdb0ad 100644
--- a/sunrpc/svc_tcp.c
+++ b/sunrpc/svc_tcp.c
@@ -1,6 +1,23 @@
 /*
  * svc_tcp.c, Server side for TCP/IP based RPC.
  *
+ * Copyright (C) 2012 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/>.
+ *
  * Copyright (c) 2010, Oracle America, Inc.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -247,6 +264,7 @@ again:
     {
       if (errno == EINTR)
 	goto again;
+      __svc_accept_failed ();
       return FALSE;
     }
   /*
diff --git a/sunrpc/svc_udp.c b/sunrpc/svc_udp.c
index 6c4d75a..3324e2a 100644
--- a/sunrpc/svc_udp.c
+++ b/sunrpc/svc_udp.c
@@ -3,6 +3,23 @@
  * Server side for UDP/IP based RPC.  (Does some caching in the hopes of
  * achieving execute-at-most-once semantics.)
  *
+ * Copyright (C) 2012 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/>.
+ *
  * Copyright (c) 2010, Oracle America, Inc.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -277,8 +294,12 @@ again:
 		       (int) su->su_iosz, 0,
 		       (struct sockaddr *) &(xprt->xp_raddr), &len);
   xprt->xp_addrlen = len;
-  if (rlen == -1 && errno == EINTR)
-    goto again;
+  if (rlen == -1)
+    {
+      if (errno == EINTR)
+	goto again;
+      __svc_accept_failed ();
+    }
   if (rlen < 16)		/* < 4 32-bit ints? */
     return FALSE;
   xdrs->x_op = XDR_DECODE;
diff --git a/sunrpc/svc_unix.c b/sunrpc/svc_unix.c
index 94507b2..5c3184a 100644
--- a/sunrpc/svc_unix.c
+++ b/sunrpc/svc_unix.c
@@ -1,6 +1,23 @@
 /*
  * svc_unix.c, Server side for TCP/IP based RPC.
  *
+ * Copyright (C) 2012 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/>.
+ *
  * Copyright (c) 2010, Oracle America, Inc.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -244,6 +261,7 @@ again:
     {
       if (errno == EINTR)
 	goto again;
+      __svc_accept_failed ();
       return FALSE;
     }
   /*

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=3b498440aac70e994f32f45a31102964313af690

commit 3b498440aac70e994f32f45a31102964313af690
Author: Andreas Schwab <schwab@suse.de>
Date:   Wed Nov 28 10:24:06 2012 +0100

    Properly handle indirect functions in ABI check on powerpc64

diff --git a/ChangeLog b/ChangeLog
index 06993a5..96e1d81 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2012-11-28  Andreas Schwab  <schwab@suse.de>
+
+	* scripts/abilist.awk: Also handle indirect functions in .opd
+	section.
+
 2013-04-26  Adhemerval Zanella  <azanella@linux.vnet.ibm.com>
 
 	* sysdeps/powerpc/power5/fpu/s_modf.c: Moved to ...
diff --git a/scripts/abilist.awk b/scripts/abilist.awk
index 1c1d41d..6d58f66 100644
--- a/scripts/abilist.awk
+++ b/scripts/abilist.awk
@@ -81,7 +81,7 @@ $2 == "g" || $2 == "w" && (NF == 7 || NF == 8) {
     type = "F";
     size = "";
   }
-  else if (type == "iD" && $4 == ".text") {
+  else if (type == "iD" && ($4 == ".text" || $4 == ".opd")) {
     # Indirect functions.
     type = "F";
     size = "";

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=8282b7f2aa6380e8a91515f748d4693d8151fc4f

commit 8282b7f2aa6380e8a91515f748d4693d8151fc4f
Author: Adhemerval Zanella <azanella@linux.vnet.ibm.com>
Date:   Fri Apr 26 13:00:56 2013 -0500

    PowerPC: modf optimization fix
    
    This patch fix the 3c0265394d9ffedff2b0de508602dc52e077ce5c commits
    by correctly setting minimum architecture for modf PPC optimization
    to power5+ instead of power5 (since only on power5+ round/ceil will
    be inline to inline assembly).

diff --git a/ChangeLog b/ChangeLog
index 7882fd8..06993a5 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2013-04-26  Adhemerval Zanella  <azanella@linux.vnet.ibm.com>
+
+	* sysdeps/powerpc/power5/fpu/s_modf.c: Moved to ...
+	* sysdeps/powerpc/power5+/fpu/s_modf.c: ... this.
+	* sysdeps/powerpc/power5/fpu/s_modff.c: Moved to ...
+	* sysdeps/powerpc/power5+/fpu/s_modff.c: ... this.
+	* sysdeps/powerpc/powerpc32/power5+/Implies: Add powerpc/power5+ and
+	powerpc/power5+/fpu folders.
+	* sysdeps/powerpc/powerpc64/power5+/Implies: Likewise.
+
 2013-04-23  Adhemerval Zanella  <azanella@linux.vnet.ibm.com>
 
 	* sysdeps/powerpc/power5/fpu/s_modf.c: New file: modf optimization for
diff --git a/sysdeps/powerpc/power5/fpu/s_modf.c b/sysdeps/powerpc/power5+/fpu/s_modf.c
similarity index 100%
rename from sysdeps/powerpc/power5/fpu/s_modf.c
rename to sysdeps/powerpc/power5+/fpu/s_modf.c
diff --git a/sysdeps/powerpc/power5/fpu/s_modff.c b/sysdeps/powerpc/power5+/fpu/s_modff.c
similarity index 100%
rename from sysdeps/powerpc/power5/fpu/s_modff.c
rename to sysdeps/powerpc/power5+/fpu/s_modff.c
diff --git a/sysdeps/powerpc/powerpc32/power5+/Implies b/sysdeps/powerpc/powerpc32/power5+/Implies
index a51d2fd..02d222d 100644
--- a/sysdeps/powerpc/powerpc32/power5+/Implies
+++ b/sysdeps/powerpc/powerpc32/power5+/Implies
@@ -1,2 +1,4 @@
+powerpc/power5+/fpu
+powerpc/power5+
 powerpc/powerpc32/power5/fpu
 powerpc/powerpc32/power5
diff --git a/sysdeps/powerpc/powerpc64/power5+/Implies b/sysdeps/powerpc/powerpc64/power5+/Implies
index a01a13a..565bc94 100644
--- a/sysdeps/powerpc/powerpc64/power5+/Implies
+++ b/sysdeps/powerpc/powerpc64/power5+/Implies
@@ -1,2 +1,4 @@
+powerpc/power5+/fpu
+powerpc/power5+
 powerpc/powerpc64/power5/fpu
 powerpc/powerpc64/power5

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=17e599d2613c2a2e4cb6d5c3f9d5f626879aa63f

commit 17e599d2613c2a2e4cb6d5c3f9d5f626879aa63f
Author: Adhemerval Zanella <azanella@linux.vnet.ibm.com>
Date:   Mon Mar 25 16:10:06 2013 -0500

    PowerPC: modf optimization
    
    This patch implements modf/modff optimization for POWER by focus
    on FP operations instead of relying in integer ones.

diff --git a/ChangeLog b/ChangeLog
index 197da7f..7882fd8 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,16 @@
+2013-04-23  Adhemerval Zanella  <azanella@linux.vnet.ibm.com>
+
+	* sysdeps/powerpc/power5/fpu/s_modf.c: New file: modf optimization for
+	POWER.
+	* sysdeps/powerpc/power5/fpu/s_modff.c: New file: modff optimization
+	for POWER.
+	* sysdeps/powerpc/powerpc64/power5/Implies: Add powerpc/power5 and
+	powerpc/power5/fpu folders.
+	* sysdeps/powerpc/powerpc32/power5/Implies: Likewise.
+	* benchtests/Makefile: Add modf testcase.
+	* benchtests/bench-modf.c: New file: Benchmark test for mo
+
+
 2013-01-09  Anton Blanchard  <anton@samba.org>
 
 	* sysdeps/unix/sysv/linux/powerpc/sched_getcpu.c: New file.
diff --git a/sysdeps/powerpc/power5/fpu/s_modf.c b/sysdeps/powerpc/power5/fpu/s_modf.c
new file mode 100644
index 0000000..b45bf66
--- /dev/null
+++ b/sysdeps/powerpc/power5/fpu/s_modf.c
@@ -0,0 +1,58 @@
+/* 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 Library General Public License as
+   published by the Free Software Foundation; either version 2 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#include <math.h>
+#include <math_private.h>
+#include <math_ldbl_opt.h>
+
+double
+__modf (double x, double *iptr)
+{
+  if (__builtin_isinf (x))
+    {
+      *iptr = x;
+      return __copysign (0.0, x);
+    }
+  else if (__builtin_isnan (x))
+    {
+      *iptr = NAN;
+      return NAN;
+    }
+
+  if (x >= 0.0)
+    {
+      *iptr = __floor (x);
+      return (x - *iptr);
+    }
+  else
+    {
+      *iptr = __ceil (x);
+      return (x - *iptr);
+    }
+}
+weak_alias (__modf, modf)
+#ifdef NO_LONG_DOUBLE
+strong_alias (__modf, __modfl)
+weak_alias (__modf, modfl)
+#endif
+#ifdef IS_IN_libm
+# if LONG_DOUBLE_COMPAT(libm, GLIBC_2_0)
+compat_symbol (libm, __modf, modfl, GLIBC_2_0);
+# endif
+#elif LONG_DOUBLE_COMPAT(libc, GLIBC_2_0)
+compat_symbol (libc, __modf, modfl, GLIBC_2_0);
+#endif
diff --git a/sysdeps/powerpc/power5/fpu/s_modff.c b/sysdeps/powerpc/power5/fpu/s_modff.c
new file mode 100644
index 0000000..55759cd
--- /dev/null
+++ b/sysdeps/powerpc/power5/fpu/s_modff.c
@@ -0,0 +1,46 @@
+/* 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 Library General Public License as
+   published by the Free Software Foundation; either version 2 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#include <math.h>
+#include <math_private.h>
+
+float
+__modff (float x, float *iptr)
+{
+  if (__builtin_isinff (x))
+    {
+      *iptr = x;
+      return __copysignf (0.0, x);
+    }
+  else if (__builtin_isnanf (x))
+    {
+      *iptr = NAN;
+      return NAN;
+    }
+
+  if (x >= 0.0)
+    {
+      *iptr = __floorf (x);
+      return (x - *iptr);
+    }
+  else
+    {
+      *iptr = __ceilf (x);
+      return (x - *iptr);
+    }
+}
+weak_alias (__modff, modff)
diff --git a/sysdeps/powerpc/powerpc32/power5/Implies b/sysdeps/powerpc/powerpc32/power5/Implies
index 17139bf..17949d4 100644
--- a/sysdeps/powerpc/powerpc32/power5/Implies
+++ b/sysdeps/powerpc/powerpc32/power5/Implies
@@ -1,2 +1,4 @@
+powerpc/power5/fpu
+powerpc/power5
 powerpc/powerpc32/power4/fpu
 powerpc/powerpc32/power4
diff --git a/sysdeps/powerpc/powerpc64/power5/Implies b/sysdeps/powerpc/powerpc64/power5/Implies
index bedb20b..b36831e 100644
--- a/sysdeps/powerpc/powerpc64/power5/Implies
+++ b/sysdeps/powerpc/powerpc64/power5/Implies
@@ -1,2 +1,4 @@
+powerpc/power5/fpu
+powerpc/power5
 powerpc/powerpc64/power4/fpu
 powerpc/powerpc64/power4

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=60dc6d12c5c61b05013cb15f63349dd3d343f26d

commit 60dc6d12c5c61b05013cb15f63349dd3d343f26d
Author: Adhemerval Zanella <azanella@linux.vnet.ibm.com>
Date:   Wed Mar 13 10:46:08 2013 -0300

    PowerPC: Change sched_getcpu to use vDSO getcpu instead of syscall.
    
    Backport of d5e0b9bd6e296f3ec5263fa296d39f3fed9b8fa2.

diff --git a/ChangeLog b/ChangeLog
index ca3e120..197da7f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2013-01-09  Anton Blanchard  <anton@samba.org>
+
+	* sysdeps/unix/sysv/linux/powerpc/sched_getcpu.c: New file.
+	* sysdeps/unix/sysv/linux/powerpc/Versions: Add __vdso_getcpu.
+	* sysdeps/unix/sysv/linux/powerpc/bits/libc-vdso.h: Likewise.
+	* sysdeps/unix/sysv/linux/powerpc/init-first.c: Likewise.
+
 2013-03-04  Adhemerval Zanella  <azanella@linux.vnet.ibm.com>
 
 	* sysdeps/unix/sysv/linux/powerpc/bits/libc-vdso.h: Add macro to
diff --git a/sysdeps/unix/sysv/linux/powerpc/Versions b/sysdeps/unix/sysv/linux/powerpc/Versions
index 1ef53b9..396a423 100644
--- a/sysdeps/unix/sysv/linux/powerpc/Versions
+++ b/sysdeps/unix/sysv/linux/powerpc/Versions
@@ -3,5 +3,6 @@ libc {
     __vdso_get_tbfreq;
     __vdso_clock_gettime;
     __vdso_clock_getres;
+    __vdso_getcpu;
   }
 }
diff --git a/sysdeps/unix/sysv/linux/powerpc/bits/libc-vdso.h b/sysdeps/unix/sysv/linux/powerpc/bits/libc-vdso.h
index 9797943..820079f 100644
--- a/sysdeps/unix/sysv/linux/powerpc/bits/libc-vdso.h
+++ b/sysdeps/unix/sysv/linux/powerpc/bits/libc-vdso.h
@@ -30,6 +30,8 @@ extern void *__vdso_clock_getres;
 
 extern void *__vdso_get_tbfreq;
 
+extern void *__vdso_getcpu;
+
 /* Macro to return vdso_xxx value on IFUNC implementations.
    On PPC64 the returned value is actually an OPD entry.  */
 #if defined(__PPC64__) || defined(__powerpc64__)
diff --git a/sysdeps/unix/sysv/linux/powerpc/init-first.c b/sysdeps/unix/sysv/linux/powerpc/init-first.c
index 57b36af..7e7c4de 100644
--- a/sysdeps/unix/sysv/linux/powerpc/init-first.c
+++ b/sysdeps/unix/sysv/linux/powerpc/init-first.c
@@ -26,6 +26,7 @@ void *__vdso_gettimeofday attribute_hidden;
 void *__vdso_clock_gettime;
 void *__vdso_clock_getres;
 void *__vdso_get_tbfreq;
+void *__vdso_getcpu;
 
 
 static inline void
@@ -40,6 +41,8 @@ _libc_vdso_platform_setup (void)
   __vdso_clock_getres = _dl_vdso_vsym ("__kernel_clock_getres", &linux2615);
 
   __vdso_get_tbfreq = _dl_vdso_vsym ("__kernel_vdso_get_tbfreq", &linux2615);
+
+  __vdso_getcpu = _dl_vdso_vsym ("__kernel_getcpu", &linux2615);
 }
 
 # define VDSO_SETUP _libc_vdso_platform_setup
diff --git a/sysdeps/unix/sysv/linux/powerpc/bits/libc-vdso.h b/sysdeps/unix/sysv/linux/powerpc/sched_getcpu.c
similarity index 54%
copy from sysdeps/unix/sysv/linux/powerpc/bits/libc-vdso.h
copy to sysdeps/unix/sysv/linux/powerpc/sched_getcpu.c
index 9797943..617e6f1 100644
--- a/sysdeps/unix/sysv/linux/powerpc/bits/libc-vdso.h
+++ b/sysdeps/unix/sysv/linux/powerpc/sched_getcpu.c
@@ -1,5 +1,4 @@
-/* Resolve function pointers to VDSO functions.
-   Copyright (C) 2005 Free Software Foundation, Inc.
+/* 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
@@ -16,28 +15,16 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
+#include <sched.h>
+#include <sysdep.h>
+#include <bits/libc-vdso.h>
 
-#ifndef _LIBC_VDSO_H
-#define _LIBC_VDSO_H
 
-#ifdef SHARED
+int
+sched_getcpu (void)
+{
+  unsigned int cpu;
+  int r = INLINE_VSYSCALL (getcpu, 3, &cpu, NULL, NULL);
 
-extern void *__vdso_gettimeofday attribute_hidden;
-
-extern void *__vdso_clock_gettime;
-
-extern void *__vdso_clock_getres;
-
-extern void *__vdso_get_tbfreq;
-
-/* Macro to return vdso_xxx value on IFUNC implementations.
-   On PPC64 the returned value is actually an OPD entry.  */
-#if defined(__PPC64__) || defined(__powerpc64__)
-#define PTR_IFUNC_RET(value)  &value
-#else
-#define PTR_IFUNC_RET(value)  value
-#endif
-
-#endif
-
-#endif /* _LIBC_VDSO_H */
+  return r == -1 ? r : cpu;
+}

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=cc328ae264f5b97d2811a95d84112bb1c6c7cae3

commit cc328ae264f5b97d2811a95d84112bb1c6c7cae3
Author: Adhemerval Zanella <azanella@linux.vnet.ibm.com>
Date:   Mon Mar 4 22:02:41 2013 -0300

    PowerPC: gettimeofday optimization by using IFUNC

diff --git a/ChangeLog b/ChangeLog
index 7ba99a7..ca3e120 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2013-03-04  Adhemerval Zanella  <azanella@linux.vnet.ibm.com>
+
+	* sysdeps/unix/sysv/linux/powerpc/bits/libc-vdso.h: Add macro to
+	return vdso values correctly in IFUNC implementations.
+	* sysdeps/unix/sysv/linux/powerpc/gettimeofday.c (__gettimeofday):
+	Optimization by	using IFUNC.
+
 2012-11-20  Thomas Schwinge  <thomas@codesourcery.com>
 
 	* sysdeps/sh/dl-machine.h (ELF_MACHINE_RUNTIME_FIXUP_PARAMS): New
diff --git a/sysdeps/unix/sysv/linux/powerpc/bits/libc-vdso.h b/sysdeps/unix/sysv/linux/powerpc/bits/libc-vdso.h
index 646e8c0..9797943 100644
--- a/sysdeps/unix/sysv/linux/powerpc/bits/libc-vdso.h
+++ b/sysdeps/unix/sysv/linux/powerpc/bits/libc-vdso.h
@@ -30,6 +30,14 @@ extern void *__vdso_clock_getres;
 
 extern void *__vdso_get_tbfreq;
 
+/* Macro to return vdso_xxx value on IFUNC implementations.
+   On PPC64 the returned value is actually an OPD entry.  */
+#if defined(__PPC64__) || defined(__powerpc64__)
+#define PTR_IFUNC_RET(value)  &value
+#else
+#define PTR_IFUNC_RET(value)  value
+#endif
+
 #endif
 
 #endif /* _LIBC_VDSO_H */
diff --git a/sysdeps/unix/sysv/linux/powerpc/gettimeofday.c b/sysdeps/unix/sysv/linux/powerpc/gettimeofday.c
index 7376135..5943be7 100644
--- a/sysdeps/unix/sysv/linux/powerpc/gettimeofday.c
+++ b/sysdeps/unix/sysv/linux/powerpc/gettimeofday.c
@@ -15,26 +15,47 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
-#include <sysdep.h>
-#include <bp-checks.h>
-#include <stddef.h>
 #include <sys/time.h>
-#include <time.h>
-#include <hp-timing.h>
 
-#include <bits/libc-vdso.h>
+#ifdef SHARED
 
-/* Get the current time of day and timezone information,
-   putting it into *TV and *TZ.  If TZ is NULL, *TZ is not filled.
-   Returns 0 on success, -1 on errors.  */
+# include <dl-vdso.h>
+# include <bits/libc-vdso.h>
 
-int
-__gettimeofday (tv, tz)
-     struct timeval *tv;
-     struct timezone *tz;
+void *gettimeofday_ifunc (void) __asm__ ("__gettimeofday");
+
+static int
+__gettimeofday_syscall (struct timeval *tv, struct timezone *tz)
+{
+  return INLINE_SYSCALL (gettimeofday, 2, tv, tz);
+}
+
+void *
+gettimeofday_ifunc (void)
 {
-  return INLINE_VSYSCALL (gettimeofday, 2, CHECK_1 (tv), CHECK_1 (tz));
+  /* If the vDSO is not available we fall back syscall.  */
+  return (__vdso_gettimeofday ? PTR_IFUNC_RET(__vdso_gettimeofday)
+	  : __gettimeofday_syscall);
+}
+asm (".type __gettimeofday, %gnu_indirect_function");
+
+/* This is doing "libc_hidden_def (__gettimeofday)" but the compiler won't
+   let us do it in C because it doesn't know we're defining __gettimeofday
+   here in this file.  */
+asm (".globl __GI___gettimeofday\n"
+     "__GI___gettimeofday = __gettimeofday");
+
+#else
+
+# include <sysdep.h>
+# include <errno.h>
+
+__gettimeofday (struct timeval *tv, struct timezone *tz)
+{
+  return INLINE_SYSCALL (gettimeofday, 2, tv, tz);
 }
 libc_hidden_def (__gettimeofday)
+
+#endif
 weak_alias (__gettimeofday, gettimeofday)
 libc_hidden_weak (gettimeofday)

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=36016f626e72f5d1cb6107deeab29768d82ff7e3

commit 36016f626e72f5d1cb6107deeab29768d82ff7e3
Merge: 4e1f97c 043c748
Author: Ryan S. Arnold <rsa@linux.vnet.ibm.com>
Date:   Fri Mar 1 16:20:18 2013 -0600

    Merge remote branch 'remotes/origin/release/2.16/master' into local_ibm_2.16

diff --cc ChangeLog
index d5685e1,3de21fd..7ba99a7
--- a/ChangeLog
+++ b/ChangeLog
@@@ -1,42 -1,138 +1,177 @@@
+ 2012-11-20  Thomas Schwinge  <thomas@codesourcery.com>
+ 
+ 	* sysdeps/sh/dl-machine.h (ELF_MACHINE_RUNTIME_FIXUP_PARAMS): New
+ 	macro.
+ 
+ 2012-11-14  H.J. Lu  <hongjiu.lu@intel.com>
+ 
+ 	[BZ #14831]
+ 	* elf/Makefile (tests): Add tst-audit8.
+ 	($(objpfx)tst-audit8): Also depend on $(common-objpfx)math/libm.so.
+ 	($(objpfx)tst-audit8.out): New target.
+ 	(tst-audit8-ENV): New variable.
+ 	* elf/dl-runtime.c (_dl_profile_fixup): Call _dl_fixup to skip
+ 	audit if l_reloc_result is NULL.
+ 	(ELF_MACHINE_RUNTIME_FIXUP_PARAMS): Issue an error if it isn't
+ 	defined and ELF_MACHINE_RUNTIME_FIXUP_ARGS is defined.
+ 	* elf/tst-audit8.c: New file.
+ 
+ 2012-10-04  H.J. Lu  <hongjiu.lu@intel.com>
+ 
+ 	[BZ #14648]
+ 	* sysdeps/x86_64/multiarch/init-arch.c (__init_cpu_features):
+ 	Set bit_FMA_Usable if FMA is supported.
+ 	* sysdeps/x86_64/multiarch/init-arch.h (bit_FMA_Usable): New
+ 	macro.
+ 	(bit_FMA4_Usable): Updated.
+ 	(index_FMA_Usable): New macro.
+ 	(CPUID_FMA): Likewise
+ 	(HAS_FMA): Defined with bit_FMA_Usable.
+ 
+ 2012-09-28  Andreas Schwab  <schwab@linux-m68k.org>
+ 
+ 	[BZ #6530]
+ 	* stdio-common/vfprintf.c (process_string_arg): Revert
+ 	2000-07-22 change.
+ 
+ 2012-07-06  Andreas Schwab  <schwab@linux-m68k.org>
+ 
+ 	[BZ #14042]
+ 	* sysdeps/powerpc/powerpc32/ppc-mcount.S [SHARED]: Don't use PLT
+ 	for call to __mcount_internal.
+ 	* sysdeps/powerpc/powerpc32/Makefile (sysdep_routines)
+ 	(shared-only-routines) [$(subdir) = gmon]: Add compat-ppc-mcount.
+ 	* sysdeps/powerpc/powerpc32/compat-ppc-mcount.S: New file.
+ 
+ 2011-09-28  Jonathan Nieder  <jrnieder@gmail.com>
+ 
+ 	* stdio-common/Makefile (tst-sprintf-ENV): Set environment
+ 	for testcase.
+ 	* stdio-common/tst-sprintf.c: Include <locale.h>
+ 	(main): Test sprintf's handling of incomplete multibyte
+ 	characters.
+ 
+ 2012-09-25  Joseph Myers  <joseph@codesourcery.com>
+ 
+ 	[BZ #14621]
+ 	* posix/glob.c (next_brace_sub): Use size_t instead of unsigned
+ 	int as type of variable DEPTH.
+ 	(glob): Use size_t instead of int as type of variables NEWCOUNT
+ 	and OLD_PATHC.
+ 
+ 2012-09-24  H.J. Lu  <hongjiu.lu@intel.com>
+ 
+ 	[BZ #14562]
+ 	* malloc/arena.c (heap_trim): Properly get fencepost and adjust
+ 	new chunk size with MALLOC_ALIGN_MASK.
+ 
+ 2012-08-29  H.J. Lu  <hongjiu.lu@intel.com>
+ 
+ 	[BZ #14476]
+ 	* Makefile (install): Also pass LD_SO=$(ld.so-version) to
+ 	scripts/test-installation.pl.
+ 	* scripts/test-installation.pl: Use LD_SO to get $ld_so_name
+ 	and $ld_so_version if it is set.
+ 
+ 2012-08-27  Joseph Myers  <joseph@codesourcery.com>
+ 
+ 	[BZ #14459]
+ 	* stdlib/strtod_l.c: Include <stdint.h>.
+ 	(NDEBUG): Do not define.
+ 	(round_and_return): Change EXPONENT parameter to type intmax_t.
+ 	Rearrange calculations to avoid internal overflow possibilities.
+ 	(str_to_mpn): Change EXPONENT parameter to type intmax_t *.
+ 	Rearrange calculations to avoid internal overflow possibilities.
+ 	Assert that number fits inside MPNSIZE limbs.
+ 	(____STRTOF_INTERNAL): Change EXPONENT variable to type intmax_t.
+ 	Change DIG_NO, INT_NO and LEAD_ZERO to type size_t.  Rearrange
+ 	calculations and add assertions to avoid internal overflow
+ 	possibilities.  Add casts to avoid signed/unsigned operations.
+ 	* stdlib/tst-strtod-overflow.c: New file.
+ 	* stdlib/Makefile (tests): Add tst-strtod-overflow.
+ 
+ 2012-08-15  Liubov Dmitrieva  <liubov.dmitrieva@gmail.com>
+ 
+ 	[BZ #14195]
+ 	* sysdeps/i386/i686/multiarch/strcmp-sssse3.S: Fix
+ 	segmentation fault for a case of two empty input strings.
+ 	* string/test-strncasecmp.c (check1): Renamed to...
+ 	(bz12205): ...this.
+ 	(bz14195): Add new testcase for two empty input strings and N > 0.
+ 	(test_main): Call new testcase, adapt for renamed function.
+ 
+ 2012-07-06  Mike Frysinger  <vapier@gentoo.org>
+ 
+ 	* sunrpc/rpc_clntout.c: Change <rpc/types.h> to "rpc/types.h".
+ 
+ 2012-07-16  Andreas Jaeger  <aj@suse.de>
+ 
+ 	* po/ru.po: Update from translation team.
+ 
+ 2012-07-13  Andreas Jaeger  <aj@suse.de>
+ 
+ 	* po/fr.po: Update from translation team.
+ 
+ 2012-07-11  Andreas Jaeger  <aj@suse.de>
+ 
+ 	* po/fr.po: Update from translation team.
+ 
+ 	* po/sv.po: Update from translation team
+ 	* po/fr.po: Another update from translation team.
+ 
+ 2012-07-04  Andreas Schwab  <schwab@linux-m68k.org>
+ 
+ 	* catgets/Makefile ($(objpfx)de.msg): Use xopen-msg.awk instead of
+ 	xopen-msg.sed.
+ 	* catgets/xopen-msg.awk: New file.
+ 	* catgets/xopen-msg.sed: Removed.
+ 
+ 2012-07-04  Andreas Schwab  <schwab@linux-m68k.org>
+ 
+ 	* intl/Makefile ($(objpfx)msgs.h): Use po2test.awk instead of
+ 	po2text.sed.
+ 	* intl/po2test.awk: New file.
+ 	* intl/po2test.sed: Removed.
+ 
 +2012-12-03  Mike Frysinger  <vapier@gentoo.org>
 +
 +	* bits/byteswap.h [__GNUC__]: Change __GNUC_PREREQ from 4.2 to 4.3.
 +	* sysdeps/x86/bits/byteswap.h [__GNUC__]: Likewise.
 +
 +2012-11-19  Joseph Myers  <joseph@codesourcery.com>
 +
 +	* bits/byteswap.h: Include <bits/types.h>.
 +	(__bswap_64): Use __uint64_t instead of unsigned long long int.
 +
 +2012-10-12  H.J. Lu  <hongjiu.lu@intel.com>
 +
 +	* sysdeps/x86/bits/byteswap.h: Include <bits/types.h>.
 +	(__bswap_64): __uint64_t for unsigned 64-bit int.
 +
 +2012-07-06  Andreas Schwab  <schwab@linux-m68k.org>
 +
 +	[BZ #14042]
 +	* sysdeps/powerpc/powerpc32/ppc-mcount.S [SHARED]: Don't use PLT
 +	for call to __mcount_internal.
 +	* sysdeps/powerpc/powerpc32/Makefile (sysdep_routines)
 +	(shared-only-routines) [$(subdir) = gmon]: Add compat-ppc-mcount.
 +	* sysdeps/powerpc/powerpc32/compat-ppc-mcount.S: New file.
 +
 +2012-07-06  Peter Bergner  <bergner@vnet.ibm.com>
 +
 +	* elf/rtld.c (process_envvars): Added conditional EXTRA_LD_ENVVARS_11
 +	macro which allows overriding of AT_PLATFORM using an environment
 +	variable.
 +	* sysdeps/unix/sysv/linux/powerpc/dl-librecon.h: New file adding
 +	definition for the EXTRA_LD_ENVVARS_11 macro.
 +
 +2012-07-06  Ryan S. Arnold  <rsa@linux.vnet.ibm.com>
 +
 +	* elf/dynamic-link.h (elf_get_dynamic_info): Remove assert()
 +	around DT_RUNPATH and DT_RPATH which prevents running a dynamic
 +	linker with an embedded RPATH flag, which is what a compiler
 +	modified to embed a non-default INTERP section would do.
 +
  2012-07-03  Andreas Jaeger  <aj@suse.de>
  
  	* po/bg.po: Update from translation team.

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=4e1f97ccdcc257eba262667f7a3179a7d530330d

commit 4e1f97ccdcc257eba262667f7a3179a7d530330d
Author: Mike Frysinger <vapier@gentoo.org>
Date:   Wed Nov 28 23:04:32 2012 -0500

    byteswap.h: fix gcc ver test for __builtin_bswap{32,64}
    
    The __builtin_bswap* functions were introduced in gcc-4.3, not gcc-4.2.
    Fix the __GNUC_PREREQ tests to reflect this.
    
    Otherwise trying to compile code with gcc-4.2 falls down:
    In file included from /usr/include/endian.h:60,
                     from /usr/include/ctype.h:40,
    /usr/include/bits/byteswap.h: In function 'unsigned int __bswap_32(unsigned int)':
    /usr/include/bits/byteswap.h:46: error: '__builtin_bswap32' was not declared in this scope
    /usr/include/bits/byteswap.h: In function 'long long unsigned int __bswap_64(long long unsigned int)':
    /usr/include/bits/byteswap.h:110: error: '__builtin_bswap64' was not declared in this scope
    
    Signed-off-by: Mike Frysinger <vapier@gentoo.org>
    (cherry picked from commit c9d6789ebe028a260d3e5be0c26b7d02fdfe99fe)

diff --git a/ChangeLog b/ChangeLog
index 837271b..d5685e1 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2012-12-03  Mike Frysinger  <vapier@gentoo.org>
+
+	* bits/byteswap.h [__GNUC__]: Change __GNUC_PREREQ from 4.2 to 4.3.
+	* sysdeps/x86/bits/byteswap.h [__GNUC__]: Likewise.
+
 2012-11-19  Joseph Myers  <joseph@codesourcery.com>
 
 	* bits/byteswap.h: Include <bits/types.h>.
diff --git a/bits/byteswap.h b/bits/byteswap.h
index e19e91a..7e5daed 100644
--- a/bits/byteswap.h
+++ b/bits/byteswap.h
@@ -39,7 +39,7 @@
       (((x) & 0x0000ff00u) <<  8) | (((x) & 0x000000ffu) << 24))
 
 #ifdef __GNUC__
-# if __GNUC_PREREQ (4, 2)
+# if __GNUC_PREREQ (4, 3)
 static __inline unsigned int
 __bswap_32 (unsigned int __bsx)
 {
@@ -70,7 +70,7 @@ __bswap_32 (unsigned int __bsx)
 		     | (((x) & 0x000000000000ff00ull) << 40)		      \
 		     | (((x) & 0x00000000000000ffull) << 56)))
 
-# if __GNUC_PREREQ (4, 2)
+# if __GNUC_PREREQ (4, 3)
 static __inline __uint64_t
 __bswap_64 (__uint64_t __bsx)
 {
diff --git a/sysdeps/x86/bits/byteswap.h b/sysdeps/x86/bits/byteswap.h
index babe567..581687c 100644
--- a/sysdeps/x86/bits/byteswap.h
+++ b/sysdeps/x86/bits/byteswap.h
@@ -40,7 +40,7 @@
       (((x) & 0x0000ff00) <<  8) | (((x) & 0x000000ff) << 24))
 
 #ifdef __GNUC__
-# if __GNUC_PREREQ (4, 2)
+# if __GNUC_PREREQ (4, 3)
 static __inline unsigned int
 __bswap_32 (unsigned int __bsx)
 {
@@ -104,7 +104,7 @@ __bswap_32 (unsigned int __bsx)
 		     | (((x) & 0x000000000000ff00ull) << 40)		      \
 		     | (((x) & 0x00000000000000ffull) << 56)))
 
-# if __GNUC_PREREQ (4, 2)
+# if __GNUC_PREREQ (4, 3)
 static __inline __uint64_t
 __bswap_64 (__uint64_t __bsx)
 {

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=025b233a88a30f5f0474ff2c6051313eb33e5689

commit 025b233a88a30f5f0474ff2c6051313eb33e5689
Author: Joseph Myers <joseph@codesourcery.com>
Date:   Tue Nov 20 00:04:45 2012 +0000

    Fix __bswap_64 return type in generic bits/byteswap.h.
    (cherry picked from commit ecd4caf9783c99fb068a100c35899a0c3a3c6d98)

diff --git a/ChangeLog b/ChangeLog
index e047896..837271b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2012-11-19  Joseph Myers  <joseph@codesourcery.com>
+
+	* bits/byteswap.h: Include <bits/types.h>.
+	(__bswap_64): Use __uint64_t instead of unsigned long long int.
+
 2012-10-12  H.J. Lu  <hongjiu.lu@intel.com>
 
 	* sysdeps/x86/bits/byteswap.h: Include <bits/types.h>.
diff --git a/bits/byteswap.h b/bits/byteswap.h
index 3ca0ad6..e19e91a 100644
--- a/bits/byteswap.h
+++ b/bits/byteswap.h
@@ -24,6 +24,7 @@
 #define _BITS_BYTESWAP_H 1
 
 #include <features.h>
+#include <bits/types.h>
 
 /* Swap bytes in 16 bit value.  */
 #define __bswap_constant_16(x) \
@@ -70,15 +71,15 @@ __bswap_32 (unsigned int __bsx)
 		     | (((x) & 0x00000000000000ffull) << 56)))
 
 # if __GNUC_PREREQ (4, 2)
-static __inline unsigned long long int
-__bswap_64 (unsigned long long int __bsx)
+static __inline __uint64_t
+__bswap_64 (__uint64_t __bsx)
 {
   return __builtin_bswap64 (__bsx);
 }
 # else
 #  define __bswap_64(x) \
      (__extension__							      \
-      ({ union { __extension__ unsigned long long int __ll;		      \
+      ({ union { __extension__ __uint64_t __ll;				      \
 		 unsigned int __l[2]; } __w, __r;			      \
 	 if (__builtin_constant_p (x))					      \
 	   __r.__ll = __bswap_constant_64 (x);				      \
@@ -101,8 +102,8 @@ __bswap_64 (unsigned long long int __bsx)
       | (((x) & 0x000000000000ff00ull) << 40)				      \
       | (((x) & 0x00000000000000ffull) << 56))
 
-static __inline unsigned long long int
-__bswap_64 (unsigned long long int __bsx)
+static __inline __uint64_t
+__bswap_64 (__uint64_t __bsx)
 {
   return __bswap_constant_64 (__bsx);
 }

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=2c739e2cffb65d80787cfa861f9f6c62de327ad6

commit 2c739e2cffb65d80787cfa861f9f6c62de327ad6
Author: H.J. Lu <hjl.tools@gmail.com>
Date:   Fri Oct 12 09:21:47 2012 -0700

    Use __uint64_t in x86 __bswap_64
    (cherry picked from commit d394eb742a3565d7fe7a4b02710a60b5f219ee64)

diff --git a/ChangeLog b/ChangeLog
index cf418f6..e047896 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2012-10-12  H.J. Lu  <hongjiu.lu@intel.com>
+
+	* sysdeps/x86/bits/byteswap.h: Include <bits/types.h>.
+	(__bswap_64): __uint64_t for unsigned 64-bit int.
+
 2012-07-06  Andreas Schwab  <schwab@linux-m68k.org>
 
 	[BZ #14042]
diff --git a/sysdeps/x86/bits/byteswap.h b/sysdeps/x86/bits/byteswap.h
index 4178439..babe567 100644
--- a/sysdeps/x86/bits/byteswap.h
+++ b/sysdeps/x86/bits/byteswap.h
@@ -24,6 +24,7 @@
 #define _BITS_BYTESWAP_H 1
 
 #include <features.h>
+#include <bits/types.h>
 #include <bits/wordsize.h>
 
 /* Swap bytes in 16 bit value.  */
@@ -104,15 +105,15 @@ __bswap_32 (unsigned int __bsx)
 		     | (((x) & 0x00000000000000ffull) << 56)))
 
 # if __GNUC_PREREQ (4, 2)
-static __inline unsigned long long int
-__bswap_64 (unsigned long long int __bsx)
+static __inline __uint64_t
+__bswap_64 (__uint64_t __bsx)
 {
   return __builtin_bswap64 (__bsx);
 }
 # elif __WORDSIZE == 64
 #  define __bswap_64(x) \
      (__extension__							      \
-      ({ register unsigned long __v, __x = (x);				      \
+      ({ register __uint64_t __v, __x = (x);				      \
 	 if (__builtin_constant_p (__x))				      \
 	   __v = __bswap_constant_64 (__x);				      \
 	 else								      \
@@ -121,7 +122,7 @@ __bswap_64 (unsigned long long int __bsx)
 # else
 #  define __bswap_64(x) \
      (__extension__                                                           \
-      ({ union { __extension__ unsigned long long int __ll;                   \
+      ({ union { __extension__ __uint64_t __ll;		                      \
 		 unsigned int __l[2]; } __w, __r;                             \
 	 if (__builtin_constant_p (x))                                        \
 	   __r.__ll = __bswap_constant_64 (x);                                \
@@ -144,8 +145,8 @@ __bswap_64 (unsigned long long int __bsx)
       | (((x) & 0x000000000000ff00ull) << 40)				      \
       | (((x) & 0x00000000000000ffull) << 56))
 
-static __inline unsigned long long int
-__bswap_64 (unsigned long long int __bsx)
+static __inline __uint64_t
+__bswap_64 (__uint64_t __bsx)
 {
   return __bswap_constant_64 (__bsx);
 }

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=a24f8ac8e65b451efc81839dd653d0a0e95a23ab

commit a24f8ac8e65b451efc81839dd653d0a0e95a23ab
Author: Andreas Schwab <schwab@linux-m68k.org>
Date:   Tue May 1 17:10:10 2012 +0200

    Fix missing _mcount@GLIBC_2.0 on powerpc32
    (cherry picked from commit 261f485936b283f4327fc1f2fc8fd1705d805c12)

diff --git a/ChangeLog b/ChangeLog
index 8ff57ef..cf418f6 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2012-07-06  Andreas Schwab  <schwab@linux-m68k.org>
+
+	[BZ #14042]
+	* sysdeps/powerpc/powerpc32/ppc-mcount.S [SHARED]: Don't use PLT
+	for call to __mcount_internal.
+	* sysdeps/powerpc/powerpc32/Makefile (sysdep_routines)
+	(shared-only-routines) [$(subdir) = gmon]: Add compat-ppc-mcount.
+	* sysdeps/powerpc/powerpc32/compat-ppc-mcount.S: New file.
+
 2012-07-06  Peter Bergner  <bergner@vnet.ibm.com>
 
 	* elf/rtld.c (process_envvars): Added conditional EXTRA_LD_ENVVARS_11
diff --git a/sysdeps/powerpc/powerpc32/Makefile b/sysdeps/powerpc/powerpc32/Makefile
index aa2d0b9..64f7900 100644
--- a/sysdeps/powerpc/powerpc32/Makefile
+++ b/sysdeps/powerpc/powerpc32/Makefile
@@ -6,8 +6,9 @@ sysdep-LDFLAGS += -msoft-float
 endif
 
 ifeq ($(subdir),gmon)
-sysdep_routines += ppc-mcount
+sysdep_routines += ppc-mcount compat-ppc-mcount
 static-only-routines += ppc-mcount
+shared-only-routines += compat-ppc-mcount
 endif
 
 ifeq ($(subdir),misc)
diff --git a/sysdeps/powerpc/powerpc32/compat-ppc-mcount.S b/sysdeps/powerpc/powerpc32/compat-ppc-mcount.S
new file mode 100644
index 0000000..2a9cb24
--- /dev/null
+++ b/sysdeps/powerpc/powerpc32/compat-ppc-mcount.S
@@ -0,0 +1,11 @@
+#include <shlib-compat.h>
+
+#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_15)
+
+	compat_text_section
+# define _mcount __compat_mcount
+# include "ppc-mcount.S"
+# undef _mcount
+
+compat_symbol (libc, __compat_mcount, _mcount, GLIBC_2_0)
+#endif
diff --git a/sysdeps/powerpc/powerpc32/ppc-mcount.S b/sysdeps/powerpc/powerpc32/ppc-mcount.S
index 9a3c041..911638b 100644
--- a/sysdeps/powerpc/powerpc32/ppc-mcount.S
+++ b/sysdeps/powerpc/powerpc32/ppc-mcount.S
@@ -1,5 +1,5 @@
 /* PowerPC-specific implementation of profiling support.
-   Copyright (C) 1997, 1999, 2005, 2006 Free Software Foundation, Inc.
+   Copyright (C) 1997-2012 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
@@ -57,7 +57,11 @@ ENTRY(_mcount)
 	stw	r4, 44(r1)
 	cfi_offset (lr, -4)
 	stw	r5,  8(r1)
+#ifndef SHARED
 	bl	JUMPTARGET(__mcount_internal)
+#else
+	bl	__mcount_internal@local
+#endif
  /* Restore the registers...  */
 	lwz     r6,  8(r1)
 	lwz	r0, 44(r1)

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=94464655b576985fdd5f66f7f6126ee1f92a41cc

commit 94464655b576985fdd5f66f7f6126ee1f92a41cc
Author: Peter Bergner <bergner@vnet.ibm.com>
Date:   Fri Jul 6 13:24:49 2012 -0500

    Add AT_PLATFORM env variable to ld.so to override auxv AT_PLATFORM.

diff --git a/ChangeLog b/ChangeLog
index 69a2d7e..8ff57ef 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2012-07-06  Peter Bergner  <bergner@vnet.ibm.com>
+
+	* elf/rtld.c (process_envvars): Added conditional EXTRA_LD_ENVVARS_11
+	macro which allows overriding of AT_PLATFORM using an environment
+	variable.
+	* sysdeps/unix/sysv/linux/powerpc/dl-librecon.h: New file adding
+	definition for the EXTRA_LD_ENVVARS_11 macro.
+
 2012-07-06  Ryan S. Arnold  <rsa@linux.vnet.ibm.com>
 
 	* elf/dynamic-link.h (elf_get_dynamic_info): Remove assert()
diff --git a/elf/rtld.c b/elf/rtld.c
index 6bcf224..d9ccd62 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -2666,6 +2666,11 @@ process_envvars (enum mode *modep)
 	  break;
 
 	case 11:
+#ifdef EXTRA_LD_ENVVARS_11
+	   /* We might have some extra environment variables with length 11
+	      to handle.  */
+	   EXTRA_LD_ENVVARS_11
+#endif
 	  /* Path where the binary is found.  */
 	  if (!INTUSE(__libc_enable_secure)
 	      && memcmp (envline, "ORIGIN_PATH", 11) == 0)
diff --git a/sysdeps/unix/sysv/linux/powerpc/dl-librecon.h b/sysdeps/unix/sysv/linux/powerpc/dl-librecon.h
new file mode 100644
index 0000000..cd4335e
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/powerpc/dl-librecon.h
@@ -0,0 +1,44 @@
+/* Optional code to distinguish library flavors.
+   Copyright (C) 2010-2012 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/>.  */
+
+#ifndef _DL_LIBRECON_H
+
+#include <string.h>
+#include <sysdeps/unix/sysv/linux/dl-librecon.h>
+
+/* Recognizing extra environment variables.  */
+#define EXTRA_LD_ENVVARS_11 \
+  if (memcmp (envline, "AT_PLATFORM", 11) == 0)				      \
+    {									      \
+      int platformlen = strlen (&envline[12]);				      \
+      GLRO(dl_platformlen) = platformlen;				      \
+      if (platformlen > 0)						      \
+	{								      \
+	  GLRO(dl_platform) = &envline[12];				      \
+	  break;							      \
+	}								      \
+      GLRO(dl_platform) = NULL;						      \
+      break;		 		 		 		      \
+    }
+
+/* Extra unsecure variables.  The names are all stuffed in a single
+   string which means they have to be terminated with a '\0' explicitly.  */
+#define EXTRA_UNSECURE_ENVVARS \
+  "LD_AT_PLATFORM\0"
+
+#endif /* dl-librecon.h */

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=d846920271a0f4dc54c0dbbd56998228e75e776c

commit d846920271a0f4dc54c0dbbd56998228e75e776c
Author: Ryan S. Arnold <rsa@linux.vnet.ibm.com>
Date:   Fri Jul 6 13:03:09 2012 -0500

    Remove assert() if DT_RUNPATH and DT_RPATH flags are found in ld.so.

diff --git a/ChangeLog b/ChangeLog
index 756b406..69a2d7e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2012-07-06  Ryan S. Arnold  <rsa@linux.vnet.ibm.com>
+
+	* elf/dynamic-link.h (elf_get_dynamic_info): Remove assert()
+	around DT_RUNPATH and DT_RPATH which prevents running a dynamic
+	linker with an embedded RPATH flag, which is what a compiler
+	modified to embed a non-default INTERP section would do.
+
 2012-07-03  Andreas Jaeger  <aj@suse.de>
 
 	* po/bg.po: Update from translation team.
diff --git a/elf/dynamic-link.h b/elf/dynamic-link.h
index 44f53b3..0c68fd4 100644
--- a/elf/dynamic-link.h
+++ b/elf/dynamic-link.h
@@ -206,8 +206,8 @@ elf_get_dynamic_info (struct link_map *l, ElfW(Dyn) *temp)
   assert (info[DT_FLAGS] == NULL
 	  || (info[DT_FLAGS]->d_un.d_val & ~DF_BIND_NOW) == 0);
   /* Flags must not be set for ld.so.  */
-  assert (info[DT_RUNPATH] == NULL);
-  assert (info[DT_RPATH] == NULL);
+  info[DT_RUNPATH] = NULL;
+  info[DT_RPATH] = NULL;
 #else
   if (info[DT_FLAGS] != NULL)
     {

-----------------------------------------------------------------------


hooks/post-receive
-- 
GNU C Library master sources


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]