diff mbox series

[v3,15/20] elf: Add main application on main_map l_name

Message ID 20210730194715.881900-16-adhemerval.zanella@linaro.org
State New
Headers show
Series Some rtld-audit fixes | expand

Commit Message

Adhemerval Zanella July 30, 2021, 7:47 p.m. UTC
For the la_objopen() the path listed in link_map->l_name for the main
application binary is empty, even though dladdr() is able to recover the
correct path.

By setting the expected application name on l_name, it allows to
simplify the code to handle the special case and make the API that
return such information (la_objopen(), dladdr() and dlinfo() to have
similar semantic.

Checked on x86_64-linux-gnu.
---
 dlfcn/Makefile          |  4 ++-
 dlfcn/tst-dladdr-self.c | 55 +++++++++++++++++++++++++++++++++++++++++
 elf/dl-addr.c           |  5 ----
 elf/dl-dst.h            |  2 +-
 elf/dl-init.c           |  3 +--
 elf/dl-load.c           |  9 +++++--
 elf/dl-misc.c           |  1 +
 elf/rtld.c              |  6 +----
 elf/tst-audit22.c       |  4 +++
 elf/tst-auditmod22.c    |  8 ++++++
 gmon/gmon.c             | 10 ++++----
 11 files changed, 86 insertions(+), 21 deletions(-)
 create mode 100644 dlfcn/tst-dladdr-self.c
diff mbox series

Patch

diff --git a/dlfcn/Makefile b/dlfcn/Makefile
index 6bbfbb8344..bceb2b2885 100644
--- a/dlfcn/Makefile
+++ b/dlfcn/Makefile
@@ -51,7 +51,7 @@  endif
 ifeq (yes,$(build-shared))
 tests = glrefmain failtest tst-dladdr default errmsg1 tstcxaatexit \
 	bug-dlopen1 bug-dlsym1 tst-dlinfo bug-atexit1 bug-atexit2 \
-	bug-atexit3 tstatexit bug-dl-leaf tst-rec-dlopen
+	bug-atexit3 tstatexit bug-dl-leaf tst-rec-dlopen tst-dladdr-self
 endif
 modules-names = glreflib1 glreflib2 glreflib3 failtestmod defaultmod1 \
 		defaultmod2 errmsg1mod modatexit modcxaatexit \
@@ -143,3 +143,5 @@  $(objpfx)bug-dl-leaf.out: $(objpfx)bug-dl-leaf-lib-cb.so
 $(objpfx)bug-dl-leaf-lib-cb.so: $(objpfx)bug-dl-leaf-lib.so
 
 $(objpfx)tst-rec-dlopen.out: $(objpfx)moddummy1.so $(objpfx)moddummy2.so
+
+LDFLAGS-tst-dladdr-self = -rdynamic
diff --git a/dlfcn/tst-dladdr-self.c b/dlfcn/tst-dladdr-self.c
new file mode 100644
index 0000000000..0eddaf1cd7
--- /dev/null
+++ b/dlfcn/tst-dladdr-self.c
@@ -0,0 +1,55 @@ 
+/* Check dladdr with the reference to own exectuable.
+   Copyright (C) 2021 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/>.  */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <support/check.h>
+#include <support/xdlfcn.h>
+
+void
+test_symbol (void)
+{
+}
+
+static int
+do_test (void)
+{
+  void *handle = xdlopen (NULL, RTLD_NOW);
+  int (*sym)(void) = xdlsym (handle, "test_symbol");
+
+  Dl_info info = { 0 };
+  {
+    int r = dladdr (sym, &info);
+    TEST_VERIFY_EXIT (r != 0);
+  }
+
+  {
+    const char *p = strrchr (info.dli_fname, '/');
+    const char *dli_name = p == NULL ? info.dli_fname : p + 1;
+
+    TEST_COMPARE_STRING (dli_name, "tst-dladdr-self");
+  }
+
+  TEST_COMPARE_STRING (info.dli_sname, "test_symbol");
+  TEST_COMPARE ((uintptr_t) info.dli_saddr, (uintptr_t) test_symbol);
+
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/elf/dl-addr.c b/elf/dl-addr.c
index 3226880d48..c2c93c63ad 100644
--- a/elf/dl-addr.c
+++ b/elf/dl-addr.c
@@ -30,11 +30,6 @@  determine_info (const ElfW(Addr) addr, struct link_map *match, Dl_info *info,
   info->dli_fname = match->l_name;
   info->dli_fbase = (void *) match->l_map_start;
 
-  /* If this is the main program the information is incomplete.  */
-  if (__builtin_expect (match->l_name[0], 'a') == '\0'
-      && match->l_type == lt_executable)
-    info->dli_fname = _dl_argv[0];
-
   const ElfW(Sym) *symtab
     = (const ElfW(Sym) *) D_PTR (match, l_info[DT_SYMTAB]);
   const char *strtab = (const char *) D_PTR (match, l_info[DT_STRTAB]);
diff --git a/elf/dl-dst.h b/elf/dl-dst.h
index 34bbaf65dc..a1e9af5a06 100644
--- a/elf/dl-dst.h
+++ b/elf/dl-dst.h
@@ -44,7 +44,7 @@ 
 	   auditing, in ld.so.  */					      \
 	if ((l)->l_origin == NULL)					      \
 	  {								      \
-	    assert ((l)->l_name[0] == '\0' || IS_RTLD (l));		      \
+	    assert ((l)->l_type == lt_executable || IS_RTLD (l));	      \
 	    (l)->l_origin = _dl_get_origin ();				      \
 	    dst_len = ((l)->l_origin && (l)->l_origin != (char *) -1	      \
 			  ? strlen ((l)->l_origin) : 0);		      \
diff --git a/elf/dl-init.c b/elf/dl-init.c
index f924d26642..9fa8403290 100644
--- a/elf/dl-init.c
+++ b/elf/dl-init.c
@@ -39,8 +39,7 @@  call_init (struct link_map *l, int argc, char **argv, char **env)
   l->l_init_called = 1;
 
   /* Check for object which constructors we do not run here.  */
-  if (__builtin_expect (l->l_name[0], 'a') == '\0'
-      && l->l_type == lt_executable)
+  if (l->l_type == lt_executable)
     return;
 
   /* Print a debug message if wanted.  */
diff --git a/elf/dl-load.c b/elf/dl-load.c
index 8f8971de29..de04332cf3 100644
--- a/elf/dl-load.c
+++ b/elf/dl-load.c
@@ -1990,13 +1990,18 @@  _dl_map_object (struct link_map *loader, const char *name,
   assert (nsid >= 0);
   assert (nsid < GL(dl_nns));
 
+  /* Special case: trying to map itself.  */
+  if (name[0] == '\0')
+    return GL(dl_ns)[nsid]._ns_loaded;
+
   /* Look for this name among those already loaded.  */
   for (l = GL(dl_ns)[nsid]._ns_loaded; l; l = l->l_next)
     {
       /* If the requested name matches the soname of a loaded object,
 	 use that object.  Elide this check for names that have not
-	 yet been opened.  */
-      if (__glibc_unlikely ((l->l_faked | l->l_removed) != 0))
+	 yet been opened or the executable itself.  */
+      if (__glibc_unlikely ((l->l_faked | l->l_removed
+			     || l->l_type == lt_executable) != 0))
 	continue;
       if (!_dl_name_match_p (name, l))
 	{
diff --git a/elf/dl-misc.c b/elf/dl-misc.c
index b256d792c6..b62bbcb8b4 100644
--- a/elf/dl-misc.c
+++ b/elf/dl-misc.c
@@ -338,6 +338,7 @@  rtld_hidden_def (_dl_fatal_printf)
 int
 _dl_name_match_p (const char *name, const struct link_map *map)
 {
+  /* Filter out the main executable.  */
   if (strcmp (name, map->l_name) == 0)
     return 1;
 
diff --git a/elf/rtld.c b/elf/rtld.c
index 04bcab3670..63248c86d0 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -1359,11 +1359,6 @@  dl_main (const ElfW(Phdr) *phdr,
 
       phdr = main_map->l_phdr;
       phnum = main_map->l_phnum;
-      /* We overwrite here a pointer to a malloc()ed string.  But since
-	 the malloc() implementation used at this point is the dummy
-	 implementations which has no real free() function it does not
-	 makes sense to free the old string first.  */
-      main_map->l_name = (char *) "";
       *user_entry = main_map->l_entry;
 
 #ifdef HAVE_AUX_VECTOR
@@ -1426,6 +1421,7 @@  dl_main (const ElfW(Phdr) *phdr,
 	 information for the program.  */
     }
 
+  main_map->l_name = _dl_argv[0];
   main_map->l_map_end = 0;
   main_map->l_text_end = 0;
   /* Perhaps the executable has no PT_LOAD header entries at all.  */
diff --git a/elf/tst-audit22.c b/elf/tst-audit22.c
index c1b301c4cc..7718e3e959 100644
--- a/elf/tst-audit22.c
+++ b/elf/tst-audit22.c
@@ -94,6 +94,7 @@  do_test (int argc, char *argv[])
 
   unsigned long vdso_process = 0;
   unsigned long vdso_audit = 0;
+  bool mainapp_found = false;
 
   FILE *out = fmemopen (result.err.buffer, result.err.length, "r");
   TEST_VERIFY (out != NULL);
@@ -105,9 +106,12 @@  do_test (int argc, char *argv[])
 	vdso_process = parse_address (buffer + strlen ("vdso: "));
       else if (startswith (buffer, "vdso found: "))
 	vdso_audit = parse_address (buffer + strlen ("vdso found: "));
+      else if (startswith (buffer, "mainapp found"))
+	mainapp_found = true;
     }
 
   TEST_COMPARE (vdso_process, vdso_audit);
+  TEST_COMPARE (mainapp_found, true);
 
   free (buffer);
   xfclose (out);
diff --git a/elf/tst-auditmod22.c b/elf/tst-auditmod22.c
index 02275bed57..a4921f35de 100644
--- a/elf/tst-auditmod22.c
+++ b/elf/tst-auditmod22.c
@@ -19,6 +19,7 @@ 
 #include <link.h>
 #include <inttypes.h>
 #include <stdio.h>
+#include <string.h>
 #include <sys/auxv.h>
 
 unsigned int
@@ -30,6 +31,13 @@  la_version (unsigned int version)
 unsigned int
 la_objopen (struct link_map *map, Lmid_t lmid, uintptr_t *cookie)
 {
+  {
+    const char *p = strrchr (map->l_name, '/');
+    const char *l_name = p == NULL ? map->l_name : p + 1;
+    if (strcmp (l_name, "tst-audit22") == 0)
+      fprintf (stderr, "mainapp found\n");
+  }
+
   if (map->l_addr == getauxval (AT_SYSINFO_EHDR))
     fprintf (stderr, "vdso found: %" PRIxPTR "\n", (uintptr_t) map->l_addr);
 
diff --git a/gmon/gmon.c b/gmon/gmon.c
index dee64803ad..cb8327b8e4 100644
--- a/gmon/gmon.c
+++ b/gmon/gmon.c
@@ -48,16 +48,16 @@ 
 
 #ifdef PIC
 # include <link.h>
+# include <ldsodefs.h>
 
 static int
 callback (struct dl_phdr_info *info, size_t size, void *data)
 {
-  if (info->dlpi_name[0] == '\0')
+  if (info->dlpi_name == _dl_argv[0])
     {
-      /* The link map for the executable is created by calling
-	 _dl_new_object with "" as filename.  dl_iterate_phdr
-	 calls the callback function with filename from the
-	 link map as dlpi_name.  */
+      /* The link map l_name for the executable is set to the _dl_argv[0]
+	 after argument processing.  dl_iterate_phdr() calls the callback
+	 function with filename from the link map as dlpi_name.  */
       u_long *load_address = data;
       *load_address = (u_long) info->dlpi_addr;
       return 1;