This is the mail archive of the libc-alpha@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] |
On Thu, Feb 20, 2014 at 10:24:04AM -0500, Carlos O'Donell wrote: > This is a Fedora/RHEL specific patch which should go upstream > since it fixes a real and generic problem. > > At present the dynamic loader does not correctly account > for TLS usage in audit libraries. This results in a crash > in the dynamic loader if the audit library uses TLS. > > The fix for this is to detect the usage of TLS in the audit > library and bump the generation counter. > > The following patch does just that. No regressions on x86-64, > and a new test case added for just this case which segfaults > without the patch but works with the patch. > > OK to checkin? > > 2014-02-20 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. > > diff --git a/elf/Makefile b/elf/Makefile > index 6f4f2f8..932b479 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. > @@ -998,6 +1001,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 9454d06..cbafdd9 100644 > --- a/elf/dl-tls.c > +++ b/elf/dl-tls.c > @@ -105,6 +105,28 @@ _dl_next_tls_modid (void) > } > > > +size_t > +internal_function > +_dl_count_modids (void) > +{ > + if (! __builtin_expect (GL(dl_tls_dtv_gaps), true)) This should use __glibc_{,un}likely. Also, _dl_tls_next_modid has the opposite expectation for the value of dl_tls_dtv_gaps: if (__builtin_expect (GL(dl_tls_dtv_gaps), false)) Since we're explicitly specifying the likelihood of the branch, you might want to explain why each of those annotations are true, or fix the annotation which isn't. Siddhesh > + return GL(dl_tls_max_dtv_idx); > + > + 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 +429,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 aa50cab..7f1413a 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 0000000..0982d8b > --- /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 0000000..7f66e96 > --- /dev/null > +++ b/elf/tst-auditmod9a.c > @@ -0,0 +1,16 @@ > +#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 0000000..8eeeb49 > --- /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 ffeb093..65cd709 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; > > --- > > Cheers, > Carlos.
Attachment:
pgp8PCNbxhq2d.pgp
Description: PGP signature
Index Nav: | [Date Index] [Subject Index] [Author Index] [Thread Index] | |
---|---|---|
Message Nav: | [Date Prev] [Date Next] | [Thread Prev] [Thread Next] |