[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 New
Headers show
Series
  • Avoid malloc symbol interposition in the dynamic loader [BZ #25486]
Related show

Commit Message

Florian Weimer Feb. 8, 2020, 7:01 p.m.
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

-- 
2.24.1

Comments

Carlos O'Donell Feb. 14, 2020, 10:36 p.m. | #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;

> 



-- 
Cheers,
Carlos.

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;