elf: Most symbol lookups cannot deal with unrelocated link maps
diff mbox series

Message ID 87mufbulk4.fsf@oldenburg2.str.redhat.com
State New
Headers show
Series
  • elf: Most symbol lookups cannot deal with unrelocated link maps
Related show

Commit Message

Florian Weimer Sept. 11, 2019, 11:19 a.m. UTC
Lazy binding and dlsym should never pick up not-yet-relocated
objects in the global scope.  Especially during lazy binding,
the subsequent call to the symbol will likely result in a
hard-to-diagnose crash.

2019-09-11  Florian Weimer  <fweimer@redhat.com>

	* sysdeps/generic/ldsodefs.h (DL_LOOKUP_NEED_RELOCATED): Define.
	* elf/dl-lookup.c (_dl_lookup_symbol_x): Check for
	DL_LOOKUP_NEED_RELOCATED.
	* elf/dl-runtime.c (_dl_fixup): Pass DL_LOOKUP_NEED_RELOCATED to
	_dl_lookup_symbol_x.
	* elf/dl-sym.c (do_sym): Likewise.

Patch
diff mbox series

diff --git a/elf/dl-lookup.c b/elf/dl-lookup.c
index fd44cd4101..8933dbccb2 100644
--- a/elf/dl-lookup.c
+++ b/elf/dl-lookup.c
@@ -792,11 +792,13 @@  _dl_lookup_symbol_x (const char *undef_name, struct link_map *undef_map,
 
   bump_num_relocations ();
 
-  /* No other flag than DL_LOOKUP_ADD_DEPENDENCY or DL_LOOKUP_GSCOPE_LOCK
-     is allowed if we look up a versioned symbol.  */
+  /* No other flag than DL_LOOKUP_ADD_DEPENDENCY,
+     DL_LOOKUP_GSCOPE_LOCK, DL_LOOKUP_NEED_RELOCATED is allowed if we
+     look up a versioned symbol.  */
   assert (version == NULL
-	  || (flags & ~(DL_LOOKUP_ADD_DEPENDENCY | DL_LOOKUP_GSCOPE_LOCK))
-	     == 0);
+	  || ((flags & ~(DL_LOOKUP_ADD_DEPENDENCY | DL_LOOKUP_GSCOPE_LOCK
+			 | DL_LOOKUP_NEED_RELOCATED))
+	      == 0));
 
   size_t i = 0;
   if (__glibc_unlikely (skip_map != NULL))
@@ -834,6 +836,32 @@  _dl_lookup_symbol_x (const char *undef_name, struct link_map *undef_map,
       return 0;
     }
 
+  /* Lazy binding and dlsym can only reference relocated objects.  */
+  if (flags & DL_LOOKUP_NEED_RELOCATED
+      && !(current_value.m->l_relocated
+	   || current_value.m->l_type == lt_executable))
+    {
+      const char *reference_name = undef_map ? undef_map->l_name : "";
+      const char *versionstr = version ? ", version " : "";
+      const char *versionname = (version && version->name
+				 ? version->name : "");
+      const char *space = "";
+      const char *target_name = "";
+      if (current_value.m->l_name != NULL
+	  && current_value.m->l_name[0] != '\0')
+	{
+	  space = " ";
+	  target_name = current_value.m->l_name;
+	}
+      struct dl_exception exception;
+      _dl_exception_create_format
+	(&exception, DSO_FILENAME (reference_name),
+	 "attempt to bind symbol %s%s%s to unrelocated object%s%s",
+	 undef_name, versionstr, versionname, space, target_name);
+      _dl_signal_cexception (0, &exception, N_("symbol lookup error"));
+      _dl_exception_free (&exception);
+    }
+
   int protected = (*ref
 		   && ELFW(ST_VISIBILITY) ((*ref)->st_other) == STV_PROTECTED);
   if (__glibc_unlikely (protected != 0))
diff --git a/elf/dl-runtime.c b/elf/dl-runtime.c
index 342b794f54..e9612e3f11 100644
--- a/elf/dl-runtime.c
+++ b/elf/dl-runtime.c
@@ -98,7 +98,7 @@  _dl_fixup (
       /* We need to keep the scope around so do some locking.  This is
 	 not necessary for objects which cannot be unloaded or when
 	 we are not using any threads (yet).  */
-      int flags = DL_LOOKUP_ADD_DEPENDENCY;
+      int flags = DL_LOOKUP_ADD_DEPENDENCY | DL_LOOKUP_NEED_RELOCATED;
       if (!RTLD_SINGLE_THREAD_P)
 	{
 	  THREAD_GSCOPE_SET_FLAG ();
diff --git a/elf/dl-sym.c b/elf/dl-sym.c
index 8209342b13..78d87ca463 100644
--- a/elf/dl-sym.c
+++ b/elf/dl-sym.c
@@ -104,7 +104,8 @@  do_sym (void *handle, const char *name, void *who,
       if (RTLD_SINGLE_THREAD_P)
 	result = GLRO(dl_lookup_symbol_x) (name, match, &ref,
 					   match->l_scope, vers, 0,
-					   flags | DL_LOOKUP_ADD_DEPENDENCY,
+					   flags | DL_LOOKUP_ADD_DEPENDENCY
+					   | DL_LOOKUP_NEED_RELOCATED,
 					   NULL);
       else
 	{
@@ -113,7 +114,8 @@  do_sym (void *handle, const char *name, void *who,
 	  args.map = match;
 	  args.vers = vers;
 	  args.flags
-	    = flags | DL_LOOKUP_ADD_DEPENDENCY | DL_LOOKUP_GSCOPE_LOCK;
+	    = (flags | DL_LOOKUP_ADD_DEPENDENCY | DL_LOOKUP_GSCOPE_LOCK
+	       | DL_LOOKUP_NEED_RELOCATED);
 	  args.refp = &ref;
 
 	  THREAD_GSCOPE_SET_FLAG ();
diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
index f3ba13ee68..6201955b54 100644
--- a/sysdeps/generic/ldsodefs.h
+++ b/sysdeps/generic/ldsodefs.h
@@ -914,6 +914,8 @@  enum
     DL_LOOKUP_RETURN_NEWEST = 2,
     /* Set if dl_lookup* called with GSCOPE lock held.  */
     DL_LOOKUP_GSCOPE_LOCK = 4,
+    /* Require a result in a relocated object.  */
+    DL_LOOKUP_NEED_RELOCATED = 8,
   };
 
 /* Lookup versioned symbol.  */