[2/4] elf: Extract _dl_sym_post, _dl_sym_find_caller_map from elf/dl-sym.c

Message ID 68608ef426b88e73e0e3178497bcfe34dd8a66ef.1581182210.git.fweimer@redhat.com
State Committed
Headers

Commit Message

Florian Weimer Feb. 8, 2020, 7:01 p.m. UTC
  The definitions are moved into a new file, elf/dl-sym-post.h, so that
this code can be used by the dynamic loader as well.
---
 elf/dl-sym-post.h | 106 ++++++++++++++++++++++++++++++++++++++++++++++
 elf/dl-sym.c      |  86 ++-----------------------------------
 2 files changed, 110 insertions(+), 82 deletions(-)
 create mode 100644 elf/dl-sym-post.h
  

Comments

Carlos O'Donell Feb. 14, 2020, 10:36 p.m. UTC | #1
On 2/8/20 2:01 PM, Florian Weimer wrote:
> The definitions are moved into a new file, elf/dl-sym-post.h, so that
> this code can be used by the dynamic loader as well.

OK for master. I like the cleanup.

Reviewed-by: Carlos O'Donell <carlos@redhat.com>

> ---
>  elf/dl-sym-post.h | 106 ++++++++++++++++++++++++++++++++++++++++++++++
>  elf/dl-sym.c      |  86 ++-----------------------------------
>  2 files changed, 110 insertions(+), 82 deletions(-)
>  create mode 100644 elf/dl-sym-post.h
> 
> diff --git a/elf/dl-sym-post.h b/elf/dl-sym-post.h
> new file mode 100644
> index 0000000000..4c4f574633
> --- /dev/null
> +++ b/elf/dl-sym-post.h
> @@ -0,0 +1,106 @@
> +/* Post-processing of a symbol produced by dlsym, dlvsym.
> +   Copyright (C) 1999-2020 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
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <https://www.gnu.org/licenses/>.  */
> +
> +
> +/* Return the link map containing the caller address.  */
> +static struct link_map *
> +_dl_sym_find_caller_link_map (ElfW(Addr) caller)
> +{
> +  struct link_map *l = _dl_find_dso_for_object (caller);
> +  if (l != NULL)
> +    return l;
> +  else
> +    /* If the address is not recognized the call comes from the main
> +       program (we hope).  */
> +    return GL(dl_ns)[LM_ID_BASE]._ns_loaded;
> +}

OK.

> +
> +/* Translates RESULT, *REF, VALUE into a symbol address from the point
> +   of view of MATCH.  Performs IFUNC resolution and auditing if
> +   necessary.  If MATCH is NULL, CALLER is used to determine it.  */
> +static void *
> +_dl_sym_post (lookup_t result, const ElfW(Sym) *ref, void *value,
> +              ElfW(Addr) caller, struct link_map *match)
> +{
> +  /* Resolve indirect function address.  */
> +  if (__glibc_unlikely (ELFW(ST_TYPE) (ref->st_info) == STT_GNU_IFUNC))
> +    {
> +      DL_FIXUP_VALUE_TYPE fixup
> +        = DL_FIXUP_MAKE_VALUE (result, (ElfW(Addr)) value);
> +      fixup = elf_ifunc_invoke (DL_FIXUP_VALUE_ADDR (fixup));
> +      value = (void *) DL_FIXUP_VALUE_CODE_ADDR (fixup);
> +    }
> +
> +#ifdef SHARED
> +  /* Auditing checkpoint: we have a new binding.  Provide the
> +     auditing libraries the possibility to change the value and
> +     tell us whether further auditing is wanted.  */
> +  if (__glibc_unlikely (GLRO(dl_naudit) > 0))
> +    {
> +      const char *strtab = (const char *) D_PTR (result,
> +                                                 l_info[DT_STRTAB]);
> +      /* Compute index of the symbol entry in the symbol table of
> +         the DSO with the definition.  */
> +      unsigned int ndx = (ref - (ElfW(Sym) *) D_PTR (result,
> +                                                     l_info[DT_SYMTAB]));
> +
> +      if (match == NULL)
> +        match = _dl_sym_find_caller_link_map (caller);
> +
> +      if ((match->l_audit_any_plt | result->l_audit_any_plt) != 0)
> +        {
> +          unsigned int altvalue = 0;
> +          struct audit_ifaces *afct = GLRO(dl_audit);
> +          /* Synthesize a symbol record where the st_value field is
> +             the result.  */
> +          ElfW(Sym) sym = *ref;
> +          sym.st_value = (ElfW(Addr)) value;
> +
> +          for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
> +            {
> +              struct auditstate *match_audit
> +                = link_map_audit_state (match, cnt);
> +              struct auditstate *result_audit
> +                = link_map_audit_state (result, cnt);
> +              if (afct->symbind != NULL
> +                  && ((match_audit->bindflags & LA_FLG_BINDFROM) != 0
> +                      || ((result_audit->bindflags & LA_FLG_BINDTO)
> +                          != 0)))
> +                {
> +                  unsigned int flags = altvalue | LA_SYMB_DLSYM;
> +                  uintptr_t new_value
> +                    = afct->symbind (&sym, ndx,
> +                                     &match_audit->cookie,
> +                                     &result_audit->cookie,
> +                                     &flags, strtab + ref->st_name);
> +                  if (new_value != (uintptr_t) sym.st_value)
> +                    {
> +                      altvalue = LA_SYMB_ALTVALUE;
> +                      sym.st_value = new_value;
> +                    }
> +                }
> +
> +              afct = afct->next;
> +            }
> +
> +          value = (void *) sym.st_value;
> +        }
> +    }
> +#endif
> +  return value;
> +}

OK.

> diff --git a/elf/dl-sym.c b/elf/dl-sym.c
> index b43a50e544..361b926ea9 100644
> --- a/elf/dl-sym.c
> +++ b/elf/dl-sym.c
> @@ -28,6 +28,7 @@
>  #include <sysdep-cancel.h>
>  #include <dl-tls.h>
>  #include <dl-irel.h>
> +#include <dl-sym-post.h>
>  
>  
>  #ifdef SHARED
> @@ -80,19 +81,6 @@ call_dl_lookup (void *ptr)
>  					args->flags, NULL);
>  }
>  
> -/* Return the link map containing the caller address.  */
> -static inline struct link_map *
> -find_caller_link_map (ElfW(Addr) caller)
> -{
> -  struct link_map *l = _dl_find_dso_for_object (caller);
> -  if (l != NULL)
> -    return l;
> -  else
> -    /* If the address is not recognized the call comes from the main
> -       program (we hope).  */
> -    return GL(dl_ns)[LM_ID_BASE]._ns_loaded;
> -}
> -
>  static void *
>  do_sym (void *handle, const char *name, void *who,
>  	struct r_found_version *vers, int flags)
> @@ -106,7 +94,7 @@ do_sym (void *handle, const char *name, void *who,
>  
>    if (handle == RTLD_DEFAULT)
>      {
> -      match = find_caller_link_map (caller);
> +      match = _dl_sym_find_caller_link_map (caller);
>  
>        /* Search the global scope.  We have the simple case where
>  	 we look up in the scope of an object which was part of
> @@ -140,7 +128,7 @@ do_sym (void *handle, const char *name, void *who,
>      }
>    else if (handle == RTLD_NEXT)
>      {
> -      match = find_caller_link_map (caller);
> +      match = _dl_sym_find_caller_link_map (caller);
>  
>        if (__glibc_unlikely (match == GL(dl_ns)[LM_ID_BASE]._ns_loaded))
>  	{
> @@ -179,73 +167,7 @@ RTLD_NEXT used in code not dynamically loaded"));
>  #endif
>  	value = DL_SYMBOL_ADDRESS (result, ref);
>  
> -      /* Resolve indirect function address.  */
> -      if (__glibc_unlikely (ELFW(ST_TYPE) (ref->st_info) == STT_GNU_IFUNC))
> -	{
> -	  DL_FIXUP_VALUE_TYPE fixup
> -	    = DL_FIXUP_MAKE_VALUE (result, (ElfW(Addr)) value);
> -	  fixup = elf_ifunc_invoke (DL_FIXUP_VALUE_ADDR (fixup));
> -	  value = (void *) DL_FIXUP_VALUE_CODE_ADDR (fixup);
> -	}
> -
> -#ifdef SHARED
> -      /* Auditing checkpoint: we have a new binding.  Provide the
> -	 auditing libraries the possibility to change the value and
> -	 tell us whether further auditing is wanted.  */
> -      if (__glibc_unlikely (GLRO(dl_naudit) > 0))
> -	{
> -	  const char *strtab = (const char *) D_PTR (result,
> -						     l_info[DT_STRTAB]);
> -	  /* Compute index of the symbol entry in the symbol table of
> -	     the DSO with the definition.  */
> -	  unsigned int ndx = (ref - (ElfW(Sym) *) D_PTR (result,
> -							 l_info[DT_SYMTAB]));
> -
> -	  if (match == NULL)
> -	    match = find_caller_link_map (caller);
> -
> -	  if ((match->l_audit_any_plt | result->l_audit_any_plt) != 0)
> -	    {
> -	      unsigned int altvalue = 0;
> -	      struct audit_ifaces *afct = GLRO(dl_audit);
> -	      /* Synthesize a symbol record where the st_value field is
> -		 the result.  */
> -	      ElfW(Sym) sym = *ref;
> -	      sym.st_value = (ElfW(Addr)) value;
> -
> -	      for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
> -		{
> -		  struct auditstate *match_audit
> -		    = link_map_audit_state (match, cnt);
> -		  struct auditstate *result_audit
> -		    = link_map_audit_state (result, cnt);
> -		  if (afct->symbind != NULL
> -		      && ((match_audit->bindflags & LA_FLG_BINDFROM) != 0
> -			  || ((result_audit->bindflags & LA_FLG_BINDTO)
> -			      != 0)))
> -		    {
> -		      unsigned int flags = altvalue | LA_SYMB_DLSYM;
> -		      uintptr_t new_value
> -			= afct->symbind (&sym, ndx,
> -					 &match_audit->cookie,
> -					 &result_audit->cookie,
> -					 &flags, strtab + ref->st_name);
> -		      if (new_value != (uintptr_t) sym.st_value)
> -			{
> -			  altvalue = LA_SYMB_ALTVALUE;
> -			  sym.st_value = new_value;
> -			}
> -		    }
> -
> -		  afct = afct->next;
> -		}
> -
> -	      value = (void *) sym.st_value;
> -	    }
> -	}
> -#endif
> -
> -      return value;
> +      return _dl_sym_post (result, ref, value, caller, match);
>      }
>  
>    return NULL;
>
  

Patch

diff --git a/elf/dl-sym-post.h b/elf/dl-sym-post.h
new file mode 100644
index 0000000000..4c4f574633
--- /dev/null
+++ b/elf/dl-sym-post.h
@@ -0,0 +1,106 @@ 
+/* Post-processing of a symbol produced by dlsym, dlvsym.
+   Copyright (C) 1999-2020 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
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+
+/* Return the link map containing the caller address.  */
+static struct link_map *
+_dl_sym_find_caller_link_map (ElfW(Addr) caller)
+{
+  struct link_map *l = _dl_find_dso_for_object (caller);
+  if (l != NULL)
+    return l;
+  else
+    /* If the address is not recognized the call comes from the main
+       program (we hope).  */
+    return GL(dl_ns)[LM_ID_BASE]._ns_loaded;
+}
+
+/* Translates RESULT, *REF, VALUE into a symbol address from the point
+   of view of MATCH.  Performs IFUNC resolution and auditing if
+   necessary.  If MATCH is NULL, CALLER is used to determine it.  */
+static void *
+_dl_sym_post (lookup_t result, const ElfW(Sym) *ref, void *value,
+              ElfW(Addr) caller, struct link_map *match)
+{
+  /* Resolve indirect function address.  */
+  if (__glibc_unlikely (ELFW(ST_TYPE) (ref->st_info) == STT_GNU_IFUNC))
+    {
+      DL_FIXUP_VALUE_TYPE fixup
+        = DL_FIXUP_MAKE_VALUE (result, (ElfW(Addr)) value);
+      fixup = elf_ifunc_invoke (DL_FIXUP_VALUE_ADDR (fixup));
+      value = (void *) DL_FIXUP_VALUE_CODE_ADDR (fixup);
+    }
+
+#ifdef SHARED
+  /* Auditing checkpoint: we have a new binding.  Provide the
+     auditing libraries the possibility to change the value and
+     tell us whether further auditing is wanted.  */
+  if (__glibc_unlikely (GLRO(dl_naudit) > 0))
+    {
+      const char *strtab = (const char *) D_PTR (result,
+                                                 l_info[DT_STRTAB]);
+      /* Compute index of the symbol entry in the symbol table of
+         the DSO with the definition.  */
+      unsigned int ndx = (ref - (ElfW(Sym) *) D_PTR (result,
+                                                     l_info[DT_SYMTAB]));
+
+      if (match == NULL)
+        match = _dl_sym_find_caller_link_map (caller);
+
+      if ((match->l_audit_any_plt | result->l_audit_any_plt) != 0)
+        {
+          unsigned int altvalue = 0;
+          struct audit_ifaces *afct = GLRO(dl_audit);
+          /* Synthesize a symbol record where the st_value field is
+             the result.  */
+          ElfW(Sym) sym = *ref;
+          sym.st_value = (ElfW(Addr)) value;
+
+          for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
+            {
+              struct auditstate *match_audit
+                = link_map_audit_state (match, cnt);
+              struct auditstate *result_audit
+                = link_map_audit_state (result, cnt);
+              if (afct->symbind != NULL
+                  && ((match_audit->bindflags & LA_FLG_BINDFROM) != 0
+                      || ((result_audit->bindflags & LA_FLG_BINDTO)
+                          != 0)))
+                {
+                  unsigned int flags = altvalue | LA_SYMB_DLSYM;
+                  uintptr_t new_value
+                    = afct->symbind (&sym, ndx,
+                                     &match_audit->cookie,
+                                     &result_audit->cookie,
+                                     &flags, strtab + ref->st_name);
+                  if (new_value != (uintptr_t) sym.st_value)
+                    {
+                      altvalue = LA_SYMB_ALTVALUE;
+                      sym.st_value = new_value;
+                    }
+                }
+
+              afct = afct->next;
+            }
+
+          value = (void *) sym.st_value;
+        }
+    }
+#endif
+  return value;
+}
diff --git a/elf/dl-sym.c b/elf/dl-sym.c
index b43a50e544..361b926ea9 100644
--- a/elf/dl-sym.c
+++ b/elf/dl-sym.c
@@ -28,6 +28,7 @@ 
 #include <sysdep-cancel.h>
 #include <dl-tls.h>
 #include <dl-irel.h>
+#include <dl-sym-post.h>
 
 
 #ifdef SHARED
@@ -80,19 +81,6 @@  call_dl_lookup (void *ptr)
 					args->flags, NULL);
 }
 
-/* Return the link map containing the caller address.  */
-static inline struct link_map *
-find_caller_link_map (ElfW(Addr) caller)
-{
-  struct link_map *l = _dl_find_dso_for_object (caller);
-  if (l != NULL)
-    return l;
-  else
-    /* If the address is not recognized the call comes from the main
-       program (we hope).  */
-    return GL(dl_ns)[LM_ID_BASE]._ns_loaded;
-}
-
 static void *
 do_sym (void *handle, const char *name, void *who,
 	struct r_found_version *vers, int flags)
@@ -106,7 +94,7 @@  do_sym (void *handle, const char *name, void *who,
 
   if (handle == RTLD_DEFAULT)
     {
-      match = find_caller_link_map (caller);
+      match = _dl_sym_find_caller_link_map (caller);
 
       /* Search the global scope.  We have the simple case where
 	 we look up in the scope of an object which was part of
@@ -140,7 +128,7 @@  do_sym (void *handle, const char *name, void *who,
     }
   else if (handle == RTLD_NEXT)
     {
-      match = find_caller_link_map (caller);
+      match = _dl_sym_find_caller_link_map (caller);
 
       if (__glibc_unlikely (match == GL(dl_ns)[LM_ID_BASE]._ns_loaded))
 	{
@@ -179,73 +167,7 @@  RTLD_NEXT used in code not dynamically loaded"));
 #endif
 	value = DL_SYMBOL_ADDRESS (result, ref);
 
-      /* Resolve indirect function address.  */
-      if (__glibc_unlikely (ELFW(ST_TYPE) (ref->st_info) == STT_GNU_IFUNC))
-	{
-	  DL_FIXUP_VALUE_TYPE fixup
-	    = DL_FIXUP_MAKE_VALUE (result, (ElfW(Addr)) value);
-	  fixup = elf_ifunc_invoke (DL_FIXUP_VALUE_ADDR (fixup));
-	  value = (void *) DL_FIXUP_VALUE_CODE_ADDR (fixup);
-	}
-
-#ifdef SHARED
-      /* Auditing checkpoint: we have a new binding.  Provide the
-	 auditing libraries the possibility to change the value and
-	 tell us whether further auditing is wanted.  */
-      if (__glibc_unlikely (GLRO(dl_naudit) > 0))
-	{
-	  const char *strtab = (const char *) D_PTR (result,
-						     l_info[DT_STRTAB]);
-	  /* Compute index of the symbol entry in the symbol table of
-	     the DSO with the definition.  */
-	  unsigned int ndx = (ref - (ElfW(Sym) *) D_PTR (result,
-							 l_info[DT_SYMTAB]));
-
-	  if (match == NULL)
-	    match = find_caller_link_map (caller);
-
-	  if ((match->l_audit_any_plt | result->l_audit_any_plt) != 0)
-	    {
-	      unsigned int altvalue = 0;
-	      struct audit_ifaces *afct = GLRO(dl_audit);
-	      /* Synthesize a symbol record where the st_value field is
-		 the result.  */
-	      ElfW(Sym) sym = *ref;
-	      sym.st_value = (ElfW(Addr)) value;
-
-	      for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
-		{
-		  struct auditstate *match_audit
-		    = link_map_audit_state (match, cnt);
-		  struct auditstate *result_audit
-		    = link_map_audit_state (result, cnt);
-		  if (afct->symbind != NULL
-		      && ((match_audit->bindflags & LA_FLG_BINDFROM) != 0
-			  || ((result_audit->bindflags & LA_FLG_BINDTO)
-			      != 0)))
-		    {
-		      unsigned int flags = altvalue | LA_SYMB_DLSYM;
-		      uintptr_t new_value
-			= afct->symbind (&sym, ndx,
-					 &match_audit->cookie,
-					 &result_audit->cookie,
-					 &flags, strtab + ref->st_name);
-		      if (new_value != (uintptr_t) sym.st_value)
-			{
-			  altvalue = LA_SYMB_ALTVALUE;
-			  sym.st_value = new_value;
-			}
-		    }
-
-		  afct = afct->next;
-		}
-
-	      value = (void *) sym.st_value;
-	    }
-	}
-#endif
-
-      return value;
+      return _dl_sym_post (result, ref, value, caller, match);
     }
 
   return NULL;