]> git.ipfire.org Git - thirdparty/glibc.git/commitdiff
elf: Disable most of TLS modid gaps processing [BZ #27135]
authorFlorian Weimer <fweimer@redhat.com>
Fri, 25 Jun 2021 06:09:08 +0000 (08:09 +0200)
committerFlorian Weimer <fweimer@redhat.com>
Fri, 25 Jun 2021 06:09:08 +0000 (08:09 +0200)
Revert "elf: Fix DTV gap reuse logic [BZ #27135]"

This reverts commit 572bd547d57a39b6cf0ea072545dc4048921f4c3.

It turns out that the _dl_next_tls_modid in _dl_map_object_from_fd keeps
returning the same modid over and over again if there is a gap and
more than TLS-using module is loaded in one dlopen call.  This corrupts
TLS data structures.  The bug is still present after a revert, but
empirically it is much more difficult to trigger (because it involves a
dlopen failure).

elf/dl-close.c
elf/dl-open.c
elf/dl-tls.c

index 9f31532f4145cec596b92d172aba02c8f5c3f3dd..3720e47dd19bc830b223970ff1b16a0e0d8b94dd 100644 (file)
@@ -88,11 +88,7 @@ remove_slotinfo (size_t idx, struct dtv_slotinfo_list *listp, size_t disp,
       /* If this is not the last currently used entry no need to look
         further.  */
       if (idx != GL(dl_tls_max_dtv_idx))
-       {
-         /* There is an unused dtv entry in the middle.  */
-         GL(dl_tls_dtv_gaps) = true;
-         return true;
-       }
+       return true;
     }
 
   while (idx - disp > (disp == 0 ? 1 + GL(dl_tls_static_nelem) : 0))
index d2240d87474e0b85fb4f90869ca623b0597a3477..a066f39bd09131f10bf2824b24091e54eb1d78a6 100644 (file)
@@ -899,6 +899,16 @@ no more namespaces available for dlmopen()"));
         state if relocation failed, for example.  */
       if (args.map)
        {
+         /* Maybe some of the modules which were loaded use TLS.
+            Since it will be removed in the following _dl_close call
+            we have to mark the dtv array as having gaps to fill the
+            holes.  This is a pessimistic assumption which won't hurt
+            if not true.  There is no need to do this when we are
+            loading the auditing DSOs since TLS has not yet been set
+            up.  */
+         if ((mode & __RTLD_AUDIT) == 0)
+           GL(dl_tls_dtv_gaps) = true;
+
          _dl_close_worker (args.map, true);
 
          /* All l_nodelete_pending objects should have been deleted
index e531ec5913d618484a67dfe3018e83b83f0b017c..2b5161d10ab1b3d9790a03dc4646cc66b5bdf045 100644 (file)
@@ -191,7 +191,10 @@ _dl_next_tls_modid (void)
 size_t
 _dl_count_modids (void)
 {
-  /* The count is the max unless dlclose or failed dlopen created gaps.  */
+  /* 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);