about summary refs log tree commit diff
path: root/elf/rtld.c
diff options
context:
space:
mode:
Diffstat (limited to 'elf/rtld.c')
-rw-r--r--elf/rtld.c101
1 files changed, 101 insertions, 0 deletions
diff --git a/elf/rtld.c b/elf/rtld.c
index 2daf05a6d6..b912124fca 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -1077,6 +1077,49 @@ of this helper program; chances are you did not intend to run this program.\n\
   ++GL(dl_nloaded);
   ++GL(dl_load_adds);
 
+#if defined(__i386__)
+  /* Force non-TLS libraries for glibc 2.0 binaries
+     or if a buggy binary references non-TLS errno or h_errno.  */
+  if (__builtin_expect (GL(dl_loaded)->l_info[DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGIDX (DT_VERNEED)] == NULL, 0)
+      && GL(dl_loaded)->l_info[DT_DEBUG])
+    GLRO(dl_osversion) = 0x20205;
+  else if ((__builtin_expect (mode, normal) != normal
+	    || GL(dl_loaded)->l_info [ADDRIDX (DT_GNU_LIBLIST)] == NULL)
+	      /* Only binaries have DT_DEBUG dynamic tags...  */
+	   && GL(dl_loaded)->l_info[DT_DEBUG])
+    {
+      /* Workaround for buggy binaries.  This doesn't handle buggy
+	 libraries.  */
+      bool buggy = false;
+      const ElfW(Sym) *symtab = (const void *) D_PTR (GL(dl_loaded), l_info[DT_SYMTAB]);
+      const char *strtab = (const void *) D_PTR (GL(dl_loaded), l_info[DT_STRTAB]);
+      Elf_Symndx symidx;
+      for (symidx = GL(dl_loaded)->l_buckets[0x6c994f % GL(dl_loaded)->l_nbuckets];
+	   symidx != STN_UNDEF;
+	   symidx = GL(dl_loaded)->l_chain[symidx])
+	{
+	  if (__builtin_expect (strcmp (strtab + symtab[symidx].st_name,
+					"errno") == 0, 0)
+	      && ELFW(ST_TYPE) (symtab[symidx].st_info) != STT_TLS)
+	    buggy = true;
+	}
+      for (symidx = GL(dl_loaded)->l_buckets[0xe5c992f % GL(dl_loaded)->l_nbuckets];
+	   symidx != STN_UNDEF;
+	   symidx = GL(dl_loaded)->l_chain[symidx])
+	{
+	  if (__builtin_expect (strcmp (strtab + symtab[symidx].st_name,
+					"h_errno") == 0, 0)
+	      && ELFW(ST_TYPE) (symtab[symidx].st_info) != STT_TLS)
+	    buggy = true;
+	}
+      if (__builtin_expect (buggy, false) && GLRO(dl_osversion) > 0x20401)
+	{
+	  GLRO(dl_osversion) = 0x20401;
+	  _dl_error_printf ("Incorrectly built binary which accesses errno or h_errno directly. Needs to be fixed.\n");
+	}
+    }
+#endif
+
   /* If LD_USE_LOAD_BIAS env variable has not been seen, default
      to not using bias for non-prelinked PIEs and libraries
      and using it for executables or prelinked PIEs or libraries.  */
@@ -1247,6 +1290,64 @@ ERROR: ld.so: object '%s' from %s cannot be preloaded: ignored.\n",
 	}
     }
 
+
+#if defined(__i386__) || defined(__alpha__) || (defined(__sparc__) && !defined(__arch64__))
+  /*
+   * Modifications by Red Hat Software
+   *
+   * Deal with the broken binaries from the non-versioned ages of glibc.
+   * If a binary does not have version information enabled, we assume that
+   * it is a glibc 2.0 binary and we load a compatibility library to try to
+   * overcome binary incompatibilities.
+   *			Blame: gafton@redhat.com
+   */
+#define LIB_NOVERSION "/lib/libNoVersion.so.1"
+
+  if (__builtin_expect (GL(dl_loaded)->l_info[DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGIDX (DT_VERNEED)] == NULL, 0)
+      && (GL(dl_loaded)->l_info[DT_DEBUG] || !(GLRO(dl_debug_mask) & DL_DEBUG_PRELINK)))
+    {
+      struct stat test_st;
+      int test_fd;
+      int can_load;
+      
+      HP_TIMING_NOW (start);
+	   
+/*       _dl_sysdep_message("Loading compatibility library... ", NULL); */
+
+      can_load = 1;
+      test_fd = __open (LIB_NOVERSION, O_RDONLY);
+      if (test_fd < 0) {
+	  can_load = 0;
+/* 	  _dl_sysdep_message(" Can't find " LIB_NOVERSION "\n",  NULL); */
+      } else {
+	  if (__fxstat (_STAT_VER, test_fd, &test_st) < 0 || test_st.st_size == 0) {
+	      can_load = 0;
+/* 	      _dl_sysdep_message(" Can't stat " LIB_NOVERSION "\n",  NULL); */
+	  }
+      }
+      
+      if (test_fd >= 0) /* open did no fail.. */
+	  __close(test_fd); /* avoid fd leaks */
+
+      if (can_load != 0) {
+	  struct link_map *new_map;
+	  new_map = _dl_map_object (GL(dl_loaded), LIB_NOVERSION,
+				    1, lt_library, 0, 0);
+	  if (++new_map->l_opencount == 1) {
+	      /* It is no duplicate.  */
+	      ++npreloads;
+/* 	      _dl_sysdep_message(" DONE\n", NULL); */
+	  } else {
+/* 	      _dl_sysdep_message(" FAILED\n", NULL); */
+	  }
+      }
+	  
+      HP_TIMING_NOW (stop);
+      HP_TIMING_DIFF (diff, start, stop);
+      HP_TIMING_ACCUM_NT (load_time, diff);
+    }
+#endif
+
   if (__builtin_expect (npreloads, 0) != 0)
     {
       /* Set up PRELOADS with a vector of the preloaded libraries.  */