forked from rpms/glibc
		
	Resync with upstream master
This commit is contained in:
		
							parent
							
								
									1a343f85fe
								
							
						
					
					
						commit
						bf5e654c21
					
				| @ -1,494 +0,0 @@ | ||||
| # | ||||
| # 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). | ||||
| # | ||||
| # Not yet upstream. | ||||
| # | ||||
| diff --git a/csu/libc-start.c b/csu/libc-start.c
 | ||||
| index e5da3ef..c898d06 100644
 | ||||
| --- a/csu/libc-start.c
 | ||||
| +++ b/csu/libc-start.c
 | ||||
| @@ -37,6 +37,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 | ||||
| @@ -195,6 +201,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 aaa9534..cb8da93 100644
 | ||||
| --- a/elf/Makefile
 | ||||
| +++ b/elf/Makefile
 | ||||
| @@ -121,7 +121,8 @@ endif
 | ||||
|  tests = tst-tls1 tst-tls2 tst-tls9 tst-leaks1 \ | ||||
|  	tst-array1 tst-array2 tst-array3 tst-array4 tst-array5 | ||||
|  tests-static = tst-tls1-static tst-tls2-static tst-stackguard1-static \ | ||||
| -	       tst-leaks1-static tst-array1-static tst-array5-static
 | ||||
| +	       tst-leaks1-static tst-array1-static tst-array5-static \
 | ||||
| +	       tst-ptrguard1-static
 | ||||
|  ifeq (yes,$(build-shared)) | ||||
|  tests-static += tst-tls9-static | ||||
|  tst-tls9-static-ENV = \ | ||||
| @@ -145,7 +146,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-null-argv
 | ||||
| +	 tst-initorder tst-initorder2 tst-relsort1 tst-null-argv \
 | ||||
| +	 tst-ptrguard1
 | ||||
|  #	 reldep9 | ||||
|  test-srcs = tst-pathopt | ||||
|  selinux-enabled := $(shell cat /selinux/enforce 2> /dev/null) | ||||
| @@ -1016,6 +1018,9 @@ LDFLAGS-order2mod2.so = $(no-as-needed)
 | ||||
|  tst-stackguard1-ARGS = --command "$(host-test-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/ports/sysdeps/ia64/stackguard-macros.h b/ports/sysdeps/ia64/stackguard-macros.h
 | ||||
| index dc683c2..3907293 100644
 | ||||
| --- a/ports/sysdeps/ia64/stackguard-macros.h
 | ||||
| +++ b/ports/sysdeps/ia64/stackguard-macros.h
 | ||||
| @@ -2,3 +2,6 @@
 | ||||
|   | ||||
|  #define STACK_CHK_GUARD \ | ||||
|    ({ uintptr_t x; asm ("adds %0 = -8, r13;; ld8 %0 = [%0]" : "=r" (x)); x; }) | ||||
| +
 | ||||
| +#define POINTER_CHK_GUARD \
 | ||||
| +  ({ uintptr_t x; asm ("adds %0 = -16, r13;; ld8 %0 = [%0]" : "=r" (x)); x; })
 | ||||
| diff --git a/ports/sysdeps/tile/stackguard-macros.h b/ports/sysdeps/tile/stackguard-macros.h
 | ||||
| index 589ea2b..f2e041b 100644
 | ||||
| --- a/ports/sysdeps/tile/stackguard-macros.h
 | ||||
| +++ b/ports/sysdeps/tile/stackguard-macros.h
 | ||||
| @@ -4,11 +4,17 @@
 | ||||
|  # if __WORDSIZE == 64 | ||||
|  #  define STACK_CHK_GUARD \ | ||||
|    ({ uintptr_t x; asm ("addi %0, tp, -16; ld %0, %0" : "=r" (x)); x; }) | ||||
| +#  define POINTER_CHK_GUARD \
 | ||||
| +  ({ uintptr_t x; asm ("addi %0, tp, -24; ld %0, %0" : "=r" (x)); x; })
 | ||||
|  # else | ||||
|  #  define STACK_CHK_GUARD \ | ||||
|    ({ uintptr_t x; asm ("addi %0, tp, -8; ld4s %0, %0" : "=r" (x)); x; }) | ||||
| +#  define POINTER_CHK_GUARD \
 | ||||
| +  ({ uintptr_t x; asm ("addi %0, tp, -12; ld4s %0, %0" : "=r" (x)); x; })
 | ||||
|  # endif | ||||
|  #else | ||||
|  # define STACK_CHK_GUARD \ | ||||
|    ({ uintptr_t x; asm ("addi %0, tp, -8; lw %0, %0" : "=r" (x)); x; }) | ||||
| +# define POINTER_CHK_GUARD \
 | ||||
| +  ({ uintptr_t x; asm ("addi %0, tp, -12; lw %0, %0" : "=r" (x)); x; })
 | ||||
|  #endif | ||||
| diff --git a/sysdeps/generic/stackguard-macros.h b/sysdeps/generic/stackguard-macros.h
 | ||||
| index ababf65..77408c6 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; })
 | ||||
| diff --git a/elf/Makefile b/elf/Makefile
 | ||||
| index cb8da93..27d249b 100644
 | ||||
| --- a/elf/Makefile
 | ||||
| +++ b/elf/Makefile
 | ||||
| @@ -1019,6 +1019,9 @@ tst-stackguard1-ARGS = --command "$(host-test-program-cmd) --child"
 | ||||
|  tst-stackguard1-static-ARGS = --command "$(objpfx)tst-stackguard1-static --child" | ||||
|   | ||||
|  tst-ptrguard1-ARGS = --command "$(host-test-program-cmd) --child" | ||||
| +# When built statically, the pointer guard interface uses
 | ||||
| +# __pointer_chk_guard_local.
 | ||||
| +CFLAGS-tst-ptrguard1-static.c = -DPTRGUARD_LOCAL
 | ||||
|  tst-ptrguard1-static-ARGS = --command "$(objpfx)tst-ptrguard1-static --child" | ||||
|   | ||||
|  $(objpfx)tst-leaks1: $(libdl) | ||||
| diff --git a/sysdeps/generic/stackguard-macros.h b/sysdeps/generic/stackguard-macros.h
 | ||||
| index 4fa3d96..b4a6b23 100644
 | ||||
| --- a/sysdeps/generic/stackguard-macros.h
 | ||||
| +++ b/sysdeps/generic/stackguard-macros.h
 | ||||
| @@ -3,5 +3,10 @@
 | ||||
|  extern uintptr_t __stack_chk_guard; | ||||
|  #define STACK_CHK_GUARD __stack_chk_guard | ||||
|   | ||||
| +#ifdef PTRGUARD_LOCAL
 | ||||
|  extern uintptr_t __pointer_chk_guard_local; | ||||
| -#define POINTER_CHK_GUARD __pointer_chk_guard_local
 | ||||
| +# define POINTER_CHK_GUARD __pointer_chk_guard_local
 | ||||
| +#else
 | ||||
| +extern uintptr_t __pointer_chk_guard;
 | ||||
| +# define POINTER_CHK_GUARD __pointer_chk_guard
 | ||||
| +#endif
 | ||||
| @ -1,458 +0,0 @@ | ||||
| diff --git a/string/Makefile b/string/Makefile
 | ||||
| index aaad743..f70dc7a 100644
 | ||||
| --- a/string/Makefile
 | ||||
| +++ b/string/Makefile
 | ||||
| @@ -57,6 +57,8 @@ tests		:= tester inl-tester noinl-tester testcopy test-ffs	\
 | ||||
|  tests-ifunc := $(strop-tests:%=test-%-ifunc) | ||||
|  tests += $(tests-ifunc) | ||||
|   | ||||
| +xtests = tst-strcoll-overflow
 | ||||
| +
 | ||||
|  include ../Rules | ||||
|   | ||||
|  tester-ENV = LANGUAGE=C | ||||
| diff --git a/string/strcoll_l.c b/string/strcoll_l.c
 | ||||
| index 50ed84d..4ee101a 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,70 @@ 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;
 | ||||
| +  size_t size_max = SIZE_MAX / (sizeof (int32_t) + 1);
 | ||||
|   | ||||
| -  if (! __libc_use_alloca ((s1len + s2len) * (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)); | ||||
| -      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 +614,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 (__glibc_likely (seq1.rulearr != NULL))
 | ||||
| +	rule = seq1.rulearr[0];
 | ||||
| +      else
 | ||||
| +	rule = seq1.rule;
 | ||||
|      } | ||||
|   | ||||
|    /* Free the memory if needed.  */ | ||||
| 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"
 | ||||
							
								
								
									
										15
									
								
								glibc.spec
									
									
									
									
									
								
							
							
						
						
									
										15
									
								
								glibc.spec
									
									
									
									
									
								
							| @ -1,6 +1,6 @@ | ||||
| %define glibcsrcdir glibc-2.18-113-gf06dd27 | ||||
| %define glibcsrcdir glibc-2.18-151-g303e567 | ||||
| %define glibcversion 2.18.90 | ||||
| %define glibcrelease 4%{?dist} | ||||
| %define glibcrelease 5%{?dist} | ||||
| # Pre-release tarballs are pulled in from git using a command that is | ||||
| # effectively: | ||||
| # | ||||
| @ -208,12 +208,6 @@ Patch2026: %{name}-rh841787.patch | ||||
| # Upstream BZ 14185 | ||||
| Patch2027: %{name}-rh819430.patch | ||||
| 
 | ||||
| # Upstream BZ 14547 | ||||
| Patch2028: %{name}-strcoll-cve.patch | ||||
| 
 | ||||
| # Upstream BZ 15754 | ||||
| Patch2029: %{name}-rh985625-CVE-2013-4788.patch | ||||
| 
 | ||||
| ############################################################################## | ||||
| # End of glibc patches. | ||||
| ############################################################################## | ||||
| @ -535,11 +529,9 @@ package or when debugging this package. | ||||
| %patch0034 -p1 | ||||
| %patch0035 -p1 | ||||
| %patch0037 -p1 | ||||
| %patch2028 -p1 | ||||
| %patch0040 -p1 | ||||
| %patch0041 -p1 | ||||
| %patch0042 -p1 | ||||
| %patch2029 -p1 | ||||
| 
 | ||||
| ############################################################################## | ||||
| # %%prep - Additional prep required... | ||||
| @ -1625,6 +1617,9 @@ rm -f *.filelist* | ||||
| %endif | ||||
| 
 | ||||
| %changelog | ||||
| * Mon Sep 23 2013 Siddhesh Poyarekar <siddhesh@redhat.com> - 2.18.90-5 | ||||
| - Resync with upstream master. | ||||
| 
 | ||||
| * Sun Sep 22 2013 Carlos O'Donell <carlos@redhat.com> - 2.18.90-4 | ||||
| - Fix CVE-2013-4788: Static applications now support pointer mangling. | ||||
|   Existing static applications must be recompiled (#985625). | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user