public inbox for libc-alpha@sourceware.org
 help / color / mirror / Atom feed
* [PATCH v2 0/3] Restore support for _r_debug copy relocations & interposition
@ 2022-09-06 10:27 Florian Weimer
  2022-09-06 10:27 ` [PATCH v2 1/3] elf: Introduce separate _r_debug_array variable Florian Weimer
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Florian Weimer @ 2022-09-06 10:27 UTC (permalink / raw)
  To: libc-alpha

The previous version used an optimization for symbol lookups that is not
valid in the presence of interposition.  This version performs a full
unversioned symbol lookup with scope traversal instead.  This way, an
interposing definition in a shared object is picked up as well.

Tested on i686-linux-gnu, built with build-many-glibcs.py.

Thanks,
Florian

Florian Weimer (3):
  elf: Introduce separate _r_debug_array variable
  elf: Introduce _dl_debug_change_state
  elf: Restore support for _r_debug interpositions and copy relocations

 elf/Makefile               |   9 +++
 elf/dl-close.c             |   6 +-
 elf/dl-debug.c             | 144 ++++++++++++++++++++++++++-----------
 elf/dl-load.c              |   6 +-
 elf/dl-open.c              |   5 +-
 elf/rtld.c                 |   9 +--
 elf/tst-dlmopen4-nonpic.c  |   2 +
 elf/tst-dlmopen4-pic.c     |   2 +
 elf/tst-dlmopen4.c         |  22 ++++++
 sysdeps/generic/ldsodefs.h |  20 ++++--
 10 files changed, 165 insertions(+), 60 deletions(-)
 create mode 100644 elf/tst-dlmopen4-nonpic.c
 create mode 100644 elf/tst-dlmopen4-pic.c


base-commit: dbb75513f5cf9285c77c9e55777c5c35b653f890
-- 
2.37.2


^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH v2 1/3] elf: Introduce separate _r_debug_array variable
  2022-09-06 10:27 [PATCH v2 0/3] Restore support for _r_debug copy relocations & interposition Florian Weimer
@ 2022-09-06 10:27 ` Florian Weimer
  2022-09-06 10:27 ` [PATCH v2 2/3] elf: Introduce _dl_debug_change_state Florian Weimer
  2022-09-06 10:27 ` [PATCH v2 3/3] elf: Restore support for _r_debug interpositions and copy relocations Florian Weimer
  2 siblings, 0 replies; 4+ messages in thread
From: Florian Weimer @ 2022-09-06 10:27 UTC (permalink / raw)
  To: libc-alpha

It replaces the ns_debug member of the namespaces.  Previously,
the base namespace had an unused ns_debug member.

This change also fixes a concurrency issue: Now _dl_debug_initialize
only updates r_next of the previous namespace's r_debug after the new
r_debug is initialized, so that only the initialized version is
observed.  (Client code accessing _r_debug will benefit from load
dependency tracking in CPUs even without explicit barriers.)
---
 elf/dl-debug.c             | 91 +++++++++++++++++++++-----------------
 sysdeps/generic/ldsodefs.h |  2 -
 2 files changed, 50 insertions(+), 43 deletions(-)

diff --git a/elf/dl-debug.c b/elf/dl-debug.c
index 538468dc0b..66f9ad375d 100644
--- a/elf/dl-debug.c
+++ b/elf/dl-debug.c
@@ -30,17 +30,37 @@ extern const int verify_link_map_members[(VERIFY_MEMBER (l_addr)
 					  && VERIFY_MEMBER (l_prev))
 					 ? 1 : -1];
 
+#ifdef SHARED
+/* r_debug structs for secondary namespaces.  The first namespace is
+   handled separately because its r_debug structure must overlap with
+   the public _r_debug symbol, so the first array element corresponds
+   to LM_ID_BASE + 1.  See elf/dl-debug-symbols.S.  */
+struct r_debug_extended _r_debug_array[DL_NNS - 1];
+
+/* Return the r_debug object for the namespace NS.  */
+static inline struct r_debug_extended *
+get_rdebug (Lmid_t ns)
+{
+  if (ns == LM_ID_BASE)
+    return &_r_debug_extended;
+  else
+    return  &_r_debug_array[ns - 1];
+}
+#else /* !SHARED */
+static inline struct r_debug_extended *
+get_rdebug (Lmid_t ns)
+{
+  return &_r_debug_extended; /* There is just one namespace.  */
+}
+#endif  /* !SHARED */
+
 /* Update the `r_map' member and return the address of `struct r_debug'
    of the namespace NS. */
 
 struct r_debug *
 _dl_debug_update (Lmid_t ns)
 {
-  struct r_debug_extended *r;
-  if (ns == LM_ID_BASE)
-    r = &_r_debug_extended;
-  else
-    r = &GL(dl_ns)[ns]._ns_debug;
+  struct r_debug_extended *r = get_rdebug (ns);
   if (r->base.r_map == NULL)
     atomic_store_release (&r->base.r_map,
 			  (void *) GL(dl_ns)[ns]._ns_loaded);
@@ -54,34 +74,7 @@ _dl_debug_update (Lmid_t ns)
 struct r_debug *
 _dl_debug_initialize (ElfW(Addr) ldbase, Lmid_t ns)
 {
-  struct r_debug_extended *r, **pp = NULL;
-
-  if (ns == LM_ID_BASE)
-    {
-      r = &_r_debug_extended;
-      /* Initialize r_version to 1.  */
-      if (_r_debug_extended.base.r_version == 0)
-	_r_debug_extended.base.r_version = 1;
-    }
-  else if (DL_NNS > 1)
-    {
-      r = &GL(dl_ns)[ns]._ns_debug;
-      if (r->base.r_brk == 0)
-	{
-	  /* Add the new namespace to the linked list.  After a namespace
-	     is initialized, r_brk becomes non-zero.  A namespace becomes
-	     empty (r_map == NULL) when it is unused.  But it is never
-	     removed from the linked list.  */
-	  struct r_debug_extended *p;
-	  for (pp = &_r_debug_extended.r_next;
-	       (p = *pp) != NULL;
-	       pp = &p->r_next)
-	    ;
-
-	  r->base.r_version = 2;
-	}
-    }
-
+  struct r_debug_extended *r = get_rdebug (ns);
   if (r->base.r_brk == 0)
     {
       /* Tell the debugger where to find the map of loaded objects.
@@ -89,20 +82,36 @@ _dl_debug_initialize (ElfW(Addr) ldbase, Lmid_t ns)
 	 only once.  */
       r->base.r_ldbase = ldbase ?: _r_debug_extended.base.r_ldbase;
       r->base.r_brk = (ElfW(Addr)) &_dl_debug_state;
-      r->r_next = NULL;
+
+#ifdef SHARED
+      /* Add the new namespace to the linked list.  This assumes that
+	 namespaces are allocated in increasing order.  After a
+	 namespace is initialized, r_brk becomes non-zero.  A
+	 namespace becomes empty (r_map == NULL) when it is unused.
+	 But it is never removed from the linked list.  */
+
+      if (ns != LM_ID_BASE)
+	{
+	  r->base.r_version = 2;
+	  if (ns - 1 == LM_ID_BASE)
+	    {
+	      atomic_store_release (&_r_debug_extended.r_next, r);
+	      /* Now there are multiple namespaces.  */
+	      atomic_store_release (&_r_debug_extended.base.r_version, 2);
+	    }
+	  else
+	    /* Update r_debug_extended of the previous namespace.  */
+	    atomic_store_release (&_r_debug_array[ns - 2].r_next, r);
+	}
+      else
+#endif /* SHARED */
+	r->base.r_version = 1;
     }
 
   if (r->base.r_map == NULL)
     atomic_store_release (&r->base.r_map,
 			  (void *) GL(dl_ns)[ns]._ns_loaded);
 
-  if (pp != NULL)
-    {
-      atomic_store_release (pp, r);
-      /* Bump r_version to 2 for the new namespace.  */
-      atomic_store_release (&_r_debug_extended.base.r_version, 2);
-    }
-
   return &r->base;
 }
 
diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
index 6b256b8388..b088f6b1ae 100644
--- a/sysdeps/generic/ldsodefs.h
+++ b/sysdeps/generic/ldsodefs.h
@@ -348,8 +348,6 @@ struct rtld_global
       size_t n_elements;
       void (*free) (void *);
     } _ns_unique_sym_table;
-    /* Keep track of changes to each namespace' list.  */
-    struct r_debug_extended _ns_debug;
   } _dl_ns[DL_NNS];
   /* One higher than index of last used namespace.  */
   EXTERN size_t _dl_nns;
-- 
2.37.2



^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH v2 2/3] elf: Introduce _dl_debug_change_state
  2022-09-06 10:27 [PATCH v2 0/3] Restore support for _r_debug copy relocations & interposition Florian Weimer
  2022-09-06 10:27 ` [PATCH v2 1/3] elf: Introduce separate _r_debug_array variable Florian Weimer
@ 2022-09-06 10:27 ` Florian Weimer
  2022-09-06 10:27 ` [PATCH v2 3/3] elf: Restore support for _r_debug interpositions and copy relocations Florian Weimer
  2 siblings, 0 replies; 4+ messages in thread
From: Florian Weimer @ 2022-09-06 10:27 UTC (permalink / raw)
  To: libc-alpha

It combines updating r_state with the debugger notification.

The change to  _dl_open introduces an additional debugger notification
for dlmopen, but debuggers are expected to ignore it.
---
 elf/dl-close.c             |  6 ++----
 elf/dl-debug.c             |  7 +++++++
 elf/dl-load.c              |  6 ++----
 elf/dl-open.c              |  5 ++---
 elf/rtld.c                 |  6 ++----
 sysdeps/generic/ldsodefs.h | 14 ++++++++++++--
 6 files changed, 27 insertions(+), 17 deletions(-)

diff --git a/elf/dl-close.c b/elf/dl-close.c
index bcd6e206e9..c300999e5b 100644
--- a/elf/dl-close.c
+++ b/elf/dl-close.c
@@ -460,8 +460,7 @@ _dl_close_worker (struct link_map *map, bool force)
 
   /* Notify the debugger we are about to remove some loaded objects.  */
   struct r_debug *r = _dl_debug_update (nsid);
-  r->r_state = RT_DELETE;
-  _dl_debug_state ();
+  _dl_debug_change_state (r, RT_DELETE);
   LIBC_PROBE (unmap_start, 2, nsid, r);
 
   if (unload_global)
@@ -765,8 +764,7 @@ _dl_close_worker (struct link_map *map, bool force)
     while (GL(dl_ns)[GL(dl_nns) - 1]._ns_loaded == NULL);
 
   /* Notify the debugger those objects are finalized and gone.  */
-  r->r_state = RT_CONSISTENT;
-  _dl_debug_state ();
+  _dl_debug_change_state (r, RT_CONSISTENT);
   LIBC_PROBE (unmap_complete, 2, nsid, r);
 
   /* Recheck if we need to retry, release the lock.  */
diff --git a/elf/dl-debug.c b/elf/dl-debug.c
index 66f9ad375d..47961236cf 100644
--- a/elf/dl-debug.c
+++ b/elf/dl-debug.c
@@ -67,6 +67,13 @@ _dl_debug_update (Lmid_t ns)
   return &r->base;
 }
 
+void
+_dl_debug_change_state (struct r_debug *r, int state)
+{
+  atomic_store_release (&r->r_state, state);
+  _dl_debug_state ();
+}
+
 /* Initialize _r_debug_extended for the namespace NS.  LDBASE is the
    run-time load address of the dynamic linker, to be put in
    _r_debug_extended.r_ldbase.  Return the address of _r_debug.  */
diff --git a/elf/dl-load.c b/elf/dl-load.c
index 1ad0868dad..d23ad557fc 100644
--- a/elf/dl-load.c
+++ b/elf/dl-load.c
@@ -987,8 +987,7 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
 
 	  if (make_consistent && r != NULL)
 	    {
-	      r->r_state = RT_CONSISTENT;
-	      _dl_debug_state ();
+	      _dl_debug_change_state (r, RT_CONSISTENT);
 	      LIBC_PROBE (map_failed, 2, nsid, r);
 	    }
 
@@ -1507,8 +1506,7 @@ cannot enable executable stack as shared object requires");
       /* Notify the debugger we have added some objects.  We need to
 	 call _dl_debug_initialize in a static program in case dynamic
 	 linking has not been used before.  */
-      r->r_state = RT_ADD;
-      _dl_debug_state ();
+      _dl_debug_change_state (r, RT_ADD);
       LIBC_PROBE (map_start, 2, nsid, r);
       make_consistent = true;
     }
diff --git a/elf/dl-open.c b/elf/dl-open.c
index 46e8066fd8..b67c2e099f 100644
--- a/elf/dl-open.c
+++ b/elf/dl-open.c
@@ -617,8 +617,7 @@ dl_open_worker_begin (void *a)
 
   /* Notify the debugger all new objects are now ready to go.  */
   struct r_debug *r = _dl_debug_update (args->nsid);
-  r->r_state = RT_CONSISTENT;
-  _dl_debug_state ();
+  _dl_debug_change_state (r, RT_CONSISTENT);
   LIBC_PROBE (map_complete, 3, args->nsid, r, new);
 
   _dl_open_check (new);
@@ -853,7 +852,7 @@ no more namespaces available for dlmopen()"));
       memset (&GL(dl_ns)[nsid], 0, sizeof (GL(dl_ns)[nsid]));
       __rtld_lock_initialize (GL(dl_ns)[nsid]._ns_unique_sym_table.lock);
 
-      _dl_debug_update (nsid)->r_state = RT_CONSISTENT;
+      _dl_debug_change_state (_dl_debug_update (nsid), RT_CONSISTENT);
     }
   /* Never allow loading a DSO in a namespace which is empty.  Such
      direct placements is only causing problems.  Also don't allow
diff --git a/elf/rtld.c b/elf/rtld.c
index 3e771a93d8..ad67d7e4c5 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -1835,8 +1835,7 @@ dl_main (const ElfW(Phdr) *phdr,
   elf_setup_debug_entry (main_map, r);
 
   /* We start adding objects.  */
-  r->r_state = RT_ADD;
-  _dl_debug_state ();
+  _dl_debug_change_state (r, RT_ADD);
   LIBC_PROBE (init_start, 2, LM_ID_BASE, r);
 
   /* Auditing checkpoint: we are ready to signal that the initial map
@@ -2409,8 +2408,7 @@ dl_main (const ElfW(Phdr) *phdr,
   /* Notify the debugger all new objects are now ready to go.  We must re-get
      the address since by now the variable might be in another object.  */
   r = _dl_debug_update (LM_ID_BASE);
-  r->r_state = RT_CONSISTENT;
-  _dl_debug_state ();
+  _dl_debug_change_state (r, RT_CONSISTENT);
   LIBC_PROBE (init_complete, 2, LM_ID_BASE, r);
 
 #if defined USE_LDCONFIG && !defined MAP_COPY
diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
index b088f6b1ae..31fb19c871 100644
--- a/sysdeps/generic/ldsodefs.h
+++ b/sysdeps/generic/ldsodefs.h
@@ -1060,8 +1060,14 @@ extern void _dl_debug_state (void);
 rtld_hidden_proto (_dl_debug_state)
 
 /* Initialize `struct r_debug_extended' for the namespace NS.  LDBASE
-   is the run-time load address of the dynamic linker, to be put in the
-   `r_ldbase' member.  Return the address of the structure.  */
+   is the run-time load address of the dynamic linker, to be put in
+   the `r_ldbase' member.
+
+   This function returns the address of the r_debug structure for the
+   namespace.  This is not merely a convenience or optimization, but
+   it is necessary for the LIBC_PROBE Systemtap/debugger probes to
+   work reliably: direct variable access can create probes that tools
+   cannot consume.  */
 extern struct r_debug *_dl_debug_initialize (ElfW(Addr) ldbase, Lmid_t ns)
      attribute_hidden;
 
@@ -1069,6 +1075,10 @@ extern struct r_debug *_dl_debug_initialize (ElfW(Addr) ldbase, Lmid_t ns)
    of the namespace NS.  */
 extern struct r_debug *_dl_debug_update (Lmid_t ns) attribute_hidden;
 
+/* Updates R->r_state to STATE and notifies the debugger by calling
+   _dl_debug_state.  */
+void _dl_debug_change_state (struct r_debug *r, int state) attribute_hidden;
+
 /* Initialize the basic data structure for the search paths.  SOURCE
    is either "LD_LIBRARY_PATH" or "--library-path".
    GLIBC_HWCAPS_PREPEND adds additional glibc-hwcaps subdirectories to
-- 
2.37.2



^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH v2 3/3] elf: Restore support for _r_debug interpositions and copy relocations
  2022-09-06 10:27 [PATCH v2 0/3] Restore support for _r_debug copy relocations & interposition Florian Weimer
  2022-09-06 10:27 ` [PATCH v2 1/3] elf: Introduce separate _r_debug_array variable Florian Weimer
  2022-09-06 10:27 ` [PATCH v2 2/3] elf: Introduce _dl_debug_change_state Florian Weimer
@ 2022-09-06 10:27 ` Florian Weimer
  2 siblings, 0 replies; 4+ messages in thread
From: Florian Weimer @ 2022-09-06 10:27 UTC (permalink / raw)
  To: libc-alpha

The changes in commit a93d9e03a31ec14405cb3a09aa95413b67067380
("Extend struct r_debug to support multiple namespaces [BZ #15971]")
break the dyninst dynamic instrumentation tool.  It brings its
own definition of _r_debug (rather than a declaration).

Furthermore, it turns out it is rather hard to use the proposed
handshake for accessing _r_debug via DT_DEBUG. If applications want
to access _r_debug, they can do so directly if the relevant code has
been built as PIC.  To protect against harm from accidental copy
relocations due to linker relaxations, this commit restores copy
relocation support by adjusting both copies if interposition or
copy relocations are in play.
---
 elf/Makefile               |  9 +++++++
 elf/dl-debug.c             | 52 +++++++++++++++++++++++++++++++++++---
 elf/rtld.c                 |  3 +++
 elf/tst-dlmopen4-nonpic.c  |  2 ++
 elf/tst-dlmopen4-pic.c     |  2 ++
 elf/tst-dlmopen4.c         | 22 ++++++++++++++++
 sysdeps/generic/ldsodefs.h |  4 +++
 7 files changed, 91 insertions(+), 3 deletions(-)
 create mode 100644 elf/tst-dlmopen4-nonpic.c
 create mode 100644 elf/tst-dlmopen4-pic.c

diff --git a/elf/Makefile b/elf/Makefile
index 008770bfaf..62a3e3e88d 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -408,6 +408,8 @@ tests += \
   tst-dlmopen1 \
   tst-dlmopen3 \
   tst-dlmopen4 \
+  tst-dlmopen4-nonpic \
+  tst-dlmopen4-pic \
   tst-dlmopen-dlerror \
   tst-dlmopen-gethostbyname \
   tst-dlmopen-twice \
@@ -1998,6 +2000,13 @@ $(objpfx)tst-dlmopen3.out: $(objpfx)tst-dlmopen1mod.so
 
 $(objpfx)tst-dlmopen4.out: $(objpfx)tst-dlmopen1mod.so
 
+CFLAGS-tst-dlmopen4-pic.c += -fPIC
+$(objpfx)tst-dlmopen4-pic.out: $(objpfx)tst-dlmopen1mod.so
+
+CFLAGS-tst-dlmopen4-nonpic.c += -fno-pie
+tst-dlmopen4-nonpic-no-pie = yes
+$(objpfx)tst-dlmopen4-nonpic.out: $(objpfx)tst-dlmopen1mod.so
+
 $(objpfx)tst-audit1.out: $(objpfx)tst-auditmod1.so
 tst-audit1-ENV = LD_AUDIT=$(objpfx)tst-auditmod1.so
 
diff --git a/elf/dl-debug.c b/elf/dl-debug.c
index 47961236cf..2762e01c16 100644
--- a/elf/dl-debug.c
+++ b/elf/dl-debug.c
@@ -16,6 +16,7 @@
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
+#include <assert.h>
 #include <ldsodefs.h>
 
 
@@ -37,6 +38,37 @@ extern const int verify_link_map_members[(VERIFY_MEMBER (l_addr)
    to LM_ID_BASE + 1.  See elf/dl-debug-symbols.S.  */
 struct r_debug_extended _r_debug_array[DL_NNS - 1];
 
+/* If not null, pointer to the _r_debug in the main executable.  */
+static struct r_debug *_r_debug_main;
+
+void
+_dl_debug_post_relocate (struct link_map *main_map)
+{
+  /* Perform a full symbol search in all objects, to maintain
+     compatibility if interposed _r_debug definitions.  The lookup
+     cannot faul because there is a definition in ld.so.  */
+  const ElfW(Sym) *sym = NULL;
+  lookup_t result =_dl_lookup_symbol_x ("_r_debug", main_map, &sym,
+					main_map->l_scope, NULL, 0, 0, NULL);
+  assert (sym != NULL);
+  if (sym->st_size >= sizeof (struct r_debug))
+    {
+      struct r_debug *main_r_debug = DL_SYMBOL_ADDRESS (result, sym);
+      if (main_r_debug != &_r_debug_extended.base)
+	{
+	  /* The extended version of the struct is not available in
+	     the main executable because a copy relocation has been
+	     used.  r_map etc. have already been copied as part of the
+	     copy relocation processing.  */
+	  main_r_debug->r_version = 1;
+
+          /* Record that dual updates of the initial link map are
+             required.  */
+          _r_debug_main = main_r_debug;
+	}
+    }
+}
+
 /* Return the r_debug object for the namespace NS.  */
 static inline struct r_debug_extended *
 get_rdebug (Lmid_t ns)
@@ -71,6 +103,11 @@ void
 _dl_debug_change_state (struct r_debug *r, int state)
 {
   atomic_store_release (&r->r_state, state);
+#ifdef SHARED
+  if (r == &_r_debug_extended.base && _r_debug_main != NULL)
+    /* Update the copy-relocation of _r_debug.  */
+    atomic_store_release (&_r_debug_main->r_state, state);
+#endif
   _dl_debug_state ();
 }
 
@@ -103,7 +140,9 @@ _dl_debug_initialize (ElfW(Addr) ldbase, Lmid_t ns)
 	  if (ns - 1 == LM_ID_BASE)
 	    {
 	      atomic_store_release (&_r_debug_extended.r_next, r);
-	      /* Now there are multiple namespaces.  */
+	      /* Now there are multiple namespaces.  Note that this
+		 deliberately does not update the copy in the main
+		 executable (if it exists).  */
 	      atomic_store_release (&_r_debug_extended.base.r_version, 2);
 	    }
 	  else
@@ -116,8 +155,15 @@ _dl_debug_initialize (ElfW(Addr) ldbase, Lmid_t ns)
     }
 
   if (r->base.r_map == NULL)
-    atomic_store_release (&r->base.r_map,
-			  (void *) GL(dl_ns)[ns]._ns_loaded);
+    {
+      struct link_map_public *l = (void *) GL(dl_ns)[ns]._ns_loaded;
+      atomic_store_release (&r->base.r_map, l);
+#ifdef SHARED
+      if (ns == LM_ID_BASE && _r_debug_main != NULL)
+	/* Update the copy-relocation of _r_debug.  */
+	atomic_store_release (&_r_debug_main->r_map, l);
+#endif
+    }
 
   return &r->base;
 }
diff --git a/elf/rtld.c b/elf/rtld.c
index ad67d7e4c5..40aed9d2c4 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -2334,6 +2334,9 @@ dl_main (const ElfW(Phdr) *phdr,
     /* We must prepare the profiling.  */
     _dl_start_profile ();
 
+  /* Update _r_debug if necessary.  */
+  _dl_debug_post_relocate (main_map);
+
   if ((!was_tls_init_tp_called && GL(dl_tls_max_dtv_idx) > 0)
       || count_modids != _dl_count_modids ())
     ++GL(dl_tls_generation);
diff --git a/elf/tst-dlmopen4-nonpic.c b/elf/tst-dlmopen4-nonpic.c
new file mode 100644
index 0000000000..ad4e409953
--- /dev/null
+++ b/elf/tst-dlmopen4-nonpic.c
@@ -0,0 +1,2 @@
+#define BUILD_FOR_NONPIC
+#include "tst-dlmopen4.c"
diff --git a/elf/tst-dlmopen4-pic.c b/elf/tst-dlmopen4-pic.c
new file mode 100644
index 0000000000..919fa85c25
--- /dev/null
+++ b/elf/tst-dlmopen4-pic.c
@@ -0,0 +1,2 @@
+#define BUILD_FOR_PIC
+#include "tst-dlmopen4.c"
diff --git a/elf/tst-dlmopen4.c b/elf/tst-dlmopen4.c
index 8456f89053..6db928950d 100644
--- a/elf/tst-dlmopen4.c
+++ b/elf/tst-dlmopen4.c
@@ -46,6 +46,15 @@ do_test (void)
   TEST_COMPARE (debug->base.r_version, 1);
   TEST_VERIFY_EXIT (debug->r_next == NULL);
 
+#ifdef BUILD_FOR_PIC
+  /* In a PIC build, using _r_debug directly should give us the same
+     object.  */
+  TEST_VERIFY (&_r_debug == &debug->base);
+#endif
+#ifdef BUILD_FOR_NONPIC
+  TEST_COMPARE (_r_debug.r_version, 1);
+#endif
+
   void *h = xdlmopen (LM_ID_NEWLM, "$ORIGIN/tst-dlmopen1mod.so",
 		      RTLD_LAZY);
 
@@ -57,6 +66,19 @@ do_test (void)
   const char *name = basename (debug->r_next->base.r_map->l_name);
   TEST_COMPARE_STRING (name, "tst-dlmopen1mod.so");
 
+#ifdef BUILD_FOR_NONPIC
+  /* If a copy relocation is used, it must be at version 1.  */
+  if (&_r_debug != &debug->base)
+    {
+      TEST_COMPARE (_r_debug.r_version, 1);
+      TEST_COMPARE ((uintptr_t) _r_debug.r_map,
+		    (uintptr_t) debug->base.r_map);
+      TEST_COMPARE (_r_debug.r_brk, debug->base.r_brk);
+      TEST_COMPARE (_r_debug.r_state, debug->base.r_state);
+      TEST_COMPARE (_r_debug.r_ldbase, debug->base.r_ldbase);
+    }
+#endif
+
   xdlclose (h);
 
   return 0;
diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
index 31fb19c871..341f48a7ae 100644
--- a/sysdeps/generic/ldsodefs.h
+++ b/sysdeps/generic/ldsodefs.h
@@ -1071,6 +1071,10 @@ rtld_hidden_proto (_dl_debug_state)
 extern struct r_debug *_dl_debug_initialize (ElfW(Addr) ldbase, Lmid_t ns)
      attribute_hidden;
 
+/* This is called after relocation processing to handle a potential
+   copy relocation for _r_debug.  */
+void _dl_debug_post_relocate (struct link_map *main_map) attribute_hidden;
+
 /* Update the `r_map' member and return the address of `struct r_debug'
    of the namespace NS.  */
 extern struct r_debug *_dl_debug_update (Lmid_t ns) attribute_hidden;
-- 
2.37.2


^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2022-09-06 10:27 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-09-06 10:27 [PATCH v2 0/3] Restore support for _r_debug copy relocations & interposition Florian Weimer
2022-09-06 10:27 ` [PATCH v2 1/3] elf: Introduce separate _r_debug_array variable Florian Weimer
2022-09-06 10:27 ` [PATCH v2 2/3] elf: Introduce _dl_debug_change_state Florian Weimer
2022-09-06 10:27 ` [PATCH v2 3/3] elf: Restore support for _r_debug interpositions and copy relocations Florian Weimer

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).