about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog14
-rw-r--r--NEWS3
-rw-r--r--elf/Makefile9
-rw-r--r--elf/dl-tls.c28
-rw-r--r--elf/rtld.c7
-rw-r--r--elf/tst-audit9.c8
-rw-r--r--elf/tst-auditmod9a.c15
-rw-r--r--elf/tst-auditmod9b.c6
-rw-r--r--sysdeps/generic/ldsodefs.h3
9 files changed, 90 insertions, 3 deletions
diff --git a/ChangeLog b/ChangeLog
index 0071571bce..9e564f7fd1 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,17 @@
+2014-02-25  Ulrich Drepper  <drepper@gmail.com>
+	    Carlos O'Donell  <carlos@redhat.com>
+
+	[BZ #16613]
+	* elf/dl-tls.c (_dl_count_modids): New function.
+	* sysdeps/generic/ldsodefs.h: Declare _dl_count_modids.
+	* elf/rtld.c (dl_main): Call _dl_count_modids to track TLS usage in
+	audit library and increment generation counter.
+	(_dl_allocate_tls_init): Add assertion to check TLS generation count.
+	* elf/tst-audit9.c: New file.
+	* elf/tst-auditmod9a.c: New file.
+	* elf/tst-auditmod9b.c: New file.
+	* elf/Makefile: Add rules to build and run tst-audit9.
+
 2014-02-25  Florian Weimer  <fweimer@redhat.com>
 
 	[BZ #15347]
diff --git a/NEWS b/NEWS
index 96966d7553..ae9c3d62c8 100644
--- a/NEWS
+++ b/NEWS
@@ -9,7 +9,8 @@ Version 2.20
 
 * The following bugs are resolved with this release:
 
-  15347, 15804, 15894, 16447, 16545, 16574, 16600, 16609, 16610, 16611.
+  15347, 15804, 15894, 16447, 16545, 16574, 16600, 16609, 16610, 16611,
+  16613.
 
 * The am33 port, which had not worked for several years, has been removed
   from ports.
diff --git a/elf/Makefile b/elf/Makefile
index 863acd8627..3b217ce326 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -144,7 +144,7 @@ tests += loadtest restest1 preloadtest loadfail multiload origtest resolvfail \
 	 tst-dlmodcount tst-dlopenrpath tst-deep1 \
 	 tst-dlmopen1 tst-dlmopen2 tst-dlmopen3 \
 	 unload3 unload4 unload5 unload6 unload7 unload8 tst-global1 order2 \
-	 tst-audit1 tst-audit2 tst-audit8 \
+	 tst-audit1 tst-audit2 tst-audit8 tst-audit9 \
 	 tst-stackguard1 tst-addr1 tst-thrlock \
 	 tst-unique1 tst-unique2 tst-unique3 tst-unique4 \
 	 tst-initorder tst-initorder2 tst-relsort1 tst-null-argv \
@@ -203,6 +203,7 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \
 		order2mod1 order2mod2 order2mod3 order2mod4 \
 		tst-unique1mod1 tst-unique1mod2 \
 		tst-unique2mod1 tst-unique2mod2 \
+		tst-auditmod9a tst-auditmod9b \
 		tst-unique3lib tst-unique3lib2 \
 		tst-unique4lib \
 		tst-initordera1 tst-initorderb1 \
@@ -560,6 +561,8 @@ unload4mod1.so-no-z-defs = yes
 ifuncmod1.so-no-z-defs = yes
 ifuncmod5.so-no-z-defs = yes
 ifuncmod6.so-no-z-defs = yes
+tst-auditmod9a.so-no-z-defs = yes
+tst-auditmod9b.so-no-z-defs = yes
 
 ifeq ($(build-shared),yes)
 # Build all the modules even when not actually running test programs.
@@ -1012,6 +1015,10 @@ tst-audit1-ENV = LD_AUDIT=$(objpfx)tst-auditmod1.so
 $(objpfx)tst-audit2.out: $(objpfx)tst-auditmod1.so
 tst-audit2-ENV = LD_AUDIT=$(objpfx)tst-auditmod1.so
 
+$(objpfx)tst-audit9: $(libdl)
+$(objpfx)tst-audit9.out: $(objpfx)tst-auditmod9a.so $(objpfx)tst-auditmod9b.so
+tst-audit9-ENV = LD_AUDIT=$(objpfx)tst-auditmod9a.so
+
 $(objpfx)tst-audit8: $(common-objpfx)math/libm.so
 $(objpfx)tst-audit8.out: $(objpfx)tst-auditmod1.so
 tst-audit8-ENV = LD_AUDIT=$(objpfx)tst-auditmod1.so
diff --git a/elf/dl-tls.c b/elf/dl-tls.c
index 9454d06d72..5204fdaac0 100644
--- a/elf/dl-tls.c
+++ b/elf/dl-tls.c
@@ -105,6 +105,33 @@ _dl_next_tls_modid (void)
 }
 
 
+size_t
+internal_function
+_dl_count_modids (void)
+{
+  /* It is rare that we have gaps; see elf/dl-open.c (_dl_open) where
+     we fail to load a module and unload it leaving a gap.  If we don't
+     have gaps then the number of modids is the current maximum so
+     return that.  */
+  if (__glibc_likely (!GL(dl_tls_dtv_gaps)))
+    return GL(dl_tls_max_dtv_idx);
+
+  /* We have gaps and are forced to count the non-NULL entries.  */
+  size_t n = 0;
+  struct dtv_slotinfo_list *runp = GL(dl_tls_dtv_slotinfo_list);
+  while (runp != NULL)
+    {
+      for (size_t i = 0; i < runp->len; ++i)
+	if (runp->slotinfo[i].map != NULL)
+	  ++n;
+
+      runp = runp->next;
+    }
+
+  return n;
+}
+
+
 #ifdef SHARED
 void
 internal_function
@@ -407,6 +434,7 @@ _dl_allocate_tls_init (void *result)
 
 	  /* Keep track of the maximum generation number.  This might
 	     not be the generation counter.  */
+	  assert (listp->slotinfo[cnt].gen <= GL(dl_tls_generation));
 	  maxgen = MAX (maxgen, listp->slotinfo[cnt].gen);
 
 	  if (map->l_tls_offset == NO_TLS_OFFSET
diff --git a/elf/rtld.c b/elf/rtld.c
index aa50cab0a9..7f1413af08 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -1569,6 +1569,10 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n",
 	}
     }
 
+  /* Keep track of the currently loaded modules to count how many
+     non-audit modules which use TLS are loaded.  */
+  size_t count_modids = _dl_count_modids ();
+
   /* Set up debugging before the debugger is notified for the first time.  */
 #ifdef ELF_MACHINE_DEBUG_SETUP
   /* Some machines (e.g. MIPS) don't use DT_DEBUG in this way.  */
@@ -2220,7 +2224,8 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n",
 	_dl_start_profile ();
     }
 
-  if (!was_tls_init_tp_called && GL(dl_tls_max_dtv_idx) > 0)
+  if ((!was_tls_init_tp_called && GL(dl_tls_max_dtv_idx) > 0)
+      || count_modids != _dl_count_modids ())
     ++GL(dl_tls_generation);
 
   /* Now that we have completed relocation, the initializer data
diff --git a/elf/tst-audit9.c b/elf/tst-audit9.c
new file mode 100644
index 0000000000..0982d8b716
--- /dev/null
+++ b/elf/tst-audit9.c
@@ -0,0 +1,8 @@
+#include <dlfcn.h>
+
+int main(void)
+{
+  void *h = dlopen("$ORIGIN/tst-auditmod9b.so", RTLD_LAZY);
+  int (*fp)(void) = dlsym(h, "f");
+  return fp() - 1;
+}
diff --git a/elf/tst-auditmod9a.c b/elf/tst-auditmod9a.c
new file mode 100644
index 0000000000..7213ade123
--- /dev/null
+++ b/elf/tst-auditmod9a.c
@@ -0,0 +1,15 @@
+#include <stdint.h>
+
+__thread int var;
+
+unsigned int
+la_version (unsigned int v)
+{
+  return v;
+}
+
+void
+la_activity (uintptr_t *cookie, unsigned int flag)
+{
+  ++var;
+}
diff --git a/elf/tst-auditmod9b.c b/elf/tst-auditmod9b.c
new file mode 100644
index 0000000000..8eeeb49986
--- /dev/null
+++ b/elf/tst-auditmod9b.c
@@ -0,0 +1,6 @@
+__thread int a;
+
+int f(void)
+{
+  return ++a;
+}
diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
index ffeb093887..65cd709fef 100644
--- a/sysdeps/generic/ldsodefs.h
+++ b/sysdeps/generic/ldsodefs.h
@@ -957,6 +957,9 @@ extern void _dl_sysdep_start_cleanup (void)
 /* Determine next available module ID.  */
 extern size_t _dl_next_tls_modid (void) internal_function attribute_hidden;
 
+/* Count the modules with TLS segments.  */
+extern size_t _dl_count_modids (void) internal_function attribute_hidden;
+
 /* Calculate offset of the TLS blocks in the static TLS block.  */
 extern void _dl_determine_tlsoffset (void) internal_function attribute_hidden;