summary refs log tree commit diff
path: root/elf
diff options
context:
space:
mode:
authorMaciej W. Rozycki <macro@codesourcery.com>2013-06-28 16:20:26 +0100
committerMaciej W. Rozycki <macro@codesourcery.com>2013-06-28 16:22:20 +0100
commitf91f1c0fb89056995f1c9c6a06c361efdf5139e7 (patch)
tree67db98c499e8dbd72bc5b49e654706d375384c0f /elf
parented0257f7d3378ec4a72e297f0dcba5159f2dd138 (diff)
downloadglibc-f91f1c0fb89056995f1c9c6a06c361efdf5139e7.tar.gz
glibc-f91f1c0fb89056995f1c9c6a06c361efdf5139e7.tar.xz
glibc-f91f1c0fb89056995f1c9c6a06c361efdf5139e7.zip
[BZ #15022] Correct global-scope dlopen issues in static executables.
This change creates a link map in static executables to serve as the
global search list for dlopen.  It fixes a problem with the inability
to access the global symbol object and a crash on an attempt to map a
DSO into the global scope.  Some code that has become dead after the
addition of this link map is removed too and test cases are provided.
Diffstat (limited to 'elf')
-rw-r--r--elf/dl-load.c8
-rw-r--r--elf/dl-open.c18
-rw-r--r--elf/dl-support.c51
3 files changed, 46 insertions, 31 deletions
diff --git a/elf/dl-load.c b/elf/dl-load.c
index 757b6ec56b..d53ead4db3 100644
--- a/elf/dl-load.c
+++ b/elf/dl-load.c
@@ -342,13 +342,7 @@ _dl_dst_substitute (struct link_map *l, const char *name, char *result,
 	  if ((len = is_dst (start, name, "ORIGIN", is_path,
 			     INTUSE(__libc_enable_secure))) != 0)
 	    {
-#ifndef SHARED
-	      if (l == NULL)
-		repl = _dl_get_origin ();
-	      else
-#endif
-		repl = l->l_origin;
-
+	      repl = l->l_origin;
 	      check_for_trusted = (INTUSE(__libc_enable_secure)
 				   && l->l_type == lt_executable);
 	    }
diff --git a/elf/dl-open.c b/elf/dl-open.c
index 15221c8d57..7adf66b221 100644
--- a/elf/dl-open.c
+++ b/elf/dl-open.c
@@ -204,11 +204,9 @@ dl_open_worker (void *a)
     {
       const void *caller_dlopen = args->caller_dlopen;
 
-#ifdef SHARED
       /* We have to find out from which object the caller is calling.
 	 By default we assume this is the main application.  */
       call_map = GL(dl_ns)[LM_ID_BASE]._ns_loaded;
-#endif
 
       struct link_map *l = _dl_find_dso_for_object ((ElfW(Addr)) caller_dlopen);
 
@@ -216,15 +214,7 @@ dl_open_worker (void *a)
         call_map = l;
 
       if (args->nsid == __LM_ID_CALLER)
-	{
-#ifndef SHARED
-	  /* In statically linked apps there might be no loaded object.  */
-	  if (call_map == NULL)
-	    args->nsid = LM_ID_BASE;
-	  else
-#endif
-	    args->nsid = call_map->l_ns;
-	}
+	args->nsid = call_map->l_ns;
     }
 
   assert (_dl_debug_initialize (0, args->nsid)->r_state == RT_CONSISTENT);
@@ -642,12 +632,6 @@ no more namespaces available for dlmopen()"));
 	       || GL(dl_ns)[nsid]._ns_loaded->l_auditing))
     _dl_signal_error (EINVAL, file, NULL,
 		      N_("invalid target namespace in dlmopen()"));
-#ifndef SHARED
-  else if ((nsid == LM_ID_BASE || nsid == __LM_ID_CALLER)
-	   && GL(dl_ns)[LM_ID_BASE]._ns_loaded == NULL
-	   && GL(dl_nns) == 0)
-    GL(dl_nns) = 1;
-#endif
 
   struct dl_open_args args;
   args.file = file;
diff --git a/elf/dl-support.c b/elf/dl-support.c
index b3ab9560ad..76752f33f3 100644
--- a/elf/dl-support.c
+++ b/elf/dl-support.c
@@ -70,17 +70,52 @@ const char *_dl_origin_path;
 /* Nonzero if runtime lookup should not update the .got/.plt.  */
 int _dl_bind_not;
 
+/* A dummy link map for the executable, used by dlopen to access the global
+   scope.  We don't export any symbols ourselves, so this can be minimal.  */
+static struct link_map _dl_main_map =
+  {
+    .l_name = (char *) "",
+    .l_real = &_dl_main_map,
+    .l_ns = LM_ID_BASE,
+    .l_libname = &(struct libname_list) { .name = "", .dont_free = 1 },
+    .l_searchlist =
+      {
+	.r_list = &(struct link_map *) { &_dl_main_map },
+	.r_nlist = 1,
+      },
+    .l_symbolic_searchlist = { .r_list = &(struct link_map *) { NULL } },
+    .l_type = lt_executable,
+    .l_scope_mem = { &_dl_main_map.l_searchlist },
+    .l_scope_max = (sizeof (_dl_main_map.l_scope_mem)
+		    / sizeof (_dl_main_map.l_scope_mem[0])),
+    .l_scope = _dl_main_map.l_scope_mem,
+    .l_local_scope = { &_dl_main_map.l_searchlist },
+    .l_used = 1,
+    .l_tls_offset = NO_TLS_OFFSET,
+    .l_serial = 1,
+  };
+
 /* Namespace information.  */
-struct link_namespaces _dl_ns[DL_NNS];
-size_t _dl_nns;
+struct link_namespaces _dl_ns[DL_NNS] =
+  {
+    [LM_ID_BASE] =
+      {
+	._ns_loaded = &_dl_main_map,
+	._ns_nloaded = 1,
+	._ns_main_searchlist = &_dl_main_map.l_searchlist,
+      }
+  };
+size_t _dl_nns = 1;
 
 /* Incremented whenever something may have been added to dl_loaded. */
-unsigned long long _dl_load_adds;
+unsigned long long _dl_load_adds = 1;
 
-/* Fake scope.  In dynamically linked binaries this is the scope of the
-   main application but here we don't have something like this.  So
-   create a fake scope containing nothing.  */
-struct r_scope_elem _dl_initial_searchlist;
+/* Fake scope of the main application.  */
+struct r_scope_elem _dl_initial_searchlist =
+  {
+    .r_list = &(struct link_map *) { &_dl_main_map },
+    .r_nlist = 1,
+  };
 
 #ifndef HAVE_INLINED_SYSCALLS
 /* Nonzero during startup.  */
@@ -265,6 +300,8 @@ void
 internal_function
 _dl_non_dynamic_init (void)
 {
+  _dl_main_map.l_origin = _dl_get_origin ();
+
   if (HP_TIMING_AVAIL)
     HP_TIMING_NOW (_dl_cpuclock_offset);