diff --git a/ChangeLog b/ChangeLog index 0071571bce..9e564f7fd1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,17 @@ +2014-02-25 Ulrich Drepper + Carlos O'Donell + + [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 [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 + +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 + +__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;