summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog27
-rw-r--r--elf/dl-deps.c13
-rw-r--r--elf/dl-libc.c5
-rw-r--r--elf/dl-lookup.c45
-rw-r--r--elf/dl-open.c9
-rw-r--r--elf/dl-reloc.c15
-rw-r--r--elf/dl-runtime.c106
-rw-r--r--elf/dl-sym.c22
-rw-r--r--elf/dl-symbol.c5
-rw-r--r--elf/do-lookup.h15
-rw-r--r--elf/dynamic-link.h13
-rw-r--r--elf/ldsodefs.h8
-rw-r--r--include/unistd.h9
-rw-r--r--posix/unistd.h11
14 files changed, 192 insertions, 111 deletions
diff --git a/ChangeLog b/ChangeLog
index a254cc09aa..e6995d9a8b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -13,6 +13,33 @@
 	DT_PREINIT_ARRAY, DT_PREINIT_ARRAYSZ.
 	Add DF_ORIGIN, DF_SYMBOLIC, DF_TEXTREL, and DF_BIND_NOW.
 
+	* posix/unistd.h: Move declaration of __libc_enable_secure to...
+	* include/unistd.h: ...here.
+
+	* elf/dl-open.c (dl_open_worker): If DST is used in SUID program punt.
+	* elf/dl-deps.c (expand_dst): Likewise.
+
+	* elf/dynamic-link.h: Set DT_SYMBOLIC, DT_TEXTREL, and DT_BIND_NOW
+	based on DT_FLAGS value.
+
+	* elf/do-lookup.h: Remove reference_name parameter, add undef_map.
+	Add test for symbols marked STV_HIDDEN.
+	* elf/dl-lookup.c (_dl_lookup_symbol): Remove reference_name parameter,
+	add undef_map.  Compute reference_name locally.  Update call to
+	do_lookup.
+	(_dl_lookup_symbol_skip): Likewise.
+	(_dl_lookup_versioned_symbol): Likewise.
+	(_dl_lookup_versioned_symbol_skip): Likewise.
+	* elf/dl-libc.c: Update call to _dl_lookup_*symbol.
+	* elf/dl-runtime.c: Likewise.
+	* elf/dl-sym.c: Likewise.
+	* elf/dl-symbol.c: Likewise.
+	* elf/ldsodefs.h: Adjust prototypes.
+
+	* elf/dl-reloc.c (RESOLV): Add test for STV_PROTECTED flag set and
+	handle appropriately.  Add comment about DT_TEXTREL.
+	* elf/dl-runtime.c: Likewise.
+
 1999-07-21  Roland McGrath  <roland@baalperazim.frob.com>
 
 	* elf/dl-reloc.c (_dl_reloc_bad_type): New function.
diff --git a/elf/dl-deps.c b/elf/dl-deps.c
index b981d490df..68e4921ce5 100644
--- a/elf/dl-deps.c
+++ b/elf/dl-deps.c
@@ -22,6 +22,7 @@
 #include <errno.h>
 #include <stdlib.h>
 #include <string.h>
+#include <unistd.h>
 #include <sys/param.h>
 #include <elf/ldsodefs.h>
 
@@ -96,9 +97,15 @@ struct list
 									      \
     if (__cnt != 0)							      \
       {									      \
-	char *__newp = (char *) alloca (DL_DST_REQUIRED (l, __str,	      \
-							 strlen (__str),      \
-							 __cnt));	      \
+	char *__newp;							      \
+									      \
+	/* DST must not appear in SUID/SGID programs.  */		      \
+	if (__libc_enable_secure)					      \
+	  _dl_signal_error (0, __str,					      \
+			    "DST not allowed in SUID/SGID programs");	      \
+									      \
+	__newp = (char *) alloca (DL_DST_REQUIRED (l, __str, strlen (__str),  \
+						   __cnt));		      \
 									      \
 	__result = DL_DST_SUBSTITUTE (l, __str, __newp, 0);		      \
 									      \
diff --git a/elf/dl-libc.c b/elf/dl-libc.c
index afb3f2d14e..784af27c3d 100644
--- a/elf/dl-libc.c
+++ b/elf/dl-libc.c
@@ -82,9 +82,8 @@ do_dlsym (void *ptr)
 {
   struct do_dlsym_args *args = (struct do_dlsym_args *) ptr;
   args->ref = NULL;
-  args->loadbase = _dl_lookup_symbol (args->name, &args->ref,
-				      args->map->l_local_scope,
-				      args->map->l_name, 0);
+  args->loadbase = _dl_lookup_symbol (args->name, args->map, &args->ref,
+				      args->map->l_local_scope, 0);
 }
 
 static void
diff --git a/elf/dl-lookup.c b/elf/dl-lookup.c
index 16173c9068..4120cb1e64 100644
--- a/elf/dl-lookup.c
+++ b/elf/dl-lookup.c
@@ -75,11 +75,11 @@ unsigned long int _dl_num_relocations;
 
 ElfW(Addr)
 internal_function
-_dl_lookup_symbol (const char *undef_name, const ElfW(Sym) **ref,
-		   struct r_scope_elem *symbol_scope[],
-		   const char *reference_name,
+_dl_lookup_symbol (const char *undef_name, struct link_map *undef_map,
+		   const ElfW(Sym) **ref, struct r_scope_elem *symbol_scope[],
 		   int reloc_type)
 {
+  const char *reference_name = undef_map ? undef_map->l_name : NULL;
   const unsigned long int hash = _dl_elf_hash (undef_name);
   struct sym_val current_value = { NULL, NULL };
   struct r_scope_elem **scope;
@@ -88,8 +88,8 @@ _dl_lookup_symbol (const char *undef_name, const ElfW(Sym) **ref,
 
   /* Search the relevant loaded objects for a definition.  */
   for (scope = symbol_scope; *scope; ++scope)
-    if (do_lookup (undef_name, hash, *ref, &current_value,
-		   *scope, 0, reference_name, NULL, reloc_type))
+    if (do_lookup (undef_name, undef_map, hash, *ref, &current_value,
+		   *scope, 0, NULL, reloc_type))
       break;
 
   if (current_value.s == NULL)
@@ -125,11 +125,12 @@ _dl_lookup_symbol (const char *undef_name, const ElfW(Sym) **ref,
    SKIP_MAP is only skipped.  */
 ElfW(Addr)
 internal_function
-_dl_lookup_symbol_skip (const char *undef_name, const ElfW(Sym) **ref,
+_dl_lookup_symbol_skip (const char *undef_name,
+			struct link_map *undef_map, const ElfW(Sym) **ref,
 			struct r_scope_elem *symbol_scope[],
-			const char *reference_name,
 			struct link_map *skip_map)
 {
+  const char *reference_name = undef_map ? undef_map->l_name : NULL;
   const unsigned long int hash = _dl_elf_hash (undef_name);
   struct sym_val current_value = { NULL, NULL };
   struct r_scope_elem **scope;
@@ -143,11 +144,11 @@ _dl_lookup_symbol_skip (const char *undef_name, const ElfW(Sym) **ref,
     assert (i < (*scope)->r_nduplist);
 
   if (i >= (*scope)->r_nlist
-      || ! do_lookup (undef_name, hash, *ref, &current_value,
-		      *scope, i, reference_name, skip_map, 0))
+      || ! do_lookup (undef_name, undef_map, hash, *ref, &current_value,
+		      *scope, i, skip_map, 0))
     while (*++scope)
-      if (do_lookup (undef_name, hash, *ref, &current_value,
-		     *scope, 0, reference_name, skip_map, 0))
+      if (do_lookup (undef_name, undef_map, hash, *ref, &current_value,
+		     *scope, 0, skip_map, 0))
 	break;
 
   if (current_value.s == NULL)
@@ -177,12 +178,13 @@ _dl_lookup_symbol_skip (const char *undef_name, const ElfW(Sym) **ref,
    XXX We'll see whether we need this separate function.  */
 ElfW(Addr)
 internal_function
-_dl_lookup_versioned_symbol (const char *undef_name, const ElfW(Sym) **ref,
+_dl_lookup_versioned_symbol (const char *undef_name,
+			     struct link_map *undef_map, const ElfW(Sym) **ref,
 			     struct r_scope_elem *symbol_scope[],
-			     const char *reference_name,
 			     const struct r_found_version *version,
 			     int reloc_type)
 {
+  const char *reference_name = undef_map ? undef_map->l_name : NULL;
   const unsigned long int hash = _dl_elf_hash (undef_name);
   struct sym_val current_value = { NULL, NULL };
   struct r_scope_elem **scope;
@@ -192,8 +194,8 @@ _dl_lookup_versioned_symbol (const char *undef_name, const ElfW(Sym) **ref,
   /* Search the relevant loaded objects for a definition.  */
   for (scope = symbol_scope; *scope; ++scope)
     {
-      int res = do_lookup_versioned (undef_name, hash, *ref, &current_value,
-				     *scope, 0, reference_name, version, NULL,
+      int res = do_lookup_versioned (undef_name, undef_map, hash, *ref,
+				     &current_value, *scope, 0, version, NULL,
 				     reloc_type);
       if (res > 0)
 	break;
@@ -250,12 +252,13 @@ _dl_lookup_versioned_symbol (const char *undef_name, const ElfW(Sym) **ref,
 ElfW(Addr)
 internal_function
 _dl_lookup_versioned_symbol_skip (const char *undef_name,
+				  struct link_map *undef_map,
 				  const ElfW(Sym) **ref,
 				  struct r_scope_elem *symbol_scope[],
-				  const char *reference_name,
 				  const struct r_found_version *version,
 				  struct link_map *skip_map)
 {
+  const char *reference_name = undef_map ? undef_map->l_name : NULL;
   const unsigned long int hash = _dl_elf_hash (undef_name);
   struct sym_val current_value = { NULL, NULL };
   struct r_scope_elem **scope;
@@ -269,11 +272,13 @@ _dl_lookup_versioned_symbol_skip (const char *undef_name,
     assert (i < (*scope)->r_nduplist);
 
   if (i >= (*scope)->r_nlist
-      || ! do_lookup_versioned (undef_name, hash, *ref, &current_value, *scope,
-				i, reference_name, version, skip_map, 0))
+      || ! do_lookup_versioned (undef_name, undef_map, hash, *ref,
+				&current_value, *scope, i, version, skip_map,
+				0))
     while (*++scope)
-      if (do_lookup_versioned (undef_name, hash, *ref, &current_value, *scope,
-			       0, reference_name, version, skip_map, 0))
+      if (do_lookup_versioned (undef_name, undef_map, hash, *ref,
+			       &current_value, *scope, 0, version, skip_map,
+			       0))
 	break;
 
   if (current_value.s == NULL)
diff --git a/elf/dl-open.c b/elf/dl-open.c
index a3cd8a05a3..097fd372c0 100644
--- a/elf/dl-open.c
+++ b/elf/dl-open.c
@@ -20,9 +20,10 @@
 #include <assert.h>
 #include <dlfcn.h>
 #include <errno.h>
+#include <libintl.h>
 #include <stdlib.h>
 #include <string.h>
-#include <libintl.h>
+#include <unistd.h>
 #include <sys/mman.h>		/* Check whether MAP_COPY is defined.  */
 #include <sys/param.h>
 #include <bits/libc-lock.h>
@@ -100,6 +101,12 @@ dl_open_worker (void *a)
       struct link_map *call_map;
       char *new_file;
 
+      /* DSTs must not appear in SUID/SGID programs.  */
+      if (__libc_enable_secure)
+	/* This is an error.  */
+	_dl_signal_error (0, "dlopen",
+			  "DST not allowed in SUID/SGID programs");
+
       /* We have to find out from which object the caller is calling.
 	 Find the highest-addressed object that ADDRESS is not below.  */
       call_map = NULL;
diff --git a/elf/dl-reloc.c b/elf/dl-reloc.c
index 0bf39a8b5e..a1c235a398 100644
--- a/elf/dl-reloc.c
+++ b/elf/dl-reloc.c
@@ -71,11 +71,13 @@ _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[],
 
     /* This macro is used as a callback from the ELF_DYNAMIC_RELOCATE code.  */
 #define RESOLVE(ref, version, flags) \
-    ((version) != NULL && (version)->hash != 0				      \
-     ? _dl_lookup_versioned_symbol (strtab + (*ref)->st_name, (ref), scope,   \
-				    l->l_name, (version), (flags))	      \
-     : _dl_lookup_symbol (strtab + (*ref)->st_name, (ref), scope,	      \
-			  l->l_name, (flags)))
+    (ELFW(ST_VISIBILITY) ((*ref)->st_other) != STV_PROTECTED		      \
+     ? ((version) != NULL && (version)->hash != 0			      \
+	? _dl_lookup_versioned_symbol (strtab + (*ref)->st_name, l, (ref),    \
+				       scope, (version), (flags))	      \
+	: _dl_lookup_symbol (strtab + (*ref)->st_name, l, (ref), scope,	      \
+			     (flags)))					      \
+     : l->l_addr)
 
 #include "dynamic-link.h"
     ELF_DYNAMIC_RELOCATE (l, lazy, consider_profiling);
@@ -96,6 +98,9 @@ _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[],
   /* Mark the object so we know this work has been done.  */
   l->l_relocated = 1;
 
+  /* DT_TEXTREL is now in level 2 and might phase out at some time.
+     But we rewrite the DT_FLAGS entry to make testing easier and
+     therefore it will be available at all time.  */
   if (l->l_info[DT_TEXTREL])
     {
       /* Undo the protection change we made before relocating.  */
diff --git a/elf/dl-runtime.c b/elf/dl-runtime.c
index 9f3004ecf5..a55fbf6e4b 100644
--- a/elf/dl-runtime.c
+++ b/elf/dl-runtime.c
@@ -66,32 +66,40 @@ fixup (
   /* Sanity check that we're really looking at a PLT relocation.  */
   assert (ELFW(R_TYPE)(reloc->r_info) == ELF_MACHINE_JMP_SLOT);
 
-   /* Look up the target symbol.  */
-  switch (l->l_info[VERSYMIDX (DT_VERSYM)] != NULL)
+   /* Look up the target symbol.  If the symbol is marked STV_PROTEXTED
+      don't look in the global scope.  */
+  if (ELFW(ST_VISIBILITY) (sym->st_other) != STV_PROTECTED)
     {
-    default:
-      {
-	const ElfW(Half) *vernum =
-	  (const void *) l->l_info[VERSYMIDX (DT_VERSYM)]->d_un.d_ptr;
-	ElfW(Half) ndx = vernum[ELFW(R_SYM) (reloc->r_info)];
-	const struct r_found_version *version = &l->l_versions[ndx];
-
-	if (version->hash != 0)
+      switch (l->l_info[VERSYMIDX (DT_VERSYM)] != NULL)
+	{
+	default:
 	  {
-	    value = _dl_lookup_versioned_symbol(strtab + sym->st_name,
-						&sym, l->l_scope, l->l_name,
-						version, ELF_MACHINE_JMP_SLOT);
-	    break;
+	    const ElfW(Half) *vernum =
+	      (const void *) l->l_info[VERSYMIDX (DT_VERSYM)]->d_un.d_ptr;
+	    ElfW(Half) ndx = vernum[ELFW(R_SYM) (reloc->r_info)];
+	    const struct r_found_version *version = &l->l_versions[ndx];
+
+	    if (version->hash != 0)
+	      {
+		value = _dl_lookup_versioned_symbol(strtab + sym->st_name, l,
+						    &sym, l->l_scope, version,
+						    ELF_MACHINE_JMP_SLOT);
+		break;
+	      }
 	  }
-      }
-    case 0:
-      value = _dl_lookup_symbol (strtab + sym->st_name, &sym, l->l_scope,
-				 l->l_name, ELF_MACHINE_JMP_SLOT);
-    }
+	case 0:
+	  value = _dl_lookup_symbol (strtab + sym->st_name, l, &sym,
+				     l->l_scope, ELF_MACHINE_JMP_SLOT);
+	}
 
-  /* Currently value contains the base load address of the object
-     that defines sym.  Now add in the symbol offset.  */
-  value = (sym ? value + sym->st_value : 0);
+      /* Currently value contains the base load address of the object
+	 that defines sym.  Now add in the symbol offset.  */
+      value = (sym ? value + sym->st_value : 0);
+    }
+  else
+    /* We already found the symbol.  The module (and therefore its load
+       address) is also known.  */
+    value = l->l_addr + sym->st_value;
 
   /* And now perhaps the relocation addend.  */
   value = elf_machine_plt_value (l, reloc, value);
@@ -141,33 +149,41 @@ profile_fixup (
       /* Sanity check that we're really looking at a PLT relocation.  */
       assert (ELFW(R_TYPE)(reloc->r_info) == ELF_MACHINE_JMP_SLOT);
 
-      /* Look up the target symbol.  */
-      switch (l->l_info[VERSYMIDX (DT_VERSYM)] != NULL)
+      /* Look up the target symbol.  If the symbol is marked STV_PROTEXTED
+	 don't look in the global scope.  */
+      if (ELFW(ST_VISIBILITY) (sym->st_other) != STV_PROTECTED)
 	{
-	default:
-	  {
-	    const ElfW(Half) *vernum =
-	      (const void *) l->l_info[VERSYMIDX (DT_VERSYM)]->d_un.d_ptr;
-	    ElfW(Half) ndx = vernum[ELFW(R_SYM) (reloc->r_info)];
-	    const struct r_found_version *version = &l->l_versions[ndx];
-
-	    if (version->hash != 0)
+	  switch (l->l_info[VERSYMIDX (DT_VERSYM)] != NULL)
+	    {
+	    default:
 	      {
-		value = _dl_lookup_versioned_symbol(strtab + sym->st_name,
-						    &sym, l->l_scope,
-						    l->l_name, version,
-						    ELF_MACHINE_JMP_SLOT);
-		break;
+		const ElfW(Half) *vernum =
+		  (const void *) l->l_info[VERSYMIDX (DT_VERSYM)]->d_un.d_ptr;
+		ElfW(Half) ndx = vernum[ELFW(R_SYM) (reloc->r_info)];
+		const struct r_found_version *version = &l->l_versions[ndx];
+
+		if (version->hash != 0)
+		  {
+		    value = _dl_lookup_versioned_symbol(strtab + sym->st_name,
+							l, &sym, l->l_scope,
+							version,
+							ELF_MACHINE_JMP_SLOT);
+		    break;
+		  }
 	      }
-	  }
-	case 0:
-	  value = _dl_lookup_symbol (strtab + sym->st_name, &sym, l->l_scope,
-				     l->l_name, ELF_MACHINE_JMP_SLOT);
+	    case 0:
+	      value = _dl_lookup_symbol (strtab + sym->st_name, l, &sym,
+					 l->l_scope, ELF_MACHINE_JMP_SLOT);
+	    }
+
+	  /* Currently value contains the base load address of the object
+	     that defines sym.  Now add in the symbol offset.  */
+	  value = (sym ? value + sym->st_value : 0);
 	}
-
-      /* Currently value contains the base load address of the object
-	 that defines sym.  Now add in the symbol offset.  */
-      value = (sym ? value + sym->st_value : 0);
+      else
+	/* We already found the symbol.  The module (and therefore its load
+	   address) is also known.  */
+	value = l->l_addr + sym->st_value;
 
       /* And now perhaps the relocation addend.  */
       value = elf_machine_plt_value (l, reloc, value);
diff --git a/elf/dl-sym.c b/elf/dl-sym.c
index 441b54fe45..91ca1277df 100644
--- a/elf/dl-sym.c
+++ b/elf/dl-sym.c
@@ -34,7 +34,7 @@ _dl_sym (void *handle, const char *name, void *who)
 
   if (handle == RTLD_DEFAULT)
     /* Search the global scope.  */
-    loadbase = _dl_lookup_symbol (name, &ref, _dl_global_scope, NULL, 0);
+    loadbase = _dl_lookup_symbol (name, NULL, &ref, _dl_global_scope, 0);
   else if (handle == RTLD_NEXT)
     {
       struct link_map *l, *match;
@@ -54,15 +54,14 @@ RTLD_NEXT used in code not dynamically loaded"));
       while (l->l_loader)
 	l = l->l_loader;
 
-      loadbase = _dl_lookup_symbol_skip (name, &ref, l->l_local_scope,
-					 NULL, match);
+      loadbase = _dl_lookup_symbol_skip (name, l, &ref, l->l_local_scope,
+					 match);
     }
   else
     {
       /* Search the scope of the given object.  */
       struct link_map *map = handle;
-      loadbase = _dl_lookup_symbol (name, &ref, map->l_local_scope,
-				    map->l_name, 0);
+      loadbase = _dl_lookup_symbol (name, map, &ref, map->l_local_scope, 0);
     }
 
   if (loadbase)
@@ -88,8 +87,8 @@ _dl_vsym (void *handle, const char *name, const char *version, void *who)
 
   if (handle == RTLD_DEFAULT)
     /* Search the global scope.  */
-    loadbase = _dl_lookup_versioned_symbol (name, &ref, _dl_global_scope,
-					    NULL, &vers, 0);
+    loadbase = _dl_lookup_versioned_symbol (name, NULL, &ref, _dl_global_scope,
+					    &vers, 0);
   else if (handle == RTLD_NEXT)
     {
       struct link_map *l, *match;
@@ -109,17 +108,16 @@ RTLD_NEXT used in code not dynamically loaded"));
       while (l->l_loader)
 	l = l->l_loader;
 
-      loadbase = _dl_lookup_versioned_symbol_skip (name, &ref,
+      loadbase = _dl_lookup_versioned_symbol_skip (name, l, &ref,
 						   l->l_local_scope,
-						   NULL, &vers, match);
+						   &vers, match);
     }
   else
     {
       /* Search the scope of the given object.  */
       struct link_map *map = handle;
-      loadbase = _dl_lookup_versioned_symbol (name, &ref,
-					      map->l_local_scope,
-					      map->l_name, &vers, 0);
+      loadbase = _dl_lookup_versioned_symbol (name, map, &ref,
+					      map->l_local_scope, &vers, 0);
     }
 
   if (loadbase)
diff --git a/elf/dl-symbol.c b/elf/dl-symbol.c
index 3ae44d6bea..945f5446ae 100644
--- a/elf/dl-symbol.c
+++ b/elf/dl-symbol.c
@@ -1,5 +1,5 @@
 /* Look up a symbol's run-time value in the scope of a loaded object.
-   Copyright (C) 1995, 1996, 1998 Free Software Foundation, Inc.
+   Copyright (C) 1995, 1996, 1998, 1999 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -28,7 +28,6 @@ _dl_symbol_value (struct link_map *map, const char *name)
 {
   ElfW(Addr) loadbase;
   const ElfW(Sym) *ref = NULL;
-  loadbase = _dl_lookup_symbol (name, &ref, map->l_local_scope, map->l_name,
-				0);
+  loadbase = _dl_lookup_symbol (name, map, &ref, map->l_local_scope, 0);
   return loadbase + ref->st_value;
 }
diff --git a/elf/do-lookup.h b/elf/do-lookup.h
index 147560bd32..f83b13ccf3 100644
--- a/elf/do-lookup.h
+++ b/elf/do-lookup.h
@@ -29,10 +29,10 @@
    found the symbol, the value 0 if nothing is found and < 0 if
    something bad happened.  */
 static inline int
-FCT (const char *undef_name, unsigned long int hash,
-     const ElfW(Sym) *ref, struct sym_val *result,
-     struct r_scope_elem *scope, size_t i, const char *reference_name,
-     ARG struct link_map *skip, int reloc_type)
+FCT (const char *undef_name, struct link_map *undef_map,
+     unsigned long int hash, const ElfW(Sym) *ref, struct sym_val *result,
+     struct r_scope_elem *scope, size_t i, ARG struct link_map *skip,
+     int reloc_type)
 {
   struct link_map **list = scope->r_list;
   size_t n = scope->r_nlist;
@@ -154,7 +154,12 @@ FCT (const char *undef_name, unsigned long int hash,
 	sym = num_versions == 1 ? versioned_sym : NULL;
 #endif
 
-      if (sym != NULL)
+      if (sym != NULL
+	  /* Don't allow binding if the symbol is hidden.  When processor
+	     specific definitions for STV_INTERNAL are defined we might
+	     have to extend this conditional.  */
+	  && (ELFW(ST_VISIBILITY) (sym->st_other) != STV_HIDDEN
+	      || map == undef_map))
 	{
 	found_it:
 	  switch (ELFW(ST_BIND) (sym->st_info))
diff --git a/elf/dynamic-link.h b/elf/dynamic-link.h
index d322c1231f..59a6001069 100644
--- a/elf/dynamic-link.h
+++ b/elf/dynamic-link.h
@@ -93,6 +93,19 @@ elf_get_dynamic_info (ElfW(Dyn) *dyn, ElfW(Addr) l_addr,
     info[DT_JMPREL]->d_un.d_ptr += l_addr;
   if (info[VERSYMIDX (DT_VERSYM)] != NULL)
     info[VERSYMIDX (DT_VERSYM)]->d_un.d_ptr += l_addr;
+  if (info[DT_FLAGS] != NULL)
+    {
+      /* Flags are used.  Translate to the old form where available.
+	 Since these l_info entries are only tested for NULL pointers it
+	 is ok if they point to the DT_FLAGS entry.  */
+      ElfW(Word) flags = info[DT_FLAGS]->d_un.d_val;
+      if (flags & DF_SYMBOLIC)
+	info[DT_SYMBOLIC] = info[DT_FLAGS];
+      if (flags & DF_TEXTREL)
+	info[DT_TEXTREL] = info[DT_FLAGS];
+      if (flags & DF_BIND_NOW)
+	info[DT_BIND_NOW] = info[DT_FLAGS];
+    }
 }
 
 #ifdef RESOLVE
diff --git a/elf/ldsodefs.h b/elf/ldsodefs.h
index 483e85b085..15b7cc6037 100644
--- a/elf/ldsodefs.h
+++ b/elf/ldsodefs.h
@@ -260,35 +260,35 @@ extern void _dl_setup_hash (struct link_map *map) internal_function;
    the `elf_machine_lookup_*_p' macros in dl-machine.h to affect which
    symbols can be chosen.  */
 extern ElfW(Addr) _dl_lookup_symbol (const char *undef,
+				     struct link_map *undef_map,
 				     const ElfW(Sym) **sym,
 				     struct r_scope_elem *symbol_scope[],
-				     const char *reference_name,
 				     int reloc_type)
      internal_function;
 
 /* Lookup versioned symbol.  */
 extern ElfW(Addr) _dl_lookup_versioned_symbol (const char *undef,
+					       struct link_map *undef_map,
 					       const ElfW(Sym) **sym,
 					       struct r_scope_elem *symbol_scope[],
-					       const char *reference_name,
 					       const struct r_found_version *version,
 					       int reloc_type)
      internal_function;
 
 /* For handling RTLD_NEXT we must be able to skip shared objects.  */
 extern ElfW(Addr) _dl_lookup_symbol_skip (const char *undef,
+					  struct link_map *undef_map,
 					  const ElfW(Sym) **sym,
 					  struct r_scope_elem *symbol_scope[],
-					  const char *reference_name,
 					  struct link_map *skip_this)
      internal_function;
 
 /* For handling RTLD_NEXT with versioned symbols we must be able to
    skip shared objects.  */
 extern ElfW(Addr) _dl_lookup_versioned_symbol_skip (const char *undef,
+						    struct link_map *undef_map,
 						    const ElfW(Sym) **sym,
 						    struct r_scope_elem *symbol_scope[],
-						    const char *reference_name,
 						    const struct r_found_version *version,
 						    struct link_map *skip_this)
      internal_function;
diff --git a/include/unistd.h b/include/unistd.h
index 955637e0fb..06fa8fbd93 100644
--- a/include/unistd.h
+++ b/include/unistd.h
@@ -63,4 +63,13 @@ extern int __profil __P ((unsigned short int *__sample_buffer, size_t __size,
 			  size_t __offset, unsigned int __scale));
 extern int __getdtablesize __P ((void));
 extern int __brk __P ((__ptr_t __addr));
+
+
+/* This variable is set nonzero at startup if the process's effective
+   IDs differ from its real IDs, or it is otherwise indicated that
+   extra security should be used.  When this is set the dynamic linker
+   and some functions contained in the C library ignore various
+   environment variables that normally affect them.  */
+extern int __libc_enable_secure;
+
 #endif
diff --git a/posix/unistd.h b/posix/unistd.h
index ea1d47b2fb..d8800b7b3b 100644
--- a/posix/unistd.h
+++ b/posix/unistd.h
@@ -927,16 +927,7 @@ extern int lockf64 __P ((int __fd, int __cmd, __off64_t __len));
     ({ long int __result;						      \
        do __result = (long int) (expression);				      \
        while (__result == -1L && errno == EINTR);			      \
-       __result; }))							      \
-
-
-/* This variable is set nonzero at startup if the process's effective
-   IDs differ from its real IDs, or it is otherwise indicated that
-   extra security should be used.  When this is set the dynamic linker
-   and some functions contained in the C library ignore various
-   environment variables that normally affect them.  */
-extern int __libc_enable_secure;
-
+       __result; }))
 #endif
 
 #if defined __USE_POSIX199309 || defined __USE_UNIX98