a2cf7d
Partial backport without the new tst-dlopen-aout-pie test.  The test
a2cf7d
fails because the a self-dlopen of a PIE binary succeeds, as commit
a2cf7d
23d2e5faf0bca6d9b31bef4aa162b95ee64cbfc6 ("elf: Self-dlopen failure
a2cf7d
with explict loader invocation [BZ #24900]") has not been backported.
a2cf7d
a2cf7d
commit 77523d5e43cb5721c23855eb6045b0607a3b30a0
a2cf7d
Author: Florian Weimer <fweimer@redhat.com>
a2cf7d
Date:   Fri Oct 4 21:23:51 2019 +0200
a2cf7d
a2cf7d
    elf: Assign TLS modid later during dlopen [BZ #24930]
a2cf7d
    
a2cf7d
    Commit a42faf59d6d9f82e5293a9ebcc26d9c9e562b12b ("Fix BZ #16634.")
a2cf7d
    attempted to fix a TLS modid consistency issue by adding additional
a2cf7d
    checks to the open_verify function.  However, this is fragile
a2cf7d
    because open_verify cannot reliably predict whether
a2cf7d
    _dl_map_object_from_fd will later fail in the more complex cases
a2cf7d
    (such as memory allocation failures).  Therefore, this commit
a2cf7d
    assigns the TLS modid as late as possible.  At that point, the link
a2cf7d
    map pointer will eventually be passed to _dl_close, which will undo
a2cf7d
    the TLS modid assignment.
a2cf7d
    
a2cf7d
    Reviewed-by: Gabriel F. T. Gomes <gabrielftg@linux.ibm.com>
a2cf7d
a2cf7d
diff --git a/elf/dl-load.c b/elf/dl-load.c
a2cf7d
index bb839ef70ff46f37..b190b28e32e47391 100644
a2cf7d
--- a/elf/dl-load.c
a2cf7d
+++ b/elf/dl-load.c
a2cf7d
@@ -1134,27 +1134,21 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
a2cf7d
 	     offset.  We will adjust it later.  */
a2cf7d
 	  l->l_tls_initimage = (void *) ph->p_vaddr;
a2cf7d
 
a2cf7d
-	  /* If not loading the initial set of shared libraries,
a2cf7d
-	     check whether we should permit loading a TLS segment.  */
a2cf7d
-	  if (__glibc_likely (l->l_type == lt_library)
a2cf7d
-	      /* If GL(dl_tls_dtv_slotinfo_list) == NULL, then rtld.c did
a2cf7d
-		 not set up TLS data structures, so don't use them now.  */
a2cf7d
-	      || __glibc_likely (GL(dl_tls_dtv_slotinfo_list) != NULL))
a2cf7d
-	    {
a2cf7d
-	      /* Assign the next available module ID.  */
a2cf7d
-	      l->l_tls_modid = _dl_next_tls_modid ();
a2cf7d
-	      break;
a2cf7d
-	    }
a2cf7d
+	  /* l->l_tls_modid is assigned below, once there is no
a2cf7d
+	     possibility for failure.  */
a2cf7d
 
a2cf7d
+	  if (l->l_type != lt_library
a2cf7d
+	      && GL(dl_tls_dtv_slotinfo_list) == NULL)
a2cf7d
+	    {
a2cf7d
 #ifdef SHARED
a2cf7d
-	  /* We are loading the executable itself when the dynamic
a2cf7d
-	     linker was executed directly.  The setup will happen
a2cf7d
-	     later.  Otherwise, the TLS data structures are already
a2cf7d
-	     initialized, and we assigned a TLS modid above.  */
a2cf7d
-	  assert (l->l_prev == NULL || (mode & __RTLD_AUDIT) != 0);
a2cf7d
+	      /* We are loading the executable itself when the dynamic
a2cf7d
+		 linker was executed directly.  The setup will happen
a2cf7d
+		 later.  */
a2cf7d
+	      assert (l->l_prev == NULL || (mode & __RTLD_AUDIT) != 0);
a2cf7d
 #else
a2cf7d
-	  assert (false && "TLS not initialized in static application");
a2cf7d
+	      assert (false && "TLS not initialized in static application");
a2cf7d
 #endif
a2cf7d
+	    }
a2cf7d
 	  break;
a2cf7d
 
a2cf7d
 	case PT_GNU_STACK:
a2cf7d
@@ -1395,6 +1389,18 @@ cannot enable executable stack as shared object requires");
a2cf7d
     add_name_to_object (l, ((const char *) D_PTR (l, l_info[DT_STRTAB])
a2cf7d
 			    + l->l_info[DT_SONAME]->d_un.d_val));
a2cf7d
 
a2cf7d
+  /* _dl_close can only eventually undo the module ID assignment (via
a2cf7d
+     remove_slotinfo) if this function returns a pointer to a link
a2cf7d
+     map.  Therefore, delay this step until all possibilities for
a2cf7d
+     failure have been excluded.  */
a2cf7d
+  if (l->l_tls_blocksize > 0
a2cf7d
+      && (__glibc_likely (l->l_type == lt_library)
a2cf7d
+	  /* If GL(dl_tls_dtv_slotinfo_list) == NULL, then rtld.c did
a2cf7d
+	     not set up TLS data structures, so don't use them now.  */
a2cf7d
+	  || __glibc_likely (GL(dl_tls_dtv_slotinfo_list) != NULL)))
a2cf7d
+    /* Assign the next available module ID.  */
a2cf7d
+    l->l_tls_modid = _dl_next_tls_modid ();
a2cf7d
+
a2cf7d
 #ifdef DL_AFTER_LOAD
a2cf7d
   DL_AFTER_LOAD (l);
a2cf7d
 #endif
a2cf7d
@@ -1662,17 +1668,6 @@ open_verify (const char *name, int fd,
a2cf7d
 	  errstring = N_("only ET_DYN and ET_EXEC can be loaded");
a2cf7d
 	  goto call_lose;
a2cf7d
 	}
a2cf7d
-      else if (__glibc_unlikely (ehdr->e_type == ET_EXEC
a2cf7d
-				 && (mode & __RTLD_OPENEXEC) == 0))
a2cf7d
-	{
a2cf7d
-	  /* BZ #16634. It is an error to dlopen ET_EXEC (unless
a2cf7d
-	     __RTLD_OPENEXEC is explicitly set).  We return error here
a2cf7d
-	     so that code in _dl_map_object_from_fd does not try to set
a2cf7d
-	     l_tls_modid for this module.  */
a2cf7d
-
a2cf7d
-	  errstring = N_("cannot dynamically load executable");
a2cf7d
-	  goto call_lose;
a2cf7d
-	}
a2cf7d
       else if (__glibc_unlikely (ehdr->e_phentsize != sizeof (ElfW(Phdr))))
a2cf7d
 	{
a2cf7d
 	  errstring = N_("ELF file's phentsize not the expected size");