548bcb
commit 572bd547d57a39b6cf0ea072545dc4048921f4c3
548bcb
Author: Szabolcs Nagy <szabolcs.nagy@arm.com>
548bcb
Date:   Thu Dec 31 13:59:38 2020 +0000
548bcb
548bcb
    elf: Fix DTV gap reuse logic [BZ #27135]
548bcb
    
548bcb
    For some reason only dlopen failure caused dtv gaps to be reused.
548bcb
    
548bcb
    It is possible that the intent was to never reuse modids for a
548bcb
    different module, but after dlopen failure all gaps are reused
548bcb
    not just the ones caused by the unfinished dlopened.
548bcb
    
548bcb
    So the code has to handle reused modids already which seems to
548bcb
    work, however the data races at thread creation and tls access
548bcb
    (see bug 19329 and bug 27111) may be more severe if slots are
548bcb
    reused so this is scheduled after those fixes. I think fixing
548bcb
    the races are not simpler if reuse is disallowed and reuse has
548bcb
    other benefits, so set GL(dl_tls_dtv_gaps) whenever entries are
548bcb
    removed from the middle of the slotinfo list. The value does
548bcb
    not have to be correct: incorrect true value causes the next
548bcb
    modid query to do a slotinfo walk, incorrect false will leave
548bcb
    gaps and new entries are added at the end.
548bcb
    
548bcb
    Fixes bug 27135.
548bcb
    
548bcb
    Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
548bcb
548bcb
diff --git a/elf/dl-close.c b/elf/dl-close.c
548bcb
index 7d2dc2272cd643f5..41cb6c58491c364b 100644
548bcb
--- a/elf/dl-close.c
548bcb
+++ b/elf/dl-close.c
548bcb
@@ -88,7 +88,11 @@ remove_slotinfo (size_t idx, struct dtv_slotinfo_list *listp, size_t disp,
548bcb
       /* If this is not the last currently used entry no need to look
548bcb
 	 further.  */
548bcb
       if (idx != GL(dl_tls_max_dtv_idx))
548bcb
-	return true;
548bcb
+	{
548bcb
+	  /* There is an unused dtv entry in the middle.  */
548bcb
+	  GL(dl_tls_dtv_gaps) = true;
548bcb
+	  return true;
548bcb
+	}
548bcb
     }
548bcb
 
548bcb
   while (idx - disp > (disp == 0 ? 1 + GL(dl_tls_static_nelem) : 0))
548bcb
diff --git a/elf/dl-open.c b/elf/dl-open.c
548bcb
index a67fb3aee40860e1..54727402750f4c0c 100644
548bcb
--- a/elf/dl-open.c
548bcb
+++ b/elf/dl-open.c
548bcb
@@ -896,16 +896,6 @@ no more namespaces available for dlmopen()"));
548bcb
 	 state if relocation failed, for example.  */
548bcb
       if (args.map)
548bcb
 	{
548bcb
-	  /* Maybe some of the modules which were loaded use TLS.
548bcb
-	     Since it will be removed in the following _dl_close call
548bcb
-	     we have to mark the dtv array as having gaps to fill the
548bcb
-	     holes.  This is a pessimistic assumption which won't hurt
548bcb
-	     if not true.  There is no need to do this when we are
548bcb
-	     loading the auditing DSOs since TLS has not yet been set
548bcb
-	     up.  */
548bcb
-	  if ((mode & __RTLD_AUDIT) == 0)
548bcb
-	    GL(dl_tls_dtv_gaps) = true;
548bcb
-
548bcb
 	  _dl_close_worker (args.map, true);
548bcb
 
548bcb
 	  /* All l_nodelete_pending objects should have been deleted
548bcb
diff --git a/elf/dl-tls.c b/elf/dl-tls.c
548bcb
index 801eafad3961573c..bacb4101e2e2c4e5 100644
548bcb
--- a/elf/dl-tls.c
548bcb
+++ b/elf/dl-tls.c
548bcb
@@ -187,10 +187,7 @@ _dl_next_tls_modid (void)
548bcb
 size_t
548bcb
 _dl_count_modids (void)
548bcb
 {
548bcb
-  /* It is rare that we have gaps; see elf/dl-open.c (_dl_open) where
548bcb
-     we fail to load a module and unload it leaving a gap.  If we don't
548bcb
-     have gaps then the number of modids is the current maximum so
548bcb
-     return that.  */
548bcb
+  /* The count is the max unless dlclose or failed dlopen created gaps.  */
548bcb
   if (__glibc_likely (!GL(dl_tls_dtv_gaps)))
548bcb
     return GL(dl_tls_max_dtv_idx);
548bcb