Blame SOURCES/glibc-rh1189278.patch

147e83
#
147e83
# Based on this upstream commit:
147e83
#
147e83
# commit d8dd00805b8f3a011735d7a407097fb1c408d867
147e83
# Author: H.J. Lu <hjl.tools@gmail.com>
147e83
# Date:   Fri Nov 28 07:54:07 2014 -0800
147e83
# 
147e83
#     Resize DTV if the current DTV isn't big enough
147e83
#     
147e83
#     This patch changes _dl_allocate_tls_init to resize DTV if the current DTV
147e83
#     isn't big enough.  Tested on X86-64, x32 and ia32.
147e83
#     
147e83
#         [BZ #13862]
147e83
#         * elf/dl-tls.c: Include <atomic.h>.
147e83
#         (oom): Remove #ifdef SHARED/#endif.
147e83
#         (_dl_static_dtv, _dl_initial_dtv): Moved before ...
147e83
#         (_dl_resize_dtv): This.  Extracted from _dl_update_slotinfo.
147e83
#         (_dl_allocate_tls_init): Resize DTV if the current DTV isn't
147e83
#         big enough.
147e83
#         (_dl_update_slotinfo): Call _dl_resize_dtv to resize DTV.
147e83
#         * nptl/Makefile (tests): Add tst-stack4.
147e83
#         (modules-names): Add tst-stack4mod.
147e83
#         ($(objpfx)tst-stack4): New.
147e83
#         (tst-stack4mod.sos): Likewise.
147e83
#         ($(objpfx)tst-stack4.out): Likewise.
147e83
#         ($(tst-stack4mod.sos)): Likewise.
147e83
#         (clean): Likewise.
147e83
#         * nptl/tst-stack4.c: New file.
147e83
#         * nptl/tst-stack4mod.c: Likewise.
147e83
# 
147e83
diff -urN glibc-2.17-c758a686/elf/dl-tls.c glibc-2.17-c758a686/elf/dl-tls.c
147e83
--- glibc-2.17-c758a686/elf/dl-tls.c	2015-02-18 14:15:28.078461873 -0500
147e83
+++ glibc-2.17-c758a686/elf/dl-tls.c	2015-02-18 14:38:37.630374771 -0500
147e83
@@ -24,6 +24,7 @@
147e83
 #include <stdlib.h>
147e83
 #include <unistd.h>
147e83
 #include <sys/param.h>
147e83
+#include <atomic.h>
147e83
 
147e83
 #include <tls.h>
147e83
 #include <dl-tls.h>
147e83
@@ -35,14 +36,12 @@
147e83
 
147e83
 
147e83
 /* Out-of-memory handler.  */
147e83
-#ifdef SHARED
147e83
 static void
147e83
 __attribute__ ((__noreturn__))
147e83
 oom (void)
147e83
 {
147e83
   _dl_fatal_printf ("cannot allocate memory for thread-local data: ABORT\n");
147e83
 }
147e83
-#endif
147e83
 
147e83
 
147e83
 size_t
147e83
@@ -392,6 +391,52 @@
147e83
   return result;
147e83
 }
147e83
 
147e83
+static dtv_t *
147e83
+_dl_resize_dtv (dtv_t *dtv)
147e83
+{
147e83
+  /* Resize the dtv.  */
147e83
+  dtv_t *newp;
147e83
+  /* Load GL(dl_tls_max_dtv_idx) atomically since it may be written to by
147e83
+     other threads concurrently. -- We don't have the required atomic
147e83
+     infrastructure to load dl_tls_max_dtv_idx atomically, but on all the
147e83
+     architectures we care about it should load atomically. If this had
147e83
+     an atomic_load_acquire we would still be missing the releases for
147e83
+     the writes.  */
147e83
+  size_t newsize = GL(dl_tls_max_dtv_idx) + DTV_SURPLUS;
147e83
+  size_t oldsize = dtv[-1].counter;
147e83
+
147e83
+#if SHARED
147e83
+  if (dtv == GL(dl_initial_dtv))
147e83
+    {
147e83
+      /* This is the initial dtv that was either statically allocated in
147e83
+	 __libc_setup_tls or allocated during rtld startup using the
147e83
+	 dl-minimal.c malloc instead of the real malloc.  We can't free
147e83
+	 it, we have to abandon the old storage.  */
147e83
+
147e83
+      newp = malloc ((2 + newsize) * sizeof (dtv_t));
147e83
+      if (newp == NULL)
147e83
+	oom ();
147e83
+      memcpy (newp, &dtv[-1], (2 + oldsize) * sizeof (dtv_t));
147e83
+    }
147e83
+  else
147e83
+#endif
147e83
+    {
147e83
+      newp = realloc (&dtv[-1],
147e83
+		      (2 + newsize) * sizeof (dtv_t));
147e83
+      if (newp == NULL)
147e83
+	oom ();
147e83
+    }
147e83
+
147e83
+  newp[0].counter = newsize;
147e83
+
147e83
+  /* Clear the newly allocated part.  */
147e83
+  memset (newp + 2 + oldsize, '\0',
147e83
+	  (newsize - oldsize) * sizeof (dtv_t));
147e83
+
147e83
+  /* Return the generation counter.  */
147e83
+  return &newp[1];
147e83
+}
147e83
+
147e83
 
147e83
 void *
147e83
 internal_function
147e83
@@ -406,6 +451,16 @@
147e83
   size_t total = 0;
147e83
   size_t maxgen = 0;
147e83
 
147e83
+  /* Check if the current dtv is big enough.   */
147e83
+  if (dtv[-1].counter < GL(dl_tls_max_dtv_idx))
147e83
+    {
147e83
+      /* Resize the dtv.  */
147e83
+      dtv = _dl_resize_dtv (dtv);
147e83
+
147e83
+      /* Install this new dtv in the thread data structures.  */
147e83
+      INSTALL_DTV (result, &dtv[-1]);
147e83
+    }
147e83
+
147e83
   /* We have to prepare the dtv for all currently loaded modules using
147e83
      TLS.  For those which are dynamically loaded we add the values
147e83
      indicating deferred allocation.  */
147e83
@@ -637,41 +692,10 @@
147e83
 	      assert (total + cnt == modid);
147e83
 	      if (dtv[-1].counter < modid)
147e83
 		{
147e83
-		  /* Reallocate the dtv.  */
147e83
-		  dtv_t *newp;
147e83
-		  size_t newsize = GL(dl_tls_max_dtv_idx) + DTV_SURPLUS;
147e83
-		  size_t oldsize = dtv[-1].counter;
147e83
-
147e83
-		  assert (map->l_tls_modid <= newsize);
147e83
-
147e83
-		  if (dtv == GL(dl_initial_dtv))
147e83
-		    {
147e83
-		      /* This is the initial dtv that was allocated
147e83
-			 during rtld startup using the dl-minimal.c
147e83
-			 malloc instead of the real malloc.  We can't
147e83
-			 free it, we have to abandon the old storage.  */
147e83
-
147e83
-		      newp = malloc ((2 + newsize) * sizeof (dtv_t));
147e83
-		      if (newp == NULL)
147e83
-			oom ();
147e83
-		      memcpy (newp, &dtv[-1], (2 + oldsize) * sizeof (dtv_t));
147e83
-		    }
147e83
-		  else
147e83
-		    {
147e83
-		      newp = realloc (&dtv[-1],
147e83
-				      (2 + newsize) * sizeof (dtv_t));
147e83
-		      if (newp == NULL)
147e83
-			oom ();
147e83
-		    }
147e83
-
147e83
-		  newp[0].counter = newsize;
147e83
-
147e83
-		  /* Clear the newly allocated part.  */
147e83
-		  memset (newp + 2 + oldsize, '\0',
147e83
-			  (newsize - oldsize) * sizeof (dtv_t));
147e83
+		  /* Resize the dtv.  */
147e83
+		  dtv = _dl_resize_dtv (dtv);
147e83
 
147e83
-		  /* Point dtv to the generation counter.  */
147e83
-		  dtv = &newp[1];
147e83
+		  assert (modid <= dtv[-1].counter);
147e83
 
147e83
 		  /* Install this new dtv in the thread data
147e83
 		     structures.  */
147e83
diff -urN glibc-2.17-c758a686/nptl/Makefile glibc-2.17-c758a686/nptl/Makefile
147e83
--- glibc-2.17-c758a686/nptl/Makefile	2015-02-18 14:15:28.073462028 -0500
147e83
+++ glibc-2.17-c758a686/nptl/Makefile	2015-02-18 14:15:49.817786667 -0500
147e83
@@ -251,7 +251,7 @@
147e83
 	tst-exec1 tst-exec2 tst-exec3 tst-exec4 \
147e83
 	tst-exit1 tst-exit2 tst-exit3 \
147e83
 	tst-stdio1 tst-stdio2 \
147e83
-	tst-stack1 tst-stack2 tst-stack3 tst-pthread-getattr \
147e83
+	tst-stack1 tst-stack2 tst-stack3 tst-stack4 tst-pthread-getattr \
147e83
 	tst-unload \
147e83
 	tst-dlsym1 \
147e83
 	tst-sysconf \
147e83
@@ -297,7 +297,7 @@
147e83
 
147e83
 modules-names = tst-atfork2mod tst-tls3mod tst-tls4moda tst-tls4modb \
147e83
 		tst-tls5mod tst-tls5moda tst-tls5modb tst-tls5modc \
147e83
-		tst-tls5modd tst-tls5mode tst-tls5modf \
147e83
+		tst-tls5modd tst-tls5mode tst-tls5modf tst-stack4mod \
147e83
 		tst-_res1mod1 tst-_res1mod2 tst-execstack-mod tst-fini1mod
147e83
 extra-test-objs += $(addsuffix .os,$(strip $(modules-names))) tst-cleanup4aux.o
147e83
 test-extras += $(modules-names) tst-cleanup4aux
147e83
@@ -459,6 +459,19 @@
147e83
 	$(common-objpfx)malloc/mtrace $(objpfx)tst-stack3.mtrace > $@
147e83
 generated += tst-stack3-mem tst-stack3.mtrace
147e83
 
147e83
+$(objpfx)tst-stack4: $(libdl) $(shared-thread-library)
147e83
+tst-stack4mod.sos=$(shell for i in 0 1 2 3 4 5 6 7 8 9 10 \
147e83
+				   11 12 13 14 15 16 17 18 19; do \
147e83
+			    for j in 0 1 2 3 4 5 6 7 8 9 10 \
147e83
+				     11 12 13 14 15 16 17 18 19; do \
147e83
+			      echo $(objpfx)tst-stack4mod-$$i-$$j.so; \
147e83
+			    done; done)
147e83
+$(objpfx)tst-stack4.out: $(tst-stack4mod.sos)
147e83
+$(tst-stack4mod.sos): $(objpfx)tst-stack4mod.so
147e83
+	cp -f $< $@
147e83
+clean:
147e83
+	rm -f $(tst-stack4mod.sos)
147e83
+
147e83
 $(objpfx)tst-cleanup4: $(objpfx)tst-cleanup4aux.o $(shared-thread-library)
147e83
 $(objpfx)tst-cleanupx4: $(objpfx)tst-cleanup4aux.o $(shared-thread-library)
147e83
 
147e83
diff -urN glibc-2.17-c758a686/nptl/tst-stack4.c glibc-2.17-c758a686/nptl/tst-stack4.c
147e83
--- glibc-2.17-c758a686/nptl/tst-stack4.c	1969-12-31 19:00:00.000000000 -0500
147e83
+++ glibc-2.17-c758a686/nptl/tst-stack4.c	2015-02-18 14:15:49.817786667 -0500
147e83
@@ -0,0 +1,159 @@
147e83
+/* Test DTV size oveflow when pthread_create reuses old DTV and TLS is
147e83
+   used by dlopened shared object.
147e83
+   Copyright (C) 2014 Free Software Foundation, Inc.
147e83
+   This file is part of the GNU C Library.
147e83
+
147e83
+   The GNU C Library is free software; you can redistribute it and/or
147e83
+   modify it under the terms of the GNU Lesser General Public
147e83
+   License as published by the Free Software Foundation; either
147e83
+   version 2.1 of the License, or (at your option) any later version.
147e83
+
147e83
+   The GNU C Library is distributed in the hope that it will be useful,
147e83
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
147e83
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
147e83
+   Lesser General Public License for more details.
147e83
+
147e83
+   You should have received a copy of the GNU Lesser General Public
147e83
+   License along with the GNU C Library; if not, see
147e83
+   <http://www.gnu.org/licenses/>.  */
147e83
+
147e83
+#include <stdio.h>
147e83
+#include <stdint.h>
147e83
+#include <dlfcn.h>
147e83
+#include <assert.h>
147e83
+#include <pthread.h>
147e83
+
147e83
+/* The choices of thread count, and file counts are arbitary.
147e83
+   The point is simply to run enough threads that an exiting
147e83
+   thread has it's stack reused by another thread at the same
147e83
+   time as new libraries have been loaded.  */
147e83
+#define DSO_SHARED_FILES 20
147e83
+#define DSO_OPEN_THREADS 20
147e83
+#define DSO_EXEC_THREADS 2
147e83
+
147e83
+/* Used to make sure that only one thread is calling dlopen and dlclose
147e83
+   at a time.  */
147e83
+pthread_mutex_t g_lock;
147e83
+
147e83
+typedef void (*function) (void);
147e83
+
147e83
+void *
147e83
+dso_invoke(void *dso_fun)
147e83
+{
147e83
+  function *fun_vec = (function *) dso_fun;
147e83
+  int dso;
147e83
+
147e83
+  for (dso = 0; dso < DSO_SHARED_FILES; dso++)
147e83
+    (*fun_vec[dso]) ();
147e83
+
147e83
+  pthread_exit (NULL);
147e83
+}
147e83
+
147e83
+void *
147e83
+dso_process (void * p)
147e83
+{
147e83
+  void *handle[DSO_SHARED_FILES];
147e83
+  function fun_vec[DSO_SHARED_FILES];
147e83
+  char dso_path[DSO_SHARED_FILES][100];
147e83
+  int dso;
147e83
+  uintptr_t t = (uintptr_t) p;
147e83
+
147e83
+  /* Open DSOs and get a function.  */
147e83
+  for (dso = 0; dso < DSO_SHARED_FILES; dso++)
147e83
+    {
147e83
+      sprintf (dso_path[dso], "tst-stack4mod-%i-%i.so", t, dso);
147e83
+
147e83
+      pthread_mutex_lock (&g_lock);
147e83
+
147e83
+      handle[dso] = dlopen (dso_path[dso], RTLD_NOW);
147e83
+      assert (handle[dso]);
147e83
+
147e83
+      fun_vec[dso] = (function) dlsym (handle[dso], "function");
147e83
+      assert (fun_vec[dso]);
147e83
+
147e83
+      pthread_mutex_unlock (&g_lock);
147e83
+    }
147e83
+
147e83
+  /* Spawn workers.  */
147e83
+  pthread_t thread[DSO_EXEC_THREADS];
147e83
+  int i, ret;
147e83
+  uintptr_t result = 0;
147e83
+  for (i = 0; i < DSO_EXEC_THREADS; i++)
147e83
+    {
147e83
+      pthread_mutex_lock (&g_lock);
147e83
+      ret = pthread_create (&thread[i], NULL, dso_invoke, (void *) fun_vec);
147e83
+      if (ret != 0)
147e83
+	{
147e83
+	  printf ("pthread_create failed: %d\n", ret);
147e83
+	  result = 1;
147e83
+	}
147e83
+      pthread_mutex_unlock (&g_lock);
147e83
+    }
147e83
+
147e83
+  if (!result)
147e83
+    for (i = 0; i < DSO_EXEC_THREADS; i++)
147e83
+      {
147e83
+	ret = pthread_join (thread[i], NULL);
147e83
+	if (ret != 0)
147e83
+	  {
147e83
+	    printf ("pthread_join failed: %d\n", ret);
147e83
+	    result = 1;
147e83
+	  }
147e83
+      }
147e83
+
147e83
+  /* Close all DSOs.  */
147e83
+  for (dso = 0; dso < DSO_SHARED_FILES; dso++)
147e83
+    {
147e83
+      pthread_mutex_lock (&g_lock);
147e83
+      dlclose (handle[dso]);
147e83
+      pthread_mutex_unlock (&g_lock);
147e83
+    }
147e83
+
147e83
+  /* Exit.  */
147e83
+  pthread_exit ((void *) result);
147e83
+}
147e83
+
147e83
+static int
147e83
+do_test (void)
147e83
+{
147e83
+  pthread_t thread[DSO_OPEN_THREADS];
147e83
+  int i,j;
147e83
+  int ret;
147e83
+  int result = 0;
147e83
+
147e83
+  pthread_mutex_init (&g_lock, NULL);
147e83
+
147e83
+  /* 100 is arbitrary here and is known to trigger PR 13862.  */
147e83
+  for (j = 0; j < 100; j++)
147e83
+    {
147e83
+      for (i = 0; i < DSO_OPEN_THREADS; i++)
147e83
+	{
147e83
+	  ret = pthread_create (&thread[i], NULL, dso_process,
147e83
+				(void *) (uintptr_t) i);
147e83
+	  if (ret != 0)
147e83
+	    {
147e83
+	      printf ("pthread_create failed: %d\n", ret);
147e83
+	      result = 1;
147e83
+	    }
147e83
+	}
147e83
+
147e83
+      if (result)
147e83
+	break;
147e83
+
147e83
+      for (i = 0; i < DSO_OPEN_THREADS; i++)
147e83
+	{
147e83
+	  ret = pthread_join (thread[i], NULL);
147e83
+	  if (ret != 0)
147e83
+	    {
147e83
+	      printf ("pthread_join failed: %d\n", ret);
147e83
+	      result = 1;
147e83
+	    }
147e83
+	}
147e83
+    }
147e83
+
147e83
+  return result;
147e83
+}
147e83
+
147e83
+#define TEST_FUNCTION do_test ()
147e83
+#define TIMEOUT 100
147e83
+#include "../test-skeleton.c"
147e83
diff -urN glibc-2.17-c758a686/nptl/tst-stack4mod.c glibc-2.17-c758a686/nptl/tst-stack4mod.c
147e83
--- glibc-2.17-c758a686/nptl/tst-stack4mod.c	1969-12-31 19:00:00.000000000 -0500
147e83
+++ glibc-2.17-c758a686/nptl/tst-stack4mod.c	2015-02-18 14:15:49.817786667 -0500
147e83
@@ -0,0 +1,28 @@
147e83
+/* This tests DTV usage with TLS in dlopened shared object.
147e83
+   Copyright (C) 2014 Free Software Foundation, Inc.
147e83
+   This file is part of the GNU C Library.
147e83
+
147e83
+   The GNU C Library is free software; you can redistribute it and/or
147e83
+   modify it under the terms of the GNU Lesser General Public
147e83
+   License as published by the Free Software Foundation; either
147e83
+   version 2.1 of the License, or (at your option) any later version.
147e83
+
147e83
+   The GNU C Library is distributed in the hope that it will be useful,
147e83
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
147e83
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
147e83
+   Lesser General Public License for more details.
147e83
+
147e83
+   You should have received a copy of the GNU Lesser General Public
147e83
+   License along with the GNU C Library; if not, see
147e83
+   <http://www.gnu.org/licenses/>.  */
147e83
+
147e83
+/* 256 is arbitrary here and is known to trigger PR 13862.  */
147e83
+__thread int var[256] attribute_hidden = {0};
147e83
+
147e83
+void
147e83
+function (void)
147e83
+{
147e83
+  int i;
147e83
+  for (i = 0; i < sizeof (var) / sizeof (int); i++)
147e83
+    var[i] = i;
147e83
+}