public inbox for libc-alpha@sourceware.org
 help / color / mirror / Atom feed
* [PATCH v8 0/4] Multiple rtld-audit fixes
@ 2021-12-28 11:50 Adhemerval Zanella
  2021-12-28 11:50 ` [PATCH v8 1/4] elf: Add la_activity during application exit Adhemerval Zanella
                   ` (3 more replies)
  0 siblings, 4 replies; 10+ messages in thread
From: Adhemerval Zanella @ 2021-12-28 11:50 UTC (permalink / raw)
  To: libc-alpha, jma14; +Cc: John Mellor-Crummey, Ben Woodard

This patches fixes some of remaining issues brought by John
Mellor-Crummey [1] while trying to use it along with the HPCToolkit.
This should cover all the issues listed as 'Tier 1' [2] (the aarch64
SVE requires additional work, so it is postpone to 2.36) and also
most of the 'Tier2' issue (BZ#28096 inclusive) which prevents the use
of some glibc function that uses TLS internally on the audit module.

I have checked the patches on x86_64, i686, aarch64, armv7, powerpc64,
powerpc64le, and powerpc.

[1] https://sourceware.org/pipermail/libc-alpha/2021-June/127636.html
[2] https://docs.google.com/document/d/1dVaDBdzySecxQqD6hLLzDrEF18M1UtjDna9gL5BWWI0/edit#
[3] https://sourceware.org/git/?p=glibc.git;a=shortlog;h=refs/heads/azanella/ld-audit-fixes

Changes from v7:
  - Added la_activity tests during application exit.
  - Refactor _dl_allocate_tls_init to not initialize static TLS.
  - Changed sotruss to warn instead of error for bind-now.
  - Added NEWS and changed commit message for aarch64.

Changes from v6:
  - Dropped SVE, main application on main_map l_name, and Run
    constructors if executable has a soname of a dependency patches.
  - Bumped LAV_VERSION to 2 on la_symbind bind-now support.
  - Added extension pointer on aarch64 fix.
  - Moved the refactor patch at the start of the set.
  - Changed _dl_audit_objsearch interface.

Changes from v5:
  - Fixed build with --enable-profiling=yes.
  - Moved la_activity (LA_ACT_ADD) *after* _dl_add_to_namespace_list()
    for BZ#28062 fix.
  - Fixed powerpc64 ELFv1 OPD toc setup for bind-now.
  - Fixed testsuite issues for ia64.
  - Removed LA_SYMB_BINDNOW now that LA_SYMB_NOPLTENTER and
    LA_SYMB_NOPLTEXIT is passed for bind-now.

Changes from v4:
  - Added a fix for constructors if executable has a soname of a
    dependency
  - Rebased against master.

Changes from v3
  - Added a aarch64 SVE RFC patch.
  - Fixed an issue with bind-now fix on powerpc64 ELFv1.
  - Rebased against master.

Changes from v2
  - Refactored rtld-audit code to move common come to dl-audit.c.
  - Issue audit la_objopen() for vDSO.
  - Isseu la_activity during application exit.
  - Issue la_symbind() for bind-now (BZ #23734).
  - Fix runtime linker auditing on aarch64 (BZ #26643)

Changes from v1
  - Fixed -fstack-protector-all tst-auditmod17.
  - Simplify the _dl_call_libc_early_init call the 'Fix audit
    regression' patch.
  - Remove symbind check fr BZ#15333.
  - Added the BZ#28096 fix.

Adhemerval Zanella (3):
  elf: Add la_activity during application exit
  elf: Fix initial-exec TLS access on audit modules (BZ #28096)
  elf: Issue la_symbind for bind-now (BZ #23734)

Ben Woodard (1):
  elf: Fix runtime linker auditing on aarch64 (BZ #26643)

 NEWS                             |   8 ++
 bits/link_lavcurrent.h           |   2 +-
 elf/Makefile                     | 105 ++++++++++++++-
 elf/dl-audit.c                   |  58 +++++----
 elf/dl-fini.c                    |  10 ++
 elf/dl-tls.c                     |  16 ++-
 elf/do-rel.h                     |  57 ++++++--
 elf/rtld.c                       |   3 +-
 elf/sotruss-lib.c                |   7 +
 elf/tst-audit21.c                |  42 ++++++
 elf/tst-audit23.c                | 214 +++++++++++++++++++++++++++++++
 elf/tst-audit23mod.c             |  23 ++++
 elf/tst-audit24a.c               |  36 ++++++
 elf/tst-audit24amod1.c           |  31 +++++
 elf/tst-audit24amod2.c           |  25 ++++
 elf/tst-audit24b.c               |  37 ++++++
 elf/tst-audit24bmod1.c           |  31 +++++
 elf/tst-audit24bmod2.c           |  23 ++++
 elf/tst-audit24c.c               |   2 +
 elf/tst-audit24d.c               |  36 ++++++
 elf/tst-audit24dmod1.c           |  33 +++++
 elf/tst-audit24dmod2.c           |  28 ++++
 elf/tst-audit24dmod3.c           |  31 +++++
 elf/tst-audit24dmod4.c           |  25 ++++
 elf/tst-audit25a.c               | 127 ++++++++++++++++++
 elf/tst-audit25b.c               | 128 ++++++++++++++++++
 elf/tst-audit25mod1.c            |  30 +++++
 elf/tst-audit25mod2.c            |  30 +++++
 elf/tst-audit25mod3.c            |  22 ++++
 elf/tst-audit25mod4.c            |  22 ++++
 elf/tst-auditmod21a.c            |  80 ++++++++++++
 elf/tst-auditmod21b.c            |  22 ++++
 elf/tst-auditmod23.c             |  74 +++++++++++
 elf/tst-auditmod24.h             |  29 +++++
 elf/tst-auditmod24a.c            | 114 ++++++++++++++++
 elf/tst-auditmod24b.c            | 104 +++++++++++++++
 elf/tst-auditmod24c.c            |   3 +
 elf/tst-auditmod24d.c            | 120 +++++++++++++++++
 elf/tst-auditmod25.c             |  79 ++++++++++++
 sysdeps/aarch64/Makefile         |  20 +++
 sysdeps/aarch64/bits/link.h      |  26 ++--
 sysdeps/aarch64/dl-audit-check.h |  28 ++++
 sysdeps/aarch64/dl-link.sym      |   6 +-
 sysdeps/aarch64/dl-trampoline.S  |  97 +++++++++-----
 sysdeps/aarch64/tst-audit26.c    |  37 ++++++
 sysdeps/aarch64/tst-audit26mod.c |  33 +++++
 sysdeps/aarch64/tst-audit26mod.h |  50 ++++++++
 sysdeps/aarch64/tst-audit27.c    |  64 +++++++++
 sysdeps/aarch64/tst-audit27mod.c |  95 ++++++++++++++
 sysdeps/aarch64/tst-audit27mod.h |  67 ++++++++++
 sysdeps/aarch64/tst-auditmod26.c | 103 +++++++++++++++
 sysdeps/aarch64/tst-auditmod27.c | 180 ++++++++++++++++++++++++++
 sysdeps/generic/dl-audit-check.h |  23 ++++
 sysdeps/generic/dl-lookupcfg.h   |   3 +
 sysdeps/generic/ldsodefs.h       |   5 +-
 sysdeps/hppa/dl-lookupcfg.h      |   3 +
 sysdeps/ia64/dl-lookupcfg.h      |   3 +
 sysdeps/powerpc/dl-lookupcfg.h   |  39 ++++++
 58 files changed, 2658 insertions(+), 91 deletions(-)
 create mode 100644 elf/tst-audit21.c
 create mode 100644 elf/tst-audit23.c
 create mode 100644 elf/tst-audit23mod.c
 create mode 100644 elf/tst-audit24a.c
 create mode 100644 elf/tst-audit24amod1.c
 create mode 100644 elf/tst-audit24amod2.c
 create mode 100644 elf/tst-audit24b.c
 create mode 100644 elf/tst-audit24bmod1.c
 create mode 100644 elf/tst-audit24bmod2.c
 create mode 100644 elf/tst-audit24c.c
 create mode 100644 elf/tst-audit24d.c
 create mode 100644 elf/tst-audit24dmod1.c
 create mode 100644 elf/tst-audit24dmod2.c
 create mode 100644 elf/tst-audit24dmod3.c
 create mode 100644 elf/tst-audit24dmod4.c
 create mode 100644 elf/tst-audit25a.c
 create mode 100644 elf/tst-audit25b.c
 create mode 100644 elf/tst-audit25mod1.c
 create mode 100644 elf/tst-audit25mod2.c
 create mode 100644 elf/tst-audit25mod3.c
 create mode 100644 elf/tst-audit25mod4.c
 create mode 100644 elf/tst-auditmod21a.c
 create mode 100644 elf/tst-auditmod21b.c
 create mode 100644 elf/tst-auditmod23.c
 create mode 100644 elf/tst-auditmod24.h
 create mode 100644 elf/tst-auditmod24a.c
 create mode 100644 elf/tst-auditmod24b.c
 create mode 100644 elf/tst-auditmod24c.c
 create mode 100644 elf/tst-auditmod24d.c
 create mode 100644 elf/tst-auditmod25.c
 create mode 100644 sysdeps/aarch64/dl-audit-check.h
 create mode 100644 sysdeps/aarch64/tst-audit26.c
 create mode 100644 sysdeps/aarch64/tst-audit26mod.c
 create mode 100644 sysdeps/aarch64/tst-audit26mod.h
 create mode 100644 sysdeps/aarch64/tst-audit27.c
 create mode 100644 sysdeps/aarch64/tst-audit27mod.c
 create mode 100644 sysdeps/aarch64/tst-audit27mod.h
 create mode 100644 sysdeps/aarch64/tst-auditmod26.c
 create mode 100644 sysdeps/aarch64/tst-auditmod27.c
 create mode 100644 sysdeps/generic/dl-audit-check.h
 create mode 100644 sysdeps/powerpc/dl-lookupcfg.h

-- 
2.32.0


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

* [PATCH v8 1/4] elf: Add la_activity during application exit
  2021-12-28 11:50 [PATCH v8 0/4] Multiple rtld-audit fixes Adhemerval Zanella
@ 2021-12-28 11:50 ` Adhemerval Zanella
  2021-12-28 17:59   ` Jonathon Anderson
  2021-12-28 11:50 ` [PATCH v8 2/4] elf: Fix initial-exec TLS access on audit modules (BZ #28096) Adhemerval Zanella
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 10+ messages in thread
From: Adhemerval Zanella @ 2021-12-28 11:50 UTC (permalink / raw)
  To: libc-alpha, jma14; +Cc: John Mellor-Crummey, Ben Woodard, Florian Weimer

la_activity is not called during application exit, even though
la_objclose is.

Checked on x86_64-linux-gnu, i686-linux-gnu, and aarch64-linux-gnu.

Reviewed-by: Florian Weimer <fweimer@redhat.com>
---
 elf/Makefile         |   8 +-
 elf/dl-fini.c        |  10 ++
 elf/tst-audit23.c    | 214 +++++++++++++++++++++++++++++++++++++++++++
 elf/tst-audit23mod.c |  23 +++++
 elf/tst-auditmod23.c |  74 +++++++++++++++
 5 files changed, 328 insertions(+), 1 deletion(-)
 create mode 100644 elf/tst-audit23.c
 create mode 100644 elf/tst-audit23mod.c
 create mode 100644 elf/tst-auditmod23.c

diff --git a/elf/Makefile b/elf/Makefile
index d920586701..861c351510 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -234,7 +234,7 @@ tests += restest1 preloadtest loadfail multiload origtest resolvfail \
 	 tst-audit19b \
 	 tst-audit20 \
 	 tst-audit22 \
-	 tst-rtld-run-static \
+	 tst-audit23 \
 #	 reldep9
 tests-internal += loadtest unload unload2 circleload1 \
 	 neededtest neededtest2 neededtest3 neededtest4 \
@@ -386,6 +386,8 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \
 		tst-audit19bmod \
 		tst-auditmod20 \
 		tst-auditmod22 \
+		tst-auditmod23 \
+		tst-audit23mod \
 
 # Most modules build with _ISOMAC defined, but those filtered out
 # depend on internal headers.
@@ -1604,6 +1606,10 @@ tst-audit20-ENV = LD_AUDIT=$(objpfx)tst-auditmod20.so
 $(objpfx)tst-audit22.out: $(objpfx)tst-auditmod22.so
 tst-audit22-ARGS = -- $(host-test-program-cmd)
 
+$(objpfx)tst-audit23.out: $(objpfx)tst-auditmod23.so \
+			  $(objpfx)tst-audit23mod.so
+tst-audit23-ARGS = -- $(host-test-program-cmd)
+
 # tst-sonamemove links against an older implementation of the library.
 LDFLAGS-tst-sonamemove-linkmod1.so = \
   -Wl,--version-script=tst-sonamemove-linkmod1.map \
diff --git a/elf/dl-fini.c b/elf/dl-fini.c
index b789cfb9f2..a955d0e207 100644
--- a/elf/dl-fini.c
+++ b/elf/dl-fini.c
@@ -64,6 +64,11 @@ _dl_fini (void)
 	__rtld_lock_unlock_recursive (GL(dl_load_lock));
       else
 	{
+#ifdef SHARED
+	  /* Auditing checkpoint: we will start deleting objects.  */
+	  _dl_audit_activity_nsid (ns, LA_ACT_DELETE);
+#endif
+
 	  /* Now we can allocate an array to hold all the pointers and
 	     copy the pointers in.  */
 	  struct link_map *maps[nloaded];
@@ -153,6 +158,11 @@ _dl_fini (void)
 	      /* Correct the previous increment.  */
 	      --l->l_direct_opencount;
 	    }
+
+#ifdef SHARED
+	  /* Auditing checkpoint: we will start deleting objects.  */
+	  _dl_audit_activity_nsid (ns, LA_ACT_CONSISTENT);
+#endif
 	}
     }
 
diff --git a/elf/tst-audit23.c b/elf/tst-audit23.c
new file mode 100644
index 0000000000..1c2194f1a8
--- /dev/null
+++ b/elf/tst-audit23.c
@@ -0,0 +1,214 @@
+/* Check DT_AUDIT la_objopen and la_objclose for all objects.
+   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 <errno.h>
+#include <getopt.h>
+#include <link.h>
+#include <limits.h>
+#include <inttypes.h>
+#include <gnu/lib-names.h>
+#include <string.h>
+#include <stdlib.h>
+#include <support/capture_subprocess.h>
+#include <support/check.h>
+#include <support/xstdio.h>
+#include <support/xdlfcn.h>
+#include <support/support.h>
+
+static int restart;
+#define CMDLINE_OPTIONS \
+  { "restart", no_argument, &restart, 1 },
+
+static int
+handle_restart (void)
+{
+  xdlopen ("tst-audit23mod.so", RTLD_NOW);
+  xdlmopen (LM_ID_NEWLM, LIBC_SO, RTLD_NOW);
+
+  return 0;
+}
+
+static inline bool
+startswith (const char *str, const char *pre)
+{
+  size_t lenpre = strlen (pre);
+  size_t lenstr = strlen (str);
+  return lenstr >= lenpre && memcmp (pre, str, lenpre) == 0;
+}
+
+static inline bool
+is_vdso (const char *str)
+{
+  return startswith (str, "linux-gate")
+	 || startswith (str, "linux-vdso");
+}
+
+static int
+do_test (int argc, char *argv[])
+{
+  /* We must have either:
+     - One our fource parameters left if called initially:
+       + path to ld.so         optional
+       + "--library-path"      optional
+       + the library path      optional
+       + the application name  */
+  if (restart)
+    return handle_restart ();
+
+  char *spargv[9];
+  int i = 0;
+  for (; i < argc - 1; i++)
+    spargv[i] = argv[i + 1];
+  spargv[i++] = (char *) "--direct";
+  spargv[i++] = (char *) "--restart";
+  spargv[i] = NULL;
+
+  setenv ("LD_AUDIT", "tst-auditmod23.so", 0);
+  struct support_capture_subprocess result
+    = support_capture_subprogram (spargv[0], spargv);
+  support_capture_subprocess_check (&result, "tst-audit22", 0, sc_allow_stderr);
+
+  /* The expected la_objopen/la_objclose:
+     1. executable
+     2. loader
+     3. libc.so
+     4. tst-audit23mod.so
+     5. libc.so (LM_ID_NEWLM).
+     6. vdso (optional and ignored).  */
+  enum { max_objs = 6 };
+  struct la_obj_t
+  {
+    char *lname;
+    uintptr_t laddr;
+    Lmid_t lmid;
+    bool closed;
+  } objs[max_objs] = { [0 ... max_objs-1] = { .closed = false } };
+  size_t nobjs = 0;
+
+  /* The expected namespaces are one for the audit module and another for
+     the application.  */
+  enum { max_ns = 2 };
+  uintptr_t acts[max_ns];
+  size_t nacts = 0;
+  int last_act = -1;
+  uintptr_t last_act_cookie = -1;
+
+  FILE *out = fmemopen (result.err.buffer, result.err.length, "r");
+  TEST_VERIFY (out != NULL);
+  char *buffer = NULL;
+  size_t buffer_length = 0;
+  while (xgetline (&buffer, &buffer_length, out))
+    {
+      printf ("%s", buffer);
+      if (startswith (buffer, "la_activity: "))
+	{
+	  uintptr_t cookie;
+	  int r = sscanf (buffer + strlen ("la_activity: "),
+			  "%d %"SCNxPTR"", &last_act, &cookie);
+	  TEST_COMPARE (r, 2);
+	  /* The cookie identifies the object at the head of the link map,
+	     so we only add a new namespace if it changes from previous
+	     one.  */
+	  if (last_act == LA_ACT_ADD && acts[nacts - 1] != cookie)
+	    acts[nacts++] = cookie;
+	  /* The LA_ACT_DELETE is called in the reverse order of
+	     LA_ACT_ADD.  */
+	  else if (last_act == LA_ACT_DELETE && cookie != last_act_cookie)
+	    {
+	      last_act_cookie = acts[--nacts];
+	      TEST_COMPARE (acts[nacts], cookie);
+	      acts[nacts] = 0;
+	    }
+	}
+      else if (startswith (buffer, "la_objopen: "))
+	{
+	  char *lname;
+	  uintptr_t laddr;
+	  Lmid_t lmid;
+	  uintptr_t cookie;
+	  int r = sscanf (buffer + strlen ("la_objopen: "),
+			  "%"SCNxPTR"  %ms %"SCNxPTR" %ld", &cookie, &lname,
+			  &laddr, &lmid);
+	  TEST_COMPARE (r, 4);
+
+	  /* la_objclose is not triggered by vDSO because glibc does not
+	     unload it.  */
+	  if (is_vdso (lname))
+	    continue;
+	  if (nobjs == max_objs)
+	    FAIL_EXIT1 ("non expected la_objopen: %s %"PRIxPTR" %ld",
+			lname, laddr, lmid);
+	  objs[nobjs].lname = lname;
+	  objs[nobjs].laddr = laddr;
+	  objs[nobjs].lmid = lmid;
+	  objs[nobjs].closed = false;
+	  nobjs++;
+	}
+      else if (startswith (buffer, "la_objclose: "))
+	{
+	  char *lname;
+	  uintptr_t laddr;
+	  Lmid_t lmid;
+	  uintptr_t cookie;
+	  int r = sscanf (buffer + strlen ("la_objclose: "),
+			  "%"SCNxPTR" %ms %"SCNxPTR" %ld", &cookie, &lname,
+			  &laddr, &lmid);
+	  TEST_COMPARE (r, 4);
+
+	  for (size_t i = 0; i < nobjs; i++)
+	    {
+	      if (strcmp (lname, objs[i].lname) == 0 && lmid == objs[i].lmid)
+		{
+		  TEST_COMPARE (objs[i].closed, false);
+		  objs[i].closed = true;
+		  break;
+		}
+	    }
+
+	  /* la_objclose should be called after la_activity(LA_ACT_DELETE) for
+	     the closed object's namespace.  */
+	  TEST_COMPARE (last_act, LA_ACT_DELETE);
+	  if (last_act_cookie != 0)
+	    {
+	      TEST_COMPARE (last_act_cookie, cookie);
+	      last_act_cookie = 0;
+	    }
+	}
+    }
+
+  for (size_t i = 0; i < nobjs; i++)
+    {
+      TEST_COMPARE (objs[i].closed, true);
+      free (objs[i].lname);
+    }
+
+  /* la_activity(LA_ACT_CONSISTENT) should be the last callback received for
+     every namespace.  */
+  TEST_COMPARE (last_act, LA_ACT_CONSISTENT);
+  /* Sanity check to check if all LA_ACT_DELETE are matched with
+     la_objclose.  */
+  TEST_COMPARE (last_act_cookie, 0);
+
+  free (buffer);
+  xfclose (out);
+
+  return 0;
+}
+
+#define TEST_FUNCTION_ARGV do_test
+#include <support/test-driver.c>
diff --git a/elf/tst-audit23mod.c b/elf/tst-audit23mod.c
new file mode 100644
index 0000000000..4ca66cf772
--- /dev/null
+++ b/elf/tst-audit23mod.c
@@ -0,0 +1,23 @@
+/* Extra modules for tst-audit23
+   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/>.  */
+
+int
+foo (void)
+{
+  return 0;
+}
diff --git a/elf/tst-auditmod23.c b/elf/tst-auditmod23.c
new file mode 100644
index 0000000000..7a6d24ee80
--- /dev/null
+++ b/elf/tst-auditmod23.c
@@ -0,0 +1,74 @@
+/* Audit modules loaded by tst-audit23.
+   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 <link.h>
+#include <inttypes.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/auxv.h>
+
+unsigned int
+la_version (unsigned int version)
+{
+  return LAV_CURRENT;
+}
+
+struct map_desc_t
+{
+  char *lname;
+  uintptr_t laddr;
+  Lmid_t lmid;
+};
+
+void
+la_activity (uintptr_t *cookie, unsigned int flag)
+{
+  fprintf (stderr, "%s: %d %"PRIxPTR"\n", __func__, flag, (uintptr_t) cookie);
+}
+
+unsigned int
+la_objopen (struct link_map *map, Lmid_t lmid, uintptr_t *cookie)
+{
+  const char *l_name = map->l_name[0] == '\0' ? "mainapp" : map->l_name;
+  fprintf (stderr, "%s: %"PRIxPTR" %s %"PRIxPTR" %ld\n", __func__,
+	   (uintptr_t) cookie, l_name, map->l_addr, lmid);
+
+  struct map_desc_t *map_desc = malloc (sizeof (struct map_desc_t));
+  if (map_desc == NULL)
+    abort ();
+
+  map_desc->lname = strdup (l_name);
+  map_desc->laddr = map->l_addr;
+  map_desc->lmid = lmid;
+
+  *cookie = (uintptr_t) map_desc;
+
+  return 0;
+}
+
+unsigned int
+la_objclose (uintptr_t *cookie)
+{
+  struct map_desc_t *map_desc = (struct map_desc_t *) *cookie;
+  fprintf (stderr, "%s: %"PRIxPTR" %s %"PRIxPTR" %ld\n", __func__,
+	   (uintptr_t) cookie, map_desc->lname, map_desc->laddr,
+	   map_desc->lmid);
+
+  return 0;
+}
-- 
2.32.0


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

* [PATCH v8 2/4] elf: Fix initial-exec TLS access on audit modules (BZ #28096)
  2021-12-28 11:50 [PATCH v8 0/4] Multiple rtld-audit fixes Adhemerval Zanella
  2021-12-28 11:50 ` [PATCH v8 1/4] elf: Add la_activity during application exit Adhemerval Zanella
@ 2021-12-28 11:50 ` Adhemerval Zanella
  2021-12-31 12:25   ` Adhemerval Zanella
  2021-12-28 11:50 ` [PATCH v8 3/4] elf: Issue la_symbind for bind-now (BZ #23734) Adhemerval Zanella
  2021-12-28 11:50 ` [PATCH v8 4/4] elf: Fix runtime linker auditing on aarch64 (BZ #26643) Adhemerval Zanella
  3 siblings, 1 reply; 10+ messages in thread
From: Adhemerval Zanella @ 2021-12-28 11:50 UTC (permalink / raw)
  To: libc-alpha, jma14; +Cc: John Mellor-Crummey, Ben Woodard

For audit modules or dependencies with initial-exec TLS, we can not
set the initial TLS image on default loader initialization because it
would already be set by the audit setup.  However, subsequent thread
creation would need to follow the default behaviour.

This patch fixes by initializing the TLS arena only for base
namespace (LM_ID_BASE).

Checked on x86_64-linux-gnu, i686-linux-gnu, and aarch64-linux-gnu.
---
 elf/Makefile          |  8 +++++
 elf/dl-tls.c          | 16 ++++++---
 elf/tst-audit21.c     | 42 +++++++++++++++++++++++
 elf/tst-auditmod21a.c | 80 +++++++++++++++++++++++++++++++++++++++++++
 elf/tst-auditmod21b.c | 22 ++++++++++++
 5 files changed, 164 insertions(+), 4 deletions(-)
 create mode 100644 elf/tst-audit21.c
 create mode 100644 elf/tst-auditmod21a.c
 create mode 100644 elf/tst-auditmod21b.c

diff --git a/elf/Makefile b/elf/Makefile
index 861c351510..3a521ae89e 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -233,6 +233,7 @@ tests += restest1 preloadtest loadfail multiload origtest resolvfail \
 	 tst-audit18 \
 	 tst-audit19b \
 	 tst-audit20 \
+	 tst-audit21 \
 	 tst-audit22 \
 	 tst-audit23 \
 #	 reldep9
@@ -385,6 +386,8 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \
 		tst-auditmod19b \
 		tst-audit19bmod \
 		tst-auditmod20 \
+		tst-auditmod21a \
+		tst-auditmod21b \
 		tst-auditmod22 \
 		tst-auditmod23 \
 		tst-audit23mod \
@@ -1603,6 +1606,11 @@ tst-audit19b-ARGS = -- $(host-test-program-cmd)
 $(objpfx)tst-audit20.out: $(objpfx)tst-auditmod20.so
 tst-audit20-ENV = LD_AUDIT=$(objpfx)tst-auditmod20.so
 
+$(objpfx)tst-audit21: $(shared-thread-library)
+$(objpfx)tst-audit21.out: $(objpfx)tst-auditmod21a.so
+$(objpfx)tst-auditmod21a.so: $(objpfx)tst-auditmod21b.so
+tst-audit21-ENV = LD_AUDIT=$(objpfx)tst-auditmod21a.so
+
 $(objpfx)tst-audit22.out: $(objpfx)tst-auditmod22.so
 tst-audit22-ARGS = -- $(host-test-program-cmd)
 
diff --git a/elf/dl-tls.c b/elf/dl-tls.c
index 273f60f233..c57fc13be6 100644
--- a/elf/dl-tls.c
+++ b/elf/dl-tls.c
@@ -593,10 +593,18 @@ _dl_allocate_tls_init (void *result)
 	     some platforms use in static programs requires it.  */
 	  dtv[map->l_tls_modid].pointer.val = dest;
 
-	  /* Copy the initialization image and clear the BSS part.  */
-	  memset (__mempcpy (dest, map->l_tls_initimage,
-			     map->l_tls_initimage_size), '\0',
-		  map->l_tls_blocksize - map->l_tls_initimage_size);
+	  /* Copy the initialization image and clear the BSS part.  For
+	     audit modules or depedencies with initial-exec TLS, we can not
+	     set the initial TLS image on default loader initialization
+	     because it would already be set by the audit setup.  However,
+	     subsequent thread creation would need to follow the default
+	     behaviour.   */
+	  if (__glibc_likely (map->l_ns == LM_ID_BASE))
+	    memset (__mempcpy (dest, map->l_tls_initimage,
+			       map->l_tls_initimage_size), '\0',
+		    map->l_tls_blocksize - map->l_tls_initimage_size);
+	  //else
+	  //  map->l_dont_set_tls_static = 0;
 	}
 
       total += cnt;
diff --git a/elf/tst-audit21.c b/elf/tst-audit21.c
new file mode 100644
index 0000000000..307cb6fc3b
--- /dev/null
+++ b/elf/tst-audit21.c
@@ -0,0 +1,42 @@
+/* Check DT_AUDIT with static TLS.
+   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 <ctype.h>
+#include <support/xthread.h>
+#include <support/check.h>
+
+static volatile __thread int out __attribute__ ((tls_model ("initial-exec")));
+
+static void *
+tf (void *arg)
+{
+  TEST_COMPARE (out, 0);
+  out = isspace (' ');
+  return NULL;
+}
+
+int main (int argc, char *argv[])
+{
+  TEST_COMPARE (out, 0);
+  out = isspace (' ');
+
+  pthread_t t = xpthread_create (NULL, tf, NULL);
+  xpthread_join (t);
+
+  return 0;
+}
diff --git a/elf/tst-auditmod21a.c b/elf/tst-auditmod21a.c
new file mode 100644
index 0000000000..f00470e105
--- /dev/null
+++ b/elf/tst-auditmod21a.c
@@ -0,0 +1,80 @@
+/* Check DT_AUDIT with static TLS.
+   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 <ctype.h>
+#include <stdlib.h>
+#include <link.h>
+
+#define tls_ie __attribute__ ((tls_model ("initial-exec")))
+
+__thread int tls_var0 tls_ie;
+__thread int tls_var1 tls_ie = 0x10;
+
+/* Defined at tst-auditmod21b.so  */
+extern __thread int tls_var2;
+extern __thread int tls_var3;
+
+static volatile int out;
+
+static void
+call_libc (void)
+{
+  /* isspace access the initial-exec glibc TLS variables, which are
+     setup in glibc initialization.  */
+  out = isspace (' ');
+}
+
+unsigned int
+la_version (unsigned int v)
+{
+  tls_var0 = 0x1;
+  if (tls_var1 != 0x10)
+    abort ();
+  tls_var1 = 0x20;
+
+  tls_var2 = 0x2;
+  if (tls_var3 != 0x20)
+    abort ();
+  tls_var3 = 0x40;
+
+  call_libc ();
+
+  return LAV_CURRENT;
+}
+
+unsigned int
+la_objopen (struct link_map* map, Lmid_t lmid, uintptr_t* cookie)
+{
+  call_libc ();
+  *cookie = (uintptr_t) map;
+  return 0;
+}
+
+void
+la_activity (uintptr_t* cookie, unsigned int flag)
+{
+  if (tls_var0 != 0x1 || tls_var1 != 0x20)
+    abort ();
+  call_libc ();
+}
+
+void
+la_preinit (uintptr_t* cookie)
+{
+  call_libc ();
+}
diff --git a/elf/tst-auditmod21b.c b/elf/tst-auditmod21b.c
new file mode 100644
index 0000000000..550f858b1d
--- /dev/null
+++ b/elf/tst-auditmod21b.c
@@ -0,0 +1,22 @@
+/* Check DT_AUDIT with static TLS.
+   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/>.  */
+
+#define tls_ie __attribute__ ((tls_model ("initial-exec")))
+
+__thread int tls_var2 tls_ie;
+__thread int tls_var3 tls_ie = 0x20;
-- 
2.32.0


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

* [PATCH v8 3/4] elf: Issue la_symbind for bind-now (BZ #23734)
  2021-12-28 11:50 [PATCH v8 0/4] Multiple rtld-audit fixes Adhemerval Zanella
  2021-12-28 11:50 ` [PATCH v8 1/4] elf: Add la_activity during application exit Adhemerval Zanella
  2021-12-28 11:50 ` [PATCH v8 2/4] elf: Fix initial-exec TLS access on audit modules (BZ #28096) Adhemerval Zanella
@ 2021-12-28 11:50 ` Adhemerval Zanella
  2021-12-28 11:50 ` [PATCH v8 4/4] elf: Fix runtime linker auditing on aarch64 (BZ #26643) Adhemerval Zanella
  3 siblings, 0 replies; 10+ messages in thread
From: Adhemerval Zanella @ 2021-12-28 11:50 UTC (permalink / raw)
  To: libc-alpha, jma14; +Cc: John Mellor-Crummey, Ben Woodard

The audit symbind callback is not called for binaries built with
-Wl,-z,now or when LD_BIND_NOW=1 is used, nor the PLT tracking callbacks
(plt_enter and plt_exit) since this will would change the expected
program semantic (where no PTL is expected) and would incur in
performance implications (such as for BZ#15533).

LAV_CURRENT is also bumped to indicate the audit ABI change (where
la_symbind flags are set by the loader to indicate no possible PTL
trace).

To handle powerpc64 ELFv1 function descriptor, _dl_audit_symbind
requires to know whether bind-now is used so the symbol value is
updated to function text segment instead of the OPD (for lazy binding
this is done by PPC64_LOAD_FUNCPTR on _dl_runtime_resolve).

Checked on x86_64-linux-gnu, i686-linux-gnu, aarch64-linux-gnu,
powerpc64-linux-gnu.
---
 NEWS                           |   4 ++
 bits/link_lavcurrent.h         |   2 +-
 elf/Makefile                   |  89 ++++++++++++++++++++++-
 elf/dl-audit.c                 |  58 +++++++++------
 elf/do-rel.h                   |  57 +++++++++++----
 elf/sotruss-lib.c              |   7 ++
 elf/tst-audit24a.c             |  36 ++++++++++
 elf/tst-audit24amod1.c         |  31 ++++++++
 elf/tst-audit24amod2.c         |  25 +++++++
 elf/tst-audit24b.c             |  37 ++++++++++
 elf/tst-audit24bmod1.c         |  31 ++++++++
 elf/tst-audit24bmod2.c         |  23 ++++++
 elf/tst-audit24c.c             |   2 +
 elf/tst-audit24d.c             |  36 ++++++++++
 elf/tst-audit24dmod1.c         |  33 +++++++++
 elf/tst-audit24dmod2.c         |  28 ++++++++
 elf/tst-audit24dmod3.c         |  31 ++++++++
 elf/tst-audit24dmod4.c         |  25 +++++++
 elf/tst-audit25a.c             | 127 ++++++++++++++++++++++++++++++++
 elf/tst-audit25b.c             | 128 +++++++++++++++++++++++++++++++++
 elf/tst-audit25mod1.c          |  30 ++++++++
 elf/tst-audit25mod2.c          |  30 ++++++++
 elf/tst-audit25mod3.c          |  22 ++++++
 elf/tst-audit25mod4.c          |  22 ++++++
 elf/tst-auditmod24.h           |  29 ++++++++
 elf/tst-auditmod24a.c          | 114 +++++++++++++++++++++++++++++
 elf/tst-auditmod24b.c          | 104 +++++++++++++++++++++++++++
 elf/tst-auditmod24c.c          |   3 +
 elf/tst-auditmod24d.c          | 120 +++++++++++++++++++++++++++++++
 elf/tst-auditmod25.c           |  79 ++++++++++++++++++++
 sysdeps/generic/dl-lookupcfg.h |   3 +
 sysdeps/generic/ldsodefs.h     |   5 +-
 sysdeps/hppa/dl-lookupcfg.h    |   3 +
 sysdeps/ia64/dl-lookupcfg.h    |   3 +
 sysdeps/powerpc/dl-lookupcfg.h |  39 ++++++++++
 35 files changed, 1377 insertions(+), 39 deletions(-)
 create mode 100644 elf/tst-audit24a.c
 create mode 100644 elf/tst-audit24amod1.c
 create mode 100644 elf/tst-audit24amod2.c
 create mode 100644 elf/tst-audit24b.c
 create mode 100644 elf/tst-audit24bmod1.c
 create mode 100644 elf/tst-audit24bmod2.c
 create mode 100644 elf/tst-audit24c.c
 create mode 100644 elf/tst-audit24d.c
 create mode 100644 elf/tst-audit24dmod1.c
 create mode 100644 elf/tst-audit24dmod2.c
 create mode 100644 elf/tst-audit24dmod3.c
 create mode 100644 elf/tst-audit24dmod4.c
 create mode 100644 elf/tst-audit25a.c
 create mode 100644 elf/tst-audit25b.c
 create mode 100644 elf/tst-audit25mod1.c
 create mode 100644 elf/tst-audit25mod2.c
 create mode 100644 elf/tst-audit25mod3.c
 create mode 100644 elf/tst-audit25mod4.c
 create mode 100644 elf/tst-auditmod24.h
 create mode 100644 elf/tst-auditmod24a.c
 create mode 100644 elf/tst-auditmod24b.c
 create mode 100644 elf/tst-auditmod24c.c
 create mode 100644 elf/tst-auditmod24d.c
 create mode 100644 elf/tst-auditmod25.c
 create mode 100644 sysdeps/powerpc/dl-lookupcfg.h

diff --git a/NEWS b/NEWS
index ed8ac0d0df..28e8564be9 100644
--- a/NEWS
+++ b/NEWS
@@ -122,6 +122,10 @@ Deprecated and removed features, and other changes affecting compatibility:
   configuration script now automatically detects static-pie support in the
   toolchain and architecture and enables it if available.
 
+* The audit module interface version LAV_CURRENT is increased to enable
+  proper bind-now support.  The loader now advertise on the la_symbind
+  flags that PLT trace is not possible.
+
 Changes to build and runtime requirements:
 
   [Add changes to build and runtime requirements here]
diff --git a/bits/link_lavcurrent.h b/bits/link_lavcurrent.h
index 44fbea1e80..c48835d12b 100644
--- a/bits/link_lavcurrent.h
+++ b/bits/link_lavcurrent.h
@@ -22,4 +22,4 @@
 #endif
 
 /* Version numbers for la_version handshake interface.  */
-#define LAV_CURRENT	1
+#define LAV_CURRENT	2
diff --git a/elf/Makefile b/elf/Makefile
index 3a521ae89e..7bd3d05a82 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -236,6 +236,12 @@ tests += restest1 preloadtest loadfail multiload origtest resolvfail \
 	 tst-audit21 \
 	 tst-audit22 \
 	 tst-audit23 \
+	 tst-audit24a \
+	 tst-audit24b \
+	 tst-audit24c \
+	 tst-audit24d \
+	 tst-audit25a \
+	 tst-audit25b \
 #	 reldep9
 tests-internal += loadtest unload unload2 circleload1 \
 	 neededtest neededtest2 neededtest3 neededtest4 \
@@ -391,6 +397,23 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \
 		tst-auditmod22 \
 		tst-auditmod23 \
 		tst-audit23mod \
+		tst-auditmod24a \
+		tst-audit24amod1 \
+		tst-audit24amod2 \
+		tst-auditmod24b \
+		tst-audit24bmod1 \
+		tst-audit24bmod2 \
+		tst-auditmod24c \
+		tst-auditmod24d \
+		tst-audit24dmod1 \
+		tst-audit24dmod2 \
+		tst-audit24dmod3 \
+		tst-audit24dmod4 \
+		tst-auditmod25 \
+		tst-audit25mod1 \
+		tst-audit25mod2 \
+		tst-audit25mod3 \
+		tst-audit25mod4 \
 
 # Most modules build with _ISOMAC defined, but those filtered out
 # depend on internal headers.
@@ -450,7 +473,8 @@ extra-test-objs += $(addsuffix .os,$(strip $(modules-names)))
 
 # filtmod1.so, tst-big-note-lib.so, tst-ro-dynamic-mod.so have special
 # rules.
-modules-names-nobuild := filtmod1 tst-big-note-lib tst-ro-dynamic-mod
+modules-names-nobuild := filtmod1 tst-big-note-lib tst-ro-dynamic-mod \
+			 tst-audit24bmod1 tst-audit24bmod2.so
 
 tests += $(tests-static)
 
@@ -1618,6 +1642,69 @@ $(objpfx)tst-audit23.out: $(objpfx)tst-auditmod23.so \
 			  $(objpfx)tst-audit23mod.so
 tst-audit23-ARGS = -- $(host-test-program-cmd)
 
+$(objpfx)tst-audit24a.out: $(objpfx)tst-auditmod24a.so
+$(objpfx)tst-audit24a: $(objpfx)tst-audit24amod1.so \
+		       $(objpfx)tst-audit24amod2.so
+tst-audit24a-ENV = LD_AUDIT=$(objpfx)tst-auditmod24a.so
+LDFLAGS-tst-audit24a = -Wl,-z,now
+
+$(objpfx)tst-audit24b.out: $(objpfx)tst-auditmod24b.so
+$(objpfx)tst-audit24b: $(objpfx)tst-audit24bmod1.so \
+		       $(objpfx)tst-audit24bmod2.so
+$(objpfx)tst-audit24bmod1: $(objpfx)tst-audit24bmod2.so
+# The test check if a library without .gnu.version correctly calls the
+# audit callbacks.  So it uses an explicit link rule to avoid linking
+# against libc.so.
+$(objpfx)tst-audit24bmod1.so: $(objpfx)tst-audit24bmod1.os
+	$(CC) -nostdlib -nostartfiles -shared -o $@.new $(objpfx)tst-audit24bmod1.os \
+	  -Wl,-z,now
+	$(call after-link,$@.new)
+	mv -f $@.new $@
+CFLAGS-.os += $(call elide-stack-protector,.os,tst-audit24bmod1)
+$(objpfx)tst-audit24bmod2.so: $(objpfx)tst-audit24bmod2.os
+	$(CC) -nostdlib -nostartfiles -shared -o $@.new $(objpfx)tst-audit24bmod2.os
+	$(call after-link,$@.new)
+	mv -f $@.new $@
+CFLAGS-.os += $(call elide-stack-protector,.os,tst-audit24bmod2)
+tst-audit24b-ENV = LD_AUDIT=$(objpfx)tst-auditmod24b.so
+LDFLAGS-tst-audit24b = -Wl,-z,now
+
+# Same as tst-audit24a, but tests LD_BIND_NOW
+$(objpfx)tst-audit24c.out: $(objpfx)tst-auditmod24c.so
+$(objpfx)tst-audit24c: $(objpfx)tst-audit24amod1.so \
+		       $(objpfx)tst-audit24amod2.so
+tst-audit24c-ENV = LD_BIND_NOW=1 LD_AUDIT=$(objpfx)tst-auditmod24c.so
+LDFLAGS-tst-audit24b = -Wl,-z,lazy
+
+$(objpfx)tst-audit24d.out: $(objpfx)tst-auditmod24d.so
+$(objpfx)tst-audit24d: $(objpfx)tst-audit24dmod1.so \
+		       $(objpfx)tst-audit24dmod2.so
+$(objpfx)tst-audit24dmod1.so: $(objpfx)tst-audit24dmod3.so
+LDFLAGS-tst-audit24dmod1.so = -Wl,-z,now
+$(objpfx)tst-audit24dmod2.so: $(objpfx)tst-audit24dmod4.so
+LDFLAGS-tst-audit24dmod2.so = -Wl,-z,lazy
+tst-audit24d-ENV = LD_AUDIT=$(objpfx)tst-auditmod24d.so
+LDFLAGS-tst-audit24d = -Wl,-z,lazy
+
+$(objpfx)tst-audit25a.out: $(objpfx)tst-auditmod25.so
+$(objpfx)tst-audit25a: $(objpfx)tst-audit25mod1.so \
+		       $(objpfx)tst-audit25mod2.so \
+		       $(objpfx)tst-audit25mod3.so \
+		       $(objpfx)tst-audit25mod4.so
+$(objpfx)tst-audit25mod1.so: $(objpfx)tst-audit25mod3.so
+LDFLAGS-tst-audit25mod1.so = -Wl,-z,now
+$(objpfx)tst-audit25mod2.so: $(objpfx)tst-audit25mod4.so
+LDFLAGS-tst-audit25mod2.so = -Wl,-z,lazy
+tst-audit25a-ARGS = -- $(host-test-program-cmd)
+
+$(objpfx)tst-audit25b.out: $(objpfx)tst-auditmod25.so
+$(objpfx)tst-audit25b: $(objpfx)tst-audit25mod1.so \
+		       $(objpfx)tst-audit25mod2.so \
+		       $(objpfx)tst-audit25mod3.so \
+		       $(objpfx)tst-audit25mod4.so
+LDFLAGS-tst-audit25b = -Wl,-z,now
+tst-audit25b-ARGS = -- $(host-test-program-cmd)
+
 # tst-sonamemove links against an older implementation of the library.
 LDFLAGS-tst-sonamemove-linkmod1.so = \
   -Wl,--version-script=tst-sonamemove-linkmod1.map \
diff --git a/elf/dl-audit.c b/elf/dl-audit.c
index 152712b12f..72a50717ef 100644
--- a/elf/dl-audit.c
+++ b/elf/dl-audit.c
@@ -178,16 +178,23 @@ _dl_audit_symbind (struct link_map *l, struct reloc_result *reloc_result,
 		   const ElfW(Sym) *defsym, DL_FIXUP_VALUE_TYPE *value,
 		   lookup_t result)
 {
-  reloc_result->bound = result;
-  /* Compute index of the symbol entry in the symbol table of the DSO with the
-     definition.  */
-  reloc_result->boundndx = (defsym - (ElfW(Sym) *) D_PTR (result,
-							  l_info[DT_SYMTAB]));
+  bool for_jmp_slot = reloc_result == NULL;
+
+  /* Compute index of the symbol entry in the symbol table of the DSO
+     with the definition.  */
+  unsigned int boundndx = defsym - (ElfW(Sym) *) D_PTR (result,
+							l_info[DT_SYMTAB]);
+  if (!for_jmp_slot)
+    {
+      reloc_result->bound = result;
+      reloc_result->boundndx = boundndx;
+    }
 
   if ((l->l_audit_any_plt | result->l_audit_any_plt) == 0)
     {
       /* Set all bits since this symbol binding is not interesting.  */
-      reloc_result->enterexit = (1u << DL_NNS) - 1;
+      if (!for_jmp_slot)
+	reloc_result->enterexit = (1u << DL_NNS) - 1;
       return;
     }
 
@@ -199,12 +206,13 @@ _dl_audit_symbind (struct link_map *l, struct reloc_result *reloc_result,
      two bits.  */
   assert (DL_NNS * 2 <= sizeof (reloc_result->flags) * 8);
   assert ((LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT) == 3);
-  reloc_result->enterexit = LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT;
+  uint32_t enterexit = LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT;
 
   const char *strtab2 = (const void *) D_PTR (result, l_info[DT_STRTAB]);
 
   unsigned int flags = 0;
   struct audit_ifaces *afct = GLRO(dl_audit);
+  uintptr_t new_value = (uintptr_t) sym.st_value;
   for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
     {
       /* XXX Check whether both DSOs must request action or only one */
@@ -215,37 +223,41 @@ _dl_audit_symbind (struct link_map *l, struct reloc_result *reloc_result,
 	{
 	  if (afct->symbind != NULL)
 	    {
-	      uintptr_t new_value = afct->symbind (&sym,
-						   reloc_result->boundndx,
-						   &l_state->cookie,
-						   &result_state->cookie,
-						   &flags,
-						   strtab2 + defsym->st_name);
+	      flags |= for_jmp_slot ? LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT
+				    : 0;
+	      new_value = afct->symbind (&sym, boundndx,
+					 &l_state->cookie,
+					 &result_state->cookie, &flags,
+					 strtab2 + defsym->st_name);
 	      if (new_value != (uintptr_t) sym.st_value)
 		{
 		  flags |= LA_SYMB_ALTVALUE;
-		  sym.st_value = new_value;
+		  sym.st_value = for_jmp_slot
+		    ? DL_FIXUP_BINDNOW_ADDR_VALUE (new_value) : new_value;
 		}
 	    }
 
 	  /* Remember the results for every audit library and store a summary
 	     in the first two bits.  */
-	  reloc_result->enterexit &= flags & (LA_SYMB_NOPLTENTER
-					      | LA_SYMB_NOPLTEXIT);
-	  reloc_result->enterexit |= ((flags & (LA_SYMB_NOPLTENTER
-						| LA_SYMB_NOPLTEXIT))
-				      << ((cnt + 1) * 2));
+	  enterexit &= flags & (LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT);
+	  enterexit |= ((flags & (LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT))
+			<< ((cnt + 1) * 2));
 	}
       else
 	/* If the bind flags say this auditor is not interested, set the bits
 	   manually.  */
-	reloc_result->enterexit |= ((LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT)
-				    << ((cnt + 1) * 2));
+	enterexit |= ((LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT)
+		      << ((cnt + 1) * 2));
       afct = afct->next;
     }
 
-  reloc_result->flags = flags;
-  *value = DL_FIXUP_ADDR_VALUE (sym.st_value);
+  if (!for_jmp_slot)
+    {
+      reloc_result->enterexit = enterexit;
+      reloc_result->flags = flags;
+    }
+
+  DL_FIXUP_BINDNOW_RELOC (value, new_value, sym.st_value);
 }
 
 void
diff --git a/elf/do-rel.h b/elf/do-rel.h
index f441b74919..4b7fc14f74 100644
--- a/elf/do-rel.h
+++ b/elf/do-rel.h
@@ -16,6 +16,8 @@
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
+#include <ldsodefs.h>
+
 /* This file may be included twice, to define both
    `elf_dynamic_do_rel' and `elf_dynamic_do_rela'.  */
 
@@ -123,6 +125,10 @@ elf_dynamic_do_Rel (struct link_map *map, struct r_scope_elem *scope[],
 
 	  for (; r < end; ++r)
 	    {
+	      ElfW(Half) ndx = version[ELFW(R_SYM) (r->r_info)] & 0x7fff;
+	      const ElfW(Sym) *sym = &symtab[ELFW(R_SYM) (r->r_info)];
+	      void *const r_addr_arg = (void *) (l_addr + r->r_offset);
+	      const struct r_found_version *rversion = &map->l_versions[ndx];
 #if defined ELF_MACHINE_IRELATIVE && !defined RTLD_BOOTSTRAP
 	      if (ELFW(R_TYPE) (r->r_info) == ELF_MACHINE_IRELATIVE)
 		{
@@ -133,10 +139,19 @@ elf_dynamic_do_Rel (struct link_map *map, struct r_scope_elem *scope[],
 		}
 #endif
 
-	      ElfW(Half) ndx = version[ELFW(R_SYM) (r->r_info)] & 0x7fff;
-	      elf_machine_rel (map, scope, r, &symtab[ELFW(R_SYM) (r->r_info)],
-			       &map->l_versions[ndx],
-			       (void *) (l_addr + r->r_offset), skip_ifunc);
+	      elf_machine_rel (map, scope, r, sym, rversion, r_addr_arg,
+			       skip_ifunc);
+#if defined SHARED && !defined RTLD_BOOTSTRAP
+	      if (ELFW(R_TYPE) (r->r_info) == ELF_MACHINE_JMP_SLOT
+		  && GLRO(dl_naudit) > 0)
+		{
+		  struct link_map *sym_map
+		    = RESOLVE_MAP (map, scope, &sym, rversion,
+				   ELF_MACHINE_JMP_SLOT);
+		  if (sym != NULL)
+		    _dl_audit_symbind (map, NULL, sym, r_addr_arg, sym_map);
+		}
+#endif
 	    }
 
 #if defined ELF_MACHINE_IRELATIVE && !defined RTLD_BOOTSTRAP
@@ -158,17 +173,33 @@ elf_dynamic_do_Rel (struct link_map *map, struct r_scope_elem *scope[],
       else
 	{
 	  for (; r < end; ++r)
+	    {
+	      const ElfW(Sym) *sym = &symtab[ELFW(R_SYM) (r->r_info)];
+	      void *const r_addr_arg = (void *) (l_addr + r->r_offset);
 # ifdef ELF_MACHINE_IRELATIVE
-	    if (ELFW(R_TYPE) (r->r_info) == ELF_MACHINE_IRELATIVE)
-	      {
-		if (r2 == NULL)
-		  r2 = r;
-		end2 = r;
-	      }
-	    else
+	      if (ELFW(R_TYPE) (r->r_info) == ELF_MACHINE_IRELATIVE)
+		{
+		  if (r2 == NULL)
+		    r2 = r;
+		  end2 = r;
+		  continue;
+		}
 # endif
-	      elf_machine_rel (map, scope, r, &symtab[ELFW(R_SYM) (r->r_info)], NULL,
-			       (void *) (l_addr + r->r_offset), skip_ifunc);
+	      elf_machine_rel (map, scope, r, sym, NULL, r_addr_arg,
+			       skip_ifunc);
+# if defined SHARED && !defined RTLD_BOOTSTRAP
+	      if (ELFW(R_TYPE) (r->r_info) == ELF_MACHINE_JMP_SLOT
+		  && GLRO(dl_naudit) > 0)
+		{
+		  struct link_map *sym_map
+		    = RESOLVE_MAP (map, scope, &sym,
+				   (struct r_found_version *) NULL,
+				   ELF_MACHINE_JMP_SLOT);
+		  if (sym != NULL)
+		    _dl_audit_symbind (map, NULL , sym,r_addr_arg, sym_map);
+		}
+# endif
+	    }
 
 # ifdef ELF_MACHINE_IRELATIVE
 	  if (r2 != NULL)
diff --git a/elf/sotruss-lib.c b/elf/sotruss-lib.c
index f69d23894b..67062c5f98 100644
--- a/elf/sotruss-lib.c
+++ b/elf/sotruss-lib.c
@@ -16,6 +16,7 @@
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
+#include <err.h>
 #include <error.h>
 #include <fcntl.h>
 #include <stdio.h>
@@ -231,6 +232,12 @@ uintptr_t
 la_symbind (Elf_Sym *sym, unsigned int ndx, uintptr_t *refcook,
 	    uintptr_t *defcook, unsigned int *flags, const char *symname)
 {
+  if (*flags & LA_SYMB_NOPLTENTER)
+    warnx ("cannot trace PLT enter (bind-now enabled)");
+
+  if (do_exit && *flags & LA_SYMB_NOPLTEXIT)
+    warnx ("cannot trace PLT exit (bind-now enabled)");
+
   if (!do_exit)
     *flags = LA_SYMB_NOPLTEXIT;
 
diff --git a/elf/tst-audit24a.c b/elf/tst-audit24a.c
new file mode 100644
index 0000000000..134c3e7b5b
--- /dev/null
+++ b/elf/tst-audit24a.c
@@ -0,0 +1,36 @@
+/* DL_AUDIT test for la_symbind and bind-now.
+   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 <support/check.h>
+#include <support/support.h>
+
+int tst_audit24amod1_func1 (void);
+int tst_audit24amod1_func2 (void);
+int tst_audit24amod2_func1 (void);
+
+int
+do_test (void)
+{
+  TEST_COMPARE (tst_audit24amod1_func1 (), 1);
+  TEST_COMPARE (tst_audit24amod1_func2 (), 2);
+  TEST_COMPARE (tst_audit24amod2_func1 (), 10);
+
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/elf/tst-audit24amod1.c b/elf/tst-audit24amod1.c
new file mode 100644
index 0000000000..43d3831677
--- /dev/null
+++ b/elf/tst-audit24amod1.c
@@ -0,0 +1,31 @@
+/* Modules used by tst-audit24a.
+   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 <stdlib.h>
+
+_Noreturn int
+tst_audit24amod1_func1 (void)
+{
+  abort ();
+}
+
+int
+tst_audit24amod1_func2 (void)
+{
+  return 2;
+}
diff --git a/elf/tst-audit24amod2.c b/elf/tst-audit24amod2.c
new file mode 100644
index 0000000000..c995827855
--- /dev/null
+++ b/elf/tst-audit24amod2.c
@@ -0,0 +1,25 @@
+/* Modules used by tst-audit24a.
+   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 <stdlib.h>
+
+_Noreturn int
+tst_audit24amod2_func1 (void)
+{
+  abort ();
+}
diff --git a/elf/tst-audit24b.c b/elf/tst-audit24b.c
new file mode 100644
index 0000000000..69bf71b4c9
--- /dev/null
+++ b/elf/tst-audit24b.c
@@ -0,0 +1,37 @@
+/* DL_AUDIT test for la_symbind and bind-now.
+   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/>.  */
+
+/* This is similar to tst-audit24a, with the difference this modules
+   does not have the .gnu.version section header.  */
+
+#include <support/check.h>
+#include <support/support.h>
+
+int tst_audit24bmod1_func1 (void);
+int tst_audit24bmod1_func2 (void);
+
+int
+do_test (void)
+{
+  TEST_COMPARE (tst_audit24bmod1_func1 (), 1);
+  TEST_COMPARE (tst_audit24bmod1_func2 (), 2);
+
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/elf/tst-audit24bmod1.c b/elf/tst-audit24bmod1.c
new file mode 100644
index 0000000000..91c6fa0251
--- /dev/null
+++ b/elf/tst-audit24bmod1.c
@@ -0,0 +1,31 @@
+/* Modules used by tst-audit24c.
+   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/>.  */
+
+int tst_audit24bmod2_func1 (void);
+
+int
+tst_audit24bmod1_func1 (void)
+{
+  return -1;
+}
+
+int
+tst_audit24bmod1_func2 (void)
+{
+  return tst_audit24bmod2_func1 ();
+}
diff --git a/elf/tst-audit24bmod2.c b/elf/tst-audit24bmod2.c
new file mode 100644
index 0000000000..3baf9e8bd4
--- /dev/null
+++ b/elf/tst-audit24bmod2.c
@@ -0,0 +1,23 @@
+/* Modules used by tst-audit24b.
+   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/>.  */
+
+int
+tst_audit24bmod2_func1 (void)
+{
+  return -1;
+}
diff --git a/elf/tst-audit24c.c b/elf/tst-audit24c.c
new file mode 100644
index 0000000000..46ed328756
--- /dev/null
+++ b/elf/tst-audit24c.c
@@ -0,0 +1,2 @@
+/* It tests LD_BIND_NOW=1 instead of linking with -Wl,-z,now  */
+#include "tst-audit24a.c"
diff --git a/elf/tst-audit24d.c b/elf/tst-audit24d.c
new file mode 100644
index 0000000000..821e5a2051
--- /dev/null
+++ b/elf/tst-audit24d.c
@@ -0,0 +1,36 @@
+/* DL_AUDIT test for la_symbind and bind-now.
+   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 <support/check.h>
+#include <support/support.h>
+
+int tst_audit24dmod1_func1 (void);
+int tst_audit24dmod1_func2 (void);
+int tst_audit24dmod2_func1 (void);
+
+int
+do_test (void)
+{
+  TEST_COMPARE (tst_audit24dmod1_func1 (), 1);
+  TEST_COMPARE (tst_audit24dmod1_func2 (), 32);
+  TEST_COMPARE (tst_audit24dmod2_func1 (), 10);
+
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/elf/tst-audit24dmod1.c b/elf/tst-audit24dmod1.c
new file mode 100644
index 0000000000..792da3b581
--- /dev/null
+++ b/elf/tst-audit24dmod1.c
@@ -0,0 +1,33 @@
+/* Modules used by tst-audit24d.
+   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 <stdlib.h>
+
+int tst_audit24dmod3_func1 (void);
+
+_Noreturn int
+tst_audit24dmod1_func1 (void)
+{
+  abort ();
+}
+
+int
+tst_audit24dmod1_func2 (void)
+{
+  return 2 + tst_audit24dmod3_func1 ();;
+}
diff --git a/elf/tst-audit24dmod2.c b/elf/tst-audit24dmod2.c
new file mode 100644
index 0000000000..8c76257885
--- /dev/null
+++ b/elf/tst-audit24dmod2.c
@@ -0,0 +1,28 @@
+/* Module for tst-audit24d.
+   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 <stdlib.h>
+
+int tst_audit24dmod4_func1 (void);
+
+_Noreturn int
+tst_audit24dmod2_func1 (void)
+{
+  tst_audit24dmod4_func1 ();
+  abort ();
+}
diff --git a/elf/tst-audit24dmod3.c b/elf/tst-audit24dmod3.c
new file mode 100644
index 0000000000..367c776eb5
--- /dev/null
+++ b/elf/tst-audit24dmod3.c
@@ -0,0 +1,31 @@
+/* Module for tst-audit24d.
+   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 <stdlib.h>
+
+_Noreturn int
+tst_audit24dmod3_func1 (void)
+{
+  abort ();
+}
+
+int
+tst_audit24dmod3_func2 (void)
+{
+  return 4;
+}
diff --git a/elf/tst-audit24dmod4.c b/elf/tst-audit24dmod4.c
new file mode 100644
index 0000000000..c994c7cf03
--- /dev/null
+++ b/elf/tst-audit24dmod4.c
@@ -0,0 +1,25 @@
+/* Module for tst-audit24d.
+   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 <stdlib.h>
+
+_Noreturn int
+tst_audit24dmod4_func1 (void)
+{
+  abort ();
+}
diff --git a/elf/tst-audit25a.c b/elf/tst-audit25a.c
new file mode 100644
index 0000000000..8d08371abd
--- /dev/null
+++ b/elf/tst-audit25a.c
@@ -0,0 +1,127 @@
+/* Check DT_AUDIT and LD_BIND_NOW.
+   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 <errno.h>
+#include <getopt.h>
+#include <limits.h>
+#include <inttypes.h>
+#include <string.h>
+#include <stdlib.h>
+#include <support/capture_subprocess.h>
+#include <support/check.h>
+#include <support/xstdio.h>
+#include <support/support.h>
+#include <sys/auxv.h>
+
+static int restart;
+#define CMDLINE_OPTIONS \
+  { "restart", no_argument, &restart, 1 },
+
+void tst_audit25mod1_func1 (void);
+void tst_audit25mod1_func2 (void);
+void tst_audit25mod2_func1 (void);
+void tst_audit25mod2_func2 (void);
+
+static int
+handle_restart (void)
+{
+  tst_audit25mod1_func1 ();
+  tst_audit25mod1_func2 ();
+  tst_audit25mod2_func1 ();
+  tst_audit25mod2_func2 ();
+
+  return 0;
+}
+
+static inline bool
+startswith (const char *str, const char *pre)
+{
+  size_t lenpre = strlen (pre);
+  size_t lenstr = strlen (str);
+  return lenstr < lenpre ? false : memcmp (pre, str, lenpre) == 0;
+}
+
+static int
+do_test (int argc, char *argv[])
+{
+  /* We must have either:
+     - One our fource parameters left if called initially:
+       + path to ld.so         optional
+       + "--library-path"      optional
+       + the library path      optional
+       + the application name  */
+
+  if (restart)
+    return handle_restart ();
+
+  setenv ("LD_AUDIT", "tst-auditmod25.so", 0);
+
+  char *spargv[9];
+  int i = 0;
+  for (; i < argc - 1; i++)
+    spargv[i] = argv[i + 1];
+  spargv[i++] = (char *) "--direct";
+  spargv[i++] = (char *) "--restart";
+  spargv[i] = NULL;
+
+  {
+    struct support_capture_subprocess result
+      = support_capture_subprogram (spargv[0], spargv);
+    support_capture_subprocess_check (&result, "tst-audit25a", 0,
+				      sc_allow_stderr);
+
+    /* tst-audit25a is build with -Wl,-z,lazy and tst-audit25mod1 with
+       -Wl,-z,now; so only tst_audit25mod3_func1 should be expected to
+       have LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT.  */
+    TEST_COMPARE_STRING (result.err.buffer,
+			 "la_symbind: tst_audit25mod3_func1 1\n"
+			 "la_symbind: tst_audit25mod1_func1 0\n"
+			 "la_symbind: tst_audit25mod1_func2 0\n"
+			 "la_symbind: tst_audit25mod2_func1 0\n"
+			 "la_symbind: tst_audit25mod4_func1 0\n"
+			 "la_symbind: tst_audit25mod2_func2 0\n");
+
+    support_capture_subprocess_free (&result);
+  }
+
+  {
+    setenv ("LD_BIND_NOW", "1", 0);
+    struct support_capture_subprocess result
+      = support_capture_subprogram (spargv[0], spargv);
+    support_capture_subprocess_check (&result, "tst-audit25a", 0,
+				      sc_allow_stderr);
+
+    /* With LD_BIND_NOW all symbols are expected to have
+       LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT.  Also the resolution
+       order is done in breadth-first order.  */
+    TEST_COMPARE_STRING (result.err.buffer,
+			 "la_symbind: tst_audit25mod4_func1 1\n"
+			 "la_symbind: tst_audit25mod3_func1 1\n"
+			 "la_symbind: tst_audit25mod1_func1 1\n"
+			 "la_symbind: tst_audit25mod2_func1 1\n"
+			 "la_symbind: tst_audit25mod1_func2 1\n"
+			 "la_symbind: tst_audit25mod2_func2 1\n");
+
+    support_capture_subprocess_free (&result);
+  }
+
+  return 0;
+}
+
+#define TEST_FUNCTION_ARGV do_test
+#include <support/test-driver.c>
diff --git a/elf/tst-audit25b.c b/elf/tst-audit25b.c
new file mode 100644
index 0000000000..1d748b7068
--- /dev/null
+++ b/elf/tst-audit25b.c
@@ -0,0 +1,128 @@
+/* Check DT_AUDIT and LD_BIND_NOW.
+   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 <errno.h>
+#include <getopt.h>
+#include <limits.h>
+#include <inttypes.h>
+#include <string.h>
+#include <stdlib.h>
+#include <support/capture_subprocess.h>
+#include <support/check.h>
+#include <support/xstdio.h>
+#include <support/support.h>
+#include <sys/auxv.h>
+
+static int restart;
+#define CMDLINE_OPTIONS \
+  { "restart", no_argument, &restart, 1 },
+
+void tst_audit25mod1_func1 (void);
+void tst_audit25mod1_func2 (void);
+void tst_audit25mod2_func1 (void);
+void tst_audit25mod2_func2 (void);
+
+static int
+handle_restart (void)
+{
+  tst_audit25mod1_func1 ();
+  tst_audit25mod1_func2 ();
+  tst_audit25mod2_func1 ();
+  tst_audit25mod2_func2 ();
+
+  return 0;
+}
+
+static inline bool
+startswith (const char *str, const char *pre)
+{
+  size_t lenpre = strlen (pre);
+  size_t lenstr = strlen (str);
+  return lenstr >= lenpre && memcmp (pre, str, lenpre) == 0;
+}
+
+static int
+do_test (int argc, char *argv[])
+{
+  /* We must have either:
+     - One our fource parameters left if called initially:
+       + path to ld.so         optional
+       + "--library-path"      optional
+       + the library path      optional
+       + the application name  */
+
+  if (restart)
+    return handle_restart ();
+
+  setenv ("LD_AUDIT", "tst-auditmod25.so", 0);
+
+  char *spargv[9];
+  int i = 0;
+  for (; i < argc - 1; i++)
+    spargv[i] = argv[i + 1];
+  spargv[i++] = (char *) "--direct";
+  spargv[i++] = (char *) "--restart";
+  spargv[i] = NULL;
+
+  {
+    struct support_capture_subprocess result
+      = support_capture_subprogram (spargv[0], spargv);
+    support_capture_subprocess_check (&result, "tst-audit25a", 0,
+				      sc_allow_stderr);
+
+    /* tst-audit25a and tst-audit25mod1 are built with -Wl,-z,now, but
+       tst-audit25mod2 is built with -Wl,z,lazy.  So only
+       tst_audit25mod4_func1 (called by tst_audit25mod2_func1) should not
+       have LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT.  */
+    TEST_COMPARE_STRING (result.err.buffer,
+			 "la_symbind: tst_audit25mod3_func1 1\n"
+			 "la_symbind: tst_audit25mod1_func1 1\n"
+			 "la_symbind: tst_audit25mod2_func1 1\n"
+			 "la_symbind: tst_audit25mod1_func2 1\n"
+			 "la_symbind: tst_audit25mod2_func2 1\n"
+			 "la_symbind: tst_audit25mod4_func1 0\n");
+
+    support_capture_subprocess_free (&result);
+  }
+
+  {
+    setenv ("LD_BIND_NOW", "1", 0);
+    struct support_capture_subprocess result
+      = support_capture_subprogram (spargv[0], spargv);
+    support_capture_subprocess_check (&result, "tst-audit25a", 0,
+				      sc_allow_stderr);
+
+    /* With LD_BIND_NOW all symbols are expected to have
+       LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT.  Also the resolution
+       order is done in breadth-first order.  */
+    TEST_COMPARE_STRING (result.err.buffer,
+			 "la_symbind: tst_audit25mod4_func1 1\n"
+			 "la_symbind: tst_audit25mod3_func1 1\n"
+			 "la_symbind: tst_audit25mod1_func1 1\n"
+			 "la_symbind: tst_audit25mod2_func1 1\n"
+			 "la_symbind: tst_audit25mod1_func2 1\n"
+			 "la_symbind: tst_audit25mod2_func2 1\n");
+
+    support_capture_subprocess_free (&result);
+  }
+
+  return 0;
+}
+
+#define TEST_FUNCTION_ARGV do_test
+#include <support/test-driver.c>
diff --git a/elf/tst-audit25mod1.c b/elf/tst-audit25mod1.c
new file mode 100644
index 0000000000..9aa39ed325
--- /dev/null
+++ b/elf/tst-audit25mod1.c
@@ -0,0 +1,30 @@
+/* Modules used by tst-audit25.
+   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/>.  */
+
+void tst_audit25mod3_func1 (void);
+
+void
+tst_audit25mod1_func1 (void)
+{
+  tst_audit25mod3_func1 ();
+}
+
+void
+tst_audit25mod1_func2 (void)
+{
+}
diff --git a/elf/tst-audit25mod2.c b/elf/tst-audit25mod2.c
new file mode 100644
index 0000000000..6d8e225fcc
--- /dev/null
+++ b/elf/tst-audit25mod2.c
@@ -0,0 +1,30 @@
+/* Modules used by tst-audit25.
+   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/>.  */
+
+void tst_audit25mod4_func1 (void);
+
+void
+tst_audit25mod2_func1 (void)
+{
+  tst_audit25mod4_func1 ();
+}
+
+void
+tst_audit25mod2_func2 (void)
+{
+}
diff --git a/elf/tst-audit25mod3.c b/elf/tst-audit25mod3.c
new file mode 100644
index 0000000000..c0d5977fd8
--- /dev/null
+++ b/elf/tst-audit25mod3.c
@@ -0,0 +1,22 @@
+/* Modules used by tst-audit25.
+   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/>.  */
+
+void
+tst_audit25mod3_func1 (void)
+{
+}
diff --git a/elf/tst-audit25mod4.c b/elf/tst-audit25mod4.c
new file mode 100644
index 0000000000..689ee5138f
--- /dev/null
+++ b/elf/tst-audit25mod4.c
@@ -0,0 +1,22 @@
+/* Modules used by tst-audit25.
+   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/>.  */
+
+void
+tst_audit25mod4_func1 (void)
+{
+}
diff --git a/elf/tst-auditmod24.h b/elf/tst-auditmod24.h
new file mode 100644
index 0000000000..621fd50364
--- /dev/null
+++ b/elf/tst-auditmod24.h
@@ -0,0 +1,29 @@
+/* Auxiliary functions for tst-audit24x.
+   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/>.  */
+
+#ifndef _TST_AUDITMOD24_H
+#define _TST_AUDITMOD24_H
+
+static void
+check_symbind_flags (unsigned int flags)
+{
+  if ((flags & (LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT)) == 0)
+    abort ();
+}
+
+#endif
diff --git a/elf/tst-auditmod24a.c b/elf/tst-auditmod24a.c
new file mode 100644
index 0000000000..ce8be9c22f
--- /dev/null
+++ b/elf/tst-auditmod24a.c
@@ -0,0 +1,114 @@
+/* Audit modules for tst-audit24a.
+   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 <link.h>
+#include <inttypes.h>
+#include <stdlib.h>
+#include <string.h>
+#include <tst-auditmod24.h>
+
+#define AUDIT24_COOKIE     0x1
+#define AUDIT24MOD1_COOKIE 0x2
+#define AUDIT24MOD2_COOKIE 0x3
+
+#ifndef TEST_NAME
+# define TEST_NAME "tst-audit24a"
+#endif
+#ifndef TEST_MOD
+# define TEST_MOD TEST_NAME
+#endif
+#ifndef TEST_FUNC
+# define TEST_FUNC "tst_audit24a"
+#endif
+
+unsigned int
+la_version (unsigned int version)
+{
+  return LAV_CURRENT;
+}
+
+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 ? TEST_NAME : p + 1;
+
+  uintptr_t ck = -1;
+  if (strcmp (l_name, TEST_MOD "mod1.so") == 0)
+    ck = AUDIT24MOD1_COOKIE;
+  else if (strcmp (l_name, TEST_MOD "mod2.so") == 0)
+    ck = AUDIT24MOD2_COOKIE;
+  else if (strcmp (l_name, TEST_NAME) == 0)
+    ck = AUDIT24_COOKIE;
+
+  *cookie = ck;
+  return ck == -1 ? 0 : LA_FLG_BINDFROM | LA_FLG_BINDTO;
+}
+
+static int
+tst_func1 (void)
+{
+  return 1;
+}
+
+static int
+tst_func2 (void)
+{
+  return 10;
+}
+
+#if __ELF_NATIVE_CLASS == 64
+uintptr_t
+la_symbind64 (Elf64_Sym *sym, unsigned int ndx,
+	      uintptr_t *refcook, uintptr_t *defcook,
+	      unsigned int *flags, const char *symname)
+#else
+uintptr_t
+la_symbind32 (Elf32_Sym *sym, unsigned int ndx,
+	      uintptr_t *refcook, uintptr_t *defcook,
+	      unsigned int *flags, const char *symname)
+#endif
+{
+  if (*refcook == AUDIT24_COOKIE)
+    {
+      if (*defcook == AUDIT24MOD1_COOKIE)
+	{
+	  /* Check if bind-now symbols are advertised to not call the PLT
+	     hooks.  */
+	  check_symbind_flags (*flags);
+
+	  if (strcmp (symname, TEST_FUNC "mod1_func1") == 0)
+	    return (uintptr_t) tst_func1;
+	  else if (strcmp (symname, TEST_FUNC "mod1_func2") == 0)
+	    return sym->st_value;
+	  abort ();
+	}
+      if (*defcook == AUDIT24MOD2_COOKIE
+	  && (strcmp (symname, TEST_FUNC "mod2_func1") == 0))
+	{
+	  check_symbind_flags (*flags);
+
+	  return (uintptr_t) tst_func2;
+	}
+
+      /* malloc functions.  */
+      return sym->st_value;
+    }
+
+  abort ();
+}
diff --git a/elf/tst-auditmod24b.c b/elf/tst-auditmod24b.c
new file mode 100644
index 0000000000..d41c5adc6b
--- /dev/null
+++ b/elf/tst-auditmod24b.c
@@ -0,0 +1,104 @@
+/* Audit modules for tst-audit24b.
+   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 <link.h>
+#include <inttypes.h>
+#include <stdlib.h>
+#include <string.h>
+#include <tst-auditmod24.h>
+
+#define TEST_NAME "tst-audit24b"
+#define TEST_FUNC "tst_audit24b"
+
+#define AUDIT24_COOKIE     0x1
+#define AUDIT24MOD1_COOKIE 0x2
+#define AUDIT24MOD2_COOKIE 0x3
+
+unsigned int
+la_version (unsigned int version)
+{
+  return LAV_CURRENT;
+}
+
+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 ? TEST_NAME : p + 1;
+
+  uintptr_t ck = -1;
+  if (strcmp (l_name, TEST_NAME "mod1.so") == 0)
+    ck = AUDIT24MOD1_COOKIE;
+  else if (strcmp (l_name, TEST_NAME "mod2.so") == 0)
+    ck = AUDIT24MOD2_COOKIE;
+  else if (strcmp (l_name, TEST_NAME) == 0)
+    ck = AUDIT24_COOKIE;
+
+  *cookie = ck;
+  return ck == -1 ? 0 : LA_FLG_BINDFROM | LA_FLG_BINDTO;
+}
+
+static int
+tst_func1 (void)
+{
+  return 1;
+}
+
+static int
+tst_func2 (void)
+{
+  return 2;
+}
+
+#if __ELF_NATIVE_CLASS == 64
+uintptr_t
+la_symbind64 (Elf64_Sym *sym, unsigned int ndx,
+	      uintptr_t *refcook, uintptr_t *defcook,
+	      unsigned int *flags, const char *symname)
+#else
+uintptr_t
+la_symbind32 (Elf32_Sym *sym, unsigned int ndx,
+	      uintptr_t *refcook, uintptr_t *defcook,
+	      unsigned int *flags, const char *symname)
+#endif
+{
+  if (*refcook == AUDIT24_COOKIE)
+    {
+      if (*defcook == AUDIT24MOD1_COOKIE)
+	  {
+	    if (strcmp (symname, TEST_FUNC "mod1_func1") == 0)
+	      return (uintptr_t) tst_func1;
+	    else if (strcmp (symname, TEST_FUNC "mod1_func2") == 0)
+	      return sym->st_value;
+	    abort ();
+	  }
+      /* malloc functions.  */
+      return sym->st_value;
+    }
+  else if (*refcook == AUDIT24MOD1_COOKIE)
+    {
+      if (*defcook == AUDIT24MOD2_COOKIE
+	  && (strcmp (symname, TEST_FUNC "mod2_func1") == 0))
+	{
+	  check_symbind_flags (*flags);
+	  return (uintptr_t) tst_func2;
+	}
+    }
+
+  abort ();
+}
diff --git a/elf/tst-auditmod24c.c b/elf/tst-auditmod24c.c
new file mode 100644
index 0000000000..67e62c9d33
--- /dev/null
+++ b/elf/tst-auditmod24c.c
@@ -0,0 +1,3 @@
+#define TEST_NAME "tst-audit24c"
+#define TEST_MOD  "tst-audit24a"
+#include "tst-auditmod24a.c"
diff --git a/elf/tst-auditmod24d.c b/elf/tst-auditmod24d.c
new file mode 100644
index 0000000000..24cae42cb8
--- /dev/null
+++ b/elf/tst-auditmod24d.c
@@ -0,0 +1,120 @@
+/* Audit module for tst-audit24d.
+   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 <link.h>
+#include <inttypes.h>
+#include <stdlib.h>
+#include <string.h>
+#include <tst-auditmod24.h>
+
+#define AUDIT24_COOKIE     0x0
+#define AUDIT24MOD1_COOKIE 0x1
+#define AUDIT24MOD2_COOKIE 0x2
+#define AUDIT24MOD3_COOKIE 0x3
+#define AUDIT24MOD4_COOKIE 0x4
+
+unsigned int
+la_version (unsigned int version)
+{
+  return LAV_CURRENT;
+}
+
+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 ? "tst-audit24d" : p + 1;
+
+  uintptr_t ck = -1;
+  if (strcmp (l_name, "tst-audit24dmod1.so") == 0)
+    ck = AUDIT24MOD1_COOKIE;
+  else if (strcmp (l_name, "tst-audit24dmod2.so") == 0)
+    ck = AUDIT24MOD2_COOKIE;
+  else if (strcmp (l_name, "tst-audit24dmod3.so") == 0)
+    ck = AUDIT24MOD3_COOKIE;
+  else if (strcmp (l_name, "tst-audit24dmod.so") == 0)
+    ck = AUDIT24MOD4_COOKIE;
+  else if (strcmp (l_name, "tst-audit24d") == 0)
+    ck = AUDIT24_COOKIE;
+
+  *cookie = ck;
+  return ck == -1 ? 0 : LA_FLG_BINDFROM | LA_FLG_BINDTO;
+}
+
+static int
+tst_audit24dmod1_func1 (void)
+{
+  return 1;
+}
+
+static int
+tst_audit24dmod2_func1 (void)
+{
+  return 10;
+}
+
+static int
+tst_audit24dmod3_func1 (void)
+{
+  return 30;
+}
+
+#include <stdio.h>
+
+#if __ELF_NATIVE_CLASS == 64
+uintptr_t
+la_symbind64 (Elf64_Sym *sym, unsigned int ndx,
+	      uintptr_t *refcook, uintptr_t *defcook,
+	      unsigned int *flags, const char *symname)
+#else
+uintptr_t
+la_symbind32 (Elf32_Sym *sym, unsigned int ndx,
+	      uintptr_t *refcook, uintptr_t *defcook,
+	      unsigned int *flags, const char *symname)
+#endif
+{
+  if (*refcook == AUDIT24_COOKIE)
+    {
+      if (*defcook == AUDIT24MOD1_COOKIE)
+	  {
+	    if (strcmp (symname, "tst_audit24dmod1_func1") == 0)
+	      return (uintptr_t) tst_audit24dmod1_func1;
+	    else if (strcmp (symname, "tst_audit24dmod1_func2") == 0)
+	      return sym->st_value;
+	    abort ();
+	  }
+      if (*defcook == AUDIT24MOD2_COOKIE
+	  && (strcmp (symname, "tst_audit24dmod2_func1") == 0))
+	return (uintptr_t) tst_audit24dmod2_func1;
+
+      /* malloc functions.  */
+      return sym->st_value;
+    }
+  else if (*refcook == AUDIT24MOD1_COOKIE)
+    {
+      if (*defcook == AUDIT24MOD3_COOKIE
+	  && strcmp (symname, "tst_audit24dmod3_func1") == 0)
+	{
+	  check_symbind_flags (*flags);
+
+	  return (uintptr_t) tst_audit24dmod3_func1;
+	}
+    }
+
+  abort ();
+}
diff --git a/elf/tst-auditmod25.c b/elf/tst-auditmod25.c
new file mode 100644
index 0000000000..ea4d5fe542
--- /dev/null
+++ b/elf/tst-auditmod25.c
@@ -0,0 +1,79 @@
+/* Audit modules for tst-audit25a.
+   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 <link.h>
+#include <inttypes.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#define AUDIT25_COOKIE     0x1
+#define AUDIT25MOD1_COOKIE 0x2
+#define AUDIT25MOD2_COOKIE 0x3
+#define AUDIT25MOD3_COOKIE 0x2
+#define AUDIT25MOD4_COOKIE 0x3
+
+#define TEST_NAME "tst-audit25"
+#define TEST_MOD  "tst-audit25"
+#define TEST_FUNC "tst_audit25"
+
+unsigned int
+la_version (unsigned int version)
+{
+  return LAV_CURRENT;
+}
+
+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 ? TEST_NAME : p + 1;
+
+  uintptr_t ck = -1;
+  if (strcmp (l_name, TEST_MOD "mod1.so") == 0)
+    ck = AUDIT25MOD1_COOKIE;
+  else if (strcmp (l_name, TEST_MOD "mod2.so") == 0)
+    ck = AUDIT25MOD2_COOKIE;
+  else if (strcmp (l_name, TEST_MOD "mod3.so") == 0)
+    ck = AUDIT25MOD3_COOKIE;
+  else if (strcmp (l_name, TEST_MOD "mod4.so") == 0)
+    ck = AUDIT25MOD4_COOKIE;
+  else if (strncmp (l_name, TEST_NAME, strlen (TEST_NAME)) == 0)
+    ck = AUDIT25_COOKIE;
+
+  *cookie = ck;
+  return ck == -1 ? 0 : LA_FLG_BINDFROM | LA_FLG_BINDTO;
+}
+
+#if __ELF_NATIVE_CLASS == 64
+uintptr_t
+la_symbind64 (Elf64_Sym *sym, unsigned int ndx,
+	      uintptr_t *refcook, uintptr_t *defcook,
+	      unsigned int *flags, const char *symname)
+#else
+uintptr_t
+la_symbind32 (Elf32_Sym *sym, unsigned int ndx,
+	      uintptr_t *refcook, uintptr_t *defcook,
+	      unsigned int *flags, const char *symname)
+#endif
+{
+  if (*refcook != -1 && *defcook != -1)
+    fprintf (stderr, "la_symbind: %s %u\n", symname,
+	     *flags & (LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT) ? 1 : 0);
+  return sym->st_value;
+}
diff --git a/sysdeps/generic/dl-lookupcfg.h b/sysdeps/generic/dl-lookupcfg.h
index c038c31ce6..a15fd32771 100644
--- a/sysdeps/generic/dl-lookupcfg.h
+++ b/sysdeps/generic/dl-lookupcfg.h
@@ -26,3 +26,6 @@
 #define DL_FIXUP_VALUE_CODE_ADDR(value) (value)
 #define DL_FIXUP_VALUE_ADDR(value) (value)
 #define DL_FIXUP_ADDR_VALUE(addr) (addr)
+#define DL_FIXUP_BINDNOW_ADDR_VALUE(addr) (addr)
+#define DL_FIXUP_BINDNOW_RELOC(value, new_value, st_value) \
+  (*value) = st_value;
diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
index d0004a3111..2c7c9dbb85 100644
--- a/sysdeps/generic/ldsodefs.h
+++ b/sysdeps/generic/ldsodefs.h
@@ -1426,7 +1426,10 @@ void _dl_audit_objclose (struct link_map *l)
 /* Call the la_preinit from the audit modules for the link_map L.  */
 void _dl_audit_preinit (struct link_map *l);
 
-/* Call the la_symbind{32,64} from the audit modules for the link_map L.  */
+/* Call the la_symbind{32,64} from the audit modules for the link_map L.  If
+   RELOC_RESULT is NULL it assumes the symbol to be bind-now and will set
+   the flags with LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT prior calling
+   la_symbind{32,64}.  */
 void _dl_audit_symbind (struct link_map *l, struct reloc_result *reloc_result,
 			const ElfW(Sym) *defsym, DL_FIXUP_VALUE_TYPE *value,
 			lookup_t result)
diff --git a/sysdeps/hppa/dl-lookupcfg.h b/sysdeps/hppa/dl-lookupcfg.h
index a9a927f26c..f376965600 100644
--- a/sysdeps/hppa/dl-lookupcfg.h
+++ b/sysdeps/hppa/dl-lookupcfg.h
@@ -80,3 +80,6 @@ void attribute_hidden _dl_unmap (struct link_map *map);
 #define DL_FIXUP_VALUE_CODE_ADDR(value) ((value).ip)
 #define DL_FIXUP_VALUE_ADDR(value) ((uintptr_t) &(value))
 #define DL_FIXUP_ADDR_VALUE(addr) (*(struct fdesc *) (addr))
+#define DL_FIXUP_BINDNOW_ADDR_VALUE(addr) (addr)
+#define DL_FIXUP_BINDNOW_RELOC(value, new_value, st_value) \
+  (*value) = *(struct fdesc *) (st_value)
diff --git a/sysdeps/ia64/dl-lookupcfg.h b/sysdeps/ia64/dl-lookupcfg.h
index 58ca32424b..2b8b2fa5db 100644
--- a/sysdeps/ia64/dl-lookupcfg.h
+++ b/sysdeps/ia64/dl-lookupcfg.h
@@ -74,3 +74,6 @@ extern void attribute_hidden _dl_unmap (struct link_map *map);
 
 #define DL_FIXUP_VALUE_ADDR(value) ((uintptr_t) &(value))
 #define DL_FIXUP_ADDR_VALUE(addr) (*(struct fdesc *) (addr))
+#define DL_FIXUP_BINDNOW_ADDR_VALUE(addr) (addr)
+#define DL_FIXUP_BINDNOW_RELOC(value, new_value, st_value) \
+  (*value) = *(struct fdesc *) (st_value)
diff --git a/sysdeps/powerpc/dl-lookupcfg.h b/sysdeps/powerpc/dl-lookupcfg.h
new file mode 100644
index 0000000000..43fc94a7f6
--- /dev/null
+++ b/sysdeps/powerpc/dl-lookupcfg.h
@@ -0,0 +1,39 @@
+/* Configuration of lookup functions.  PowerPC version.
+   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/>.  */
+
+#define DL_FIXUP_VALUE_TYPE ElfW(Addr)
+#define DL_FIXUP_MAKE_VALUE(map, addr) (addr)
+#define DL_FIXUP_VALUE_CODE_ADDR(value) (value)
+#define DL_FIXUP_VALUE_ADDR(value) (value)
+#define DL_FIXUP_ADDR_VALUE(addr) (addr)
+#if __WORDSIZE == 64 && _CALL_ELF == 1
+/* We need to correctly set the audit modules value for bind-now.  */
+# define DL_FIXUP_BINDNOW_ADDR_VALUE(addr) \
+ (((Elf64_FuncDesc *)(addr))->fd_func)
+# define DL_FIXUP_BINDNOW_RELOC(value, new_value, st_value)	\
+ ({								\
+    Elf64_FuncDesc *opd = (Elf64_FuncDesc *) (value);		\
+    opd->fd_func = (st_value);					\
+    if ((new_value) != (uintptr_t) (st_value))			\
+     opd->fd_toc = ((Elf64_FuncDesc *)(new_value))->fd_toc;	\
+  })
+#else
+# define DL_FIXUP_BINDNOW_ADDR_VALUE(addr) (addr)
+# define DL_FIXUP_BINDNOW_RELOC(value, new_value, st_value)	\
+  (*value) = st_value;
+#endif
-- 
2.32.0


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

* [PATCH v8 4/4] elf: Fix runtime linker auditing on aarch64 (BZ #26643)
  2021-12-28 11:50 [PATCH v8 0/4] Multiple rtld-audit fixes Adhemerval Zanella
                   ` (2 preceding siblings ...)
  2021-12-28 11:50 ` [PATCH v8 3/4] elf: Issue la_symbind for bind-now (BZ #23734) Adhemerval Zanella
@ 2021-12-28 11:50 ` Adhemerval Zanella
  3 siblings, 0 replies; 10+ messages in thread
From: Adhemerval Zanella @ 2021-12-28 11:50 UTC (permalink / raw)
  To: libc-alpha, jma14; +Cc: John Mellor-Crummey, Ben Woodard

From: Ben Woodard <woodard@redhat.com>

The rtld audit support show two problems on aarch64:

  1. _dl_runtime_resolve does not preserve x8, the indirect result
      location register, which might generate wrong result calls
      depending of the function signature.

  2. The NEON Q registers pushed onto the stack by _dl_runtime_resolve
     were twice the size of D registers extracted from the stack frame by
     _dl_runtime_profile.

While 2. might result in wrong information passed on the PLT tracing,
1. generates wrong runtime behaviour.

The aarch64 rtld audit support is change to:

  * Both La_aarch64_regs and La_aarch64_retval are expanded to include
    both x8 and the full sized NEON V registers, as defined by the
    ABI.

  * dl_runtime_profile needed to extract registers saved by
    _dl_runtime_resolve and put them into the new correctly sized
    La_aarch64_regs structure.

  * The LAV_CURRENT check is change to only accept new audit modules
    to avoid the undefined behavior of not save/restore x8.

  * Different than other architectures, audit modules older than
    LAV_CURRENT are rejected (both La_aarch64_regs and La_aarch64_retval
    changes layout and it does not work the complexity to support
    multiple audit interfaces).

Similar to x86, a new La_aarch64_vector type to represent the NEON
register is added on the La_aarch64_regs (so each type can be accessed
directly).

Since LAV_CURRENT was already bumped to support bind-now, there is
no need to increase it again.

Checked on aarch64-linux-gnu.

Co-authored-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
---
 NEWS                             |   4 +
 elf/rtld.c                       |   3 +-
 sysdeps/aarch64/Makefile         |  20 ++++
 sysdeps/aarch64/bits/link.h      |  26 +++--
 sysdeps/aarch64/dl-audit-check.h |  28 +++++
 sysdeps/aarch64/dl-link.sym      |   6 +-
 sysdeps/aarch64/dl-trampoline.S  |  97 +++++++++++------
 sysdeps/aarch64/tst-audit26.c    |  37 +++++++
 sysdeps/aarch64/tst-audit26mod.c |  33 ++++++
 sysdeps/aarch64/tst-audit26mod.h |  50 +++++++++
 sysdeps/aarch64/tst-audit27.c    |  64 +++++++++++
 sysdeps/aarch64/tst-audit27mod.c |  95 ++++++++++++++++
 sysdeps/aarch64/tst-audit27mod.h |  67 ++++++++++++
 sysdeps/aarch64/tst-auditmod26.c | 103 ++++++++++++++++++
 sysdeps/aarch64/tst-auditmod27.c | 180 +++++++++++++++++++++++++++++++
 sysdeps/generic/dl-audit-check.h |  23 ++++
 16 files changed, 789 insertions(+), 47 deletions(-)
 create mode 100644 sysdeps/aarch64/dl-audit-check.h
 create mode 100644 sysdeps/aarch64/tst-audit26.c
 create mode 100644 sysdeps/aarch64/tst-audit26mod.c
 create mode 100644 sysdeps/aarch64/tst-audit26mod.h
 create mode 100644 sysdeps/aarch64/tst-audit27.c
 create mode 100644 sysdeps/aarch64/tst-audit27mod.c
 create mode 100644 sysdeps/aarch64/tst-audit27mod.h
 create mode 100644 sysdeps/aarch64/tst-auditmod26.c
 create mode 100644 sysdeps/aarch64/tst-auditmod27.c
 create mode 100644 sysdeps/generic/dl-audit-check.h

diff --git a/NEWS b/NEWS
index 28e8564be9..5c2f9526a6 100644
--- a/NEWS
+++ b/NEWS
@@ -126,6 +126,10 @@ Deprecated and removed features, and other changes affecting compatibility:
   proper bind-now support.  The loader now advertise on the la_symbind
   flags that PLT trace is not possible.
 
+* The audit interface on aarch64 is extended to support both the indirect
+  result location register (x8) and NEON Q register.  This makes old audit
+  modules to be rejected by the loader.
+
 Changes to build and runtime requirements:
 
   [Add changes to build and runtime requirements here]
diff --git a/elf/rtld.c b/elf/rtld.c
index e78001c2a4..d0c7014a2b 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -51,6 +51,7 @@
 #include <dl-tunables.h>
 #include <get-dynamic-info.h>
 #include <dl-execve.h>
+#include <dl-audit-check.h>
 
 #include <assert.h>
 
@@ -992,7 +993,7 @@ file=%s [%lu]; audit interface function la_version returned zero; ignored.\n",
       return;
     }
 
-  if (lav > LAV_CURRENT)
+  if (!_dl_audit_check_version (lav))
     {
       _dl_debug_printf ("\
 ERROR: audit interface '%s' requires version %d (maximum supported version %d); ignored.\n",
diff --git a/sysdeps/aarch64/Makefile b/sysdeps/aarch64/Makefile
index 7c66fb97aa..7183895d04 100644
--- a/sysdeps/aarch64/Makefile
+++ b/sysdeps/aarch64/Makefile
@@ -10,6 +10,26 @@ endif
 
 ifeq ($(subdir),elf)
 sysdep-dl-routines += dl-bti
+
+tests += tst-audit26 \
+	 tst-audit27
+
+modules-names += \
+    tst-audit26mod \
+    tst-auditmod26 \
+    tst-audit27mod \
+    tst-auditmod27
+
+$(objpfx)tst-audit26: $(objpfx)tst-audit26mod.so \
+		      $(objpfx)tst-auditmod26.so
+LDFLAGS-tst-audit26 += -Wl,-z,lazy
+tst-audit26-ENV = LD_AUDIT=$(objpfx)tst-auditmod26.so
+
+$(objpfx)tst-audit27: $(objpfx)tst-audit27mod.so \
+		      $(objpfx)tst-auditmod27.so
+$(objpfx)tst-audit27mod.so: $(libsupport)
+LDFLAGS-tst-audit27 += -Wl,-z,lazy
+tst-audit27-ENV = LD_AUDIT=$(objpfx)tst-auditmod27.so
 endif
 
 ifeq ($(subdir),elf)
diff --git a/sysdeps/aarch64/bits/link.h b/sysdeps/aarch64/bits/link.h
index 774bbe5f45..c64726947c 100644
--- a/sysdeps/aarch64/bits/link.h
+++ b/sysdeps/aarch64/bits/link.h
@@ -20,23 +20,31 @@
 # error "Never include <bits/link.h> directly; use <link.h> instead."
 #endif
 
+typedef union
+{
+  float s;
+  double d;
+  long double q;
+} La_aarch64_vector;
+
 /* Registers for entry into PLT on AArch64.  */
 typedef struct La_aarch64_regs
 {
-  uint64_t lr_xreg[8];
-  uint64_t lr_dreg[8];
-  uint64_t lr_sp;
-  uint64_t lr_lr;
+  uint64_t          lr_xreg[9];
+  La_aarch64_vector lr_vreg[8];
+  uint64_t          lr_sp;
+  uint64_t          lr_lr;
+  void              *lr_vpcs;
 } La_aarch64_regs;
 
 /* Return values for calls from PLT on AArch64.  */
 typedef struct La_aarch64_retval
 {
-  /* Up to two integer registers can be used for a return value.  */
-  uint64_t lrv_xreg[2];
-  /* Up to four D registers can be used for a return value.  */
-  uint64_t lrv_dreg[4];
-
+  /* Up to eight integer registers can be used for a return value.  */
+  uint64_t          lrv_xreg[8];
+  /* Up to eight V registers can be used for a return value.  */
+  La_aarch64_vector lrv_vreg[8];
+  void              *lrv_vpcs;
 } La_aarch64_retval;
 __BEGIN_DECLS
 
diff --git a/sysdeps/aarch64/dl-audit-check.h b/sysdeps/aarch64/dl-audit-check.h
new file mode 100644
index 0000000000..0efb5de6b3
--- /dev/null
+++ b/sysdeps/aarch64/dl-audit-check.h
@@ -0,0 +1,28 @@
+/* rtld-audit version check.  AArch64 version.
+   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/>.  */
+
+static inline bool
+_dl_audit_check_version (unsigned int lav)
+{
+  /* Audit version 1 do not save neither x8 nor NEON register, which required
+     change La_aarch64_regs and La_aarch64_retval layout (BZ#26643).  The
+     missing indirect result save/restore makes _dl_runtime_profile
+     potentially trigger undefined behavior if function returns a large
+     struct (even when PLT trace is not requested).  */
+  return lav == LAV_CURRENT;
+}
diff --git a/sysdeps/aarch64/dl-link.sym b/sysdeps/aarch64/dl-link.sym
index d67d28b40c..cb4dcdcbed 100644
--- a/sysdeps/aarch64/dl-link.sym
+++ b/sysdeps/aarch64/dl-link.sym
@@ -7,9 +7,11 @@ DL_SIZEOF_RG		sizeof(struct La_aarch64_regs)
 DL_SIZEOF_RV		sizeof(struct La_aarch64_retval)
 
 DL_OFFSET_RG_X0		offsetof(struct La_aarch64_regs, lr_xreg)
-DL_OFFSET_RG_D0		offsetof(struct La_aarch64_regs, lr_dreg)
+DL_OFFSET_RG_V0		offsetof(struct La_aarch64_regs, lr_vreg)
 DL_OFFSET_RG_SP		offsetof(struct La_aarch64_regs, lr_sp)
 DL_OFFSET_RG_LR		offsetof(struct La_aarch64_regs, lr_lr)
+DL_OFFSET_RG_VPCS       offsetof(struct La_aarch64_regs, lr_vpcs)
 
 DL_OFFSET_RV_X0		offsetof(struct La_aarch64_retval, lrv_xreg)
-DL_OFFSET_RV_D0		offsetof(struct La_aarch64_retval, lrv_dreg)
+DL_OFFSET_RV_V0		offsetof(struct La_aarch64_retval, lrv_vreg)
+DL_OFFSET_RV_VPCS       offsetof(struct La_aarch64_retval, lrv_vpcs)
diff --git a/sysdeps/aarch64/dl-trampoline.S b/sysdeps/aarch64/dl-trampoline.S
index 9b352b1d0f..f402d03941 100644
--- a/sysdeps/aarch64/dl-trampoline.S
+++ b/sysdeps/aarch64/dl-trampoline.S
@@ -45,7 +45,8 @@ _dl_runtime_resolve:
 
 	cfi_rel_offset (lr, 8)
 
-	/* Save arguments.  */
+	/* Note: Saving x9 is not required by the ABI but the assember requires
+	   the immediate values of operand 3 to be a multiple of 16 */
 	stp	x8, x9, [sp, #-(80+8*16)]!
 	cfi_adjust_cfa_offset (80+8*16)
 	cfi_rel_offset (x8, 0)
@@ -142,13 +143,17 @@ _dl_runtime_profile:
 	   Stack frame layout:
 	   [sp,   #...] lr
 	   [sp,   #...] &PLTGOT[n]
-	   [sp,    #96] La_aarch64_regs
-	   [sp,    #48] La_aarch64_retval
-	   [sp,    #40] frame size return from pltenter
-	   [sp,    #32] dl_profile_call saved x1
-	   [sp,    #24] dl_profile_call saved x0
-	   [sp,    #16] t1
-	   [sp,     #0] x29, lr   <- x29
+	   -----------------------
+	   [sp,   #384] La_aarch64_regs::lr_xreg (x0-x8)
+	   [sp,   #256] La_aarch64_regs::lr_vreg (q0-q7)
+	   [sp,   #240] La_aarch64_regs::sp and La_aarch64_regs::lr
+	   [sp,   #176] La_aarch64_retval::lrv_xreg (x0-x7)
+	   [sp,   # 48] La_aarch64_retval::lrv_vreg (q0-q7)
+	   [sp,   # 40] frame size return from pltenter
+	   [sp,   # 32] dl_profile_call saved x1
+	   [sp,   # 24] dl_profile_call saved x0
+	   [sp,   # 16] t1
+	   [sp,   #  0] x29, lr   <- x29
 	 */
 
 # define OFFSET_T1		16
@@ -183,19 +188,25 @@ _dl_runtime_profile:
 	stp	x6, x7, [x29, #OFFSET_RG + DL_OFFSET_RG_X0 + 16*3]
 	cfi_rel_offset (x6, OFFSET_RG + DL_OFFSET_RG_X0 + 16*3 + 0)
 	cfi_rel_offset (x7, OFFSET_RG + DL_OFFSET_RG_X0 + 16*3 + 8)
-
-	stp	d0, d1, [X29, #OFFSET_RG + DL_OFFSET_RG_D0 + 16*0]
-	cfi_rel_offset (d0, OFFSET_RG + DL_OFFSET_RG_D0 + 16*0)
-	cfi_rel_offset (d1, OFFSET_RG + DL_OFFSET_RG_D0 + 16*0 + 8)
-	stp	d2, d3, [X29, #OFFSET_RG+ DL_OFFSET_RG_D0 + 16*1]
-	cfi_rel_offset (d2, OFFSET_RG + DL_OFFSET_RG_D0 + 16*1 + 0)
-	cfi_rel_offset (d3, OFFSET_RG + DL_OFFSET_RG_D0 + 16*1 + 8)
-	stp	d4, d5, [X29, #OFFSET_RG + DL_OFFSET_RG_D0 + 16*2]
-	cfi_rel_offset (d4, OFFSET_RG + DL_OFFSET_RG_D0 + 16*2 + 0)
-	cfi_rel_offset (d5, OFFSET_RG + DL_OFFSET_RG_D0 + 16*2 + 8)
-	stp	d6, d7, [X29, #OFFSET_RG + DL_OFFSET_RG_D0 + 16*3]
-	cfi_rel_offset (d6, OFFSET_RG + DL_OFFSET_RG_D0 + 16*3 + 0)
-	cfi_rel_offset (d7, OFFSET_RG + DL_OFFSET_RG_D0 + 16*3 + 8)
+	str	x8, [x29, #OFFSET_RG + DL_OFFSET_RG_X0 + 16*4 + 0]
+	cfi_rel_offset (x8, OFFSET_RG + DL_OFFSET_RG_X0 + 16*4 + 0)
+	/* Note 8 bytes of padding is in the stack frame for alignment */
+
+	stp	q0, q1, [X29, #OFFSET_RG + DL_OFFSET_RG_V0 + 32*0]
+	cfi_rel_offset (q0, OFFSET_RG + DL_OFFSET_RG_V0 + 32*0)
+	cfi_rel_offset (q1, OFFSET_RG + DL_OFFSET_RG_V0 + 32*0 + 16)
+	stp	q2, q3, [X29, #OFFSET_RG+ DL_OFFSET_RG_V0 + 32*1]
+	cfi_rel_offset (q2, OFFSET_RG + DL_OFFSET_RG_V0 + 32*1 + 0)
+	cfi_rel_offset (q3, OFFSET_RG + DL_OFFSET_RG_V0 + 32*1 + 16)
+	stp	q4, q5, [X29, #OFFSET_RG + DL_OFFSET_RG_V0 + 32*2]
+	cfi_rel_offset (q4, OFFSET_RG + DL_OFFSET_RG_V0 + 32*2 + 0)
+	cfi_rel_offset (q5, OFFSET_RG + DL_OFFSET_RG_V0 + 32*2 + 16)
+	stp	q6, q7, [X29, #OFFSET_RG + DL_OFFSET_RG_V0 + 32*3]
+	cfi_rel_offset (q6, OFFSET_RG + DL_OFFSET_RG_V0 + 32*3 + 0)
+	cfi_rel_offset (q7, OFFSET_RG + DL_OFFSET_RG_V0 + 32*3 + 16)
+
+	/* No APCS extension supported.  */
+	str	xzr,    [X29, #OFFSET_RG + DL_OFFSET_RG_VPCS]
 
 	add     x0, x29, #SF_SIZE + 16
 	ldr	x1, [x29, #OFFSET_LR]
@@ -234,10 +245,11 @@ _dl_runtime_profile:
 	ldp	x2, x3, [x29, #OFFSET_RG + DL_OFFSET_RG_X0 + 16*1]
 	ldp	x4, x5, [x29, #OFFSET_RG + DL_OFFSET_RG_X0 + 16*2]
 	ldp	x6, x7, [x29, #OFFSET_RG + DL_OFFSET_RG_X0 + 16*3]
-	ldp	d0, d1, [x29, #OFFSET_RG + DL_OFFSET_RG_D0 + 16*0]
-	ldp	d2, d3, [x29, #OFFSET_RG + DL_OFFSET_RG_D0 + 16*1]
-	ldp	d4, d5, [x29, #OFFSET_RG + DL_OFFSET_RG_D0 + 16*2]
-	ldp	d6, d7, [x29, #OFFSET_RG + DL_OFFSET_RG_D0 + 16*3]
+	ldr	x8,     [x29, #OFFSET_RG + DL_OFFSET_RG_X0 + 16*4]
+	ldp	q0, q1, [x29, #OFFSET_RG + DL_OFFSET_RG_V0 + 32*0]
+	ldp	q2, q3, [x29, #OFFSET_RG + DL_OFFSET_RG_V0 + 32*1]
+	ldp	q4, q5, [x29, #OFFSET_RG + DL_OFFSET_RG_V0 + 32*2]
+	ldp	q6, q7, [x29, #OFFSET_RG + DL_OFFSET_RG_V0 + 32*3]
 
 	cfi_def_cfa_register (sp)
 	ldp	x29, x30, [x29, #0]
@@ -280,14 +292,22 @@ _dl_runtime_profile:
 	ldp	x2, x3, [x29, #OFFSET_RG + DL_OFFSET_RG_X0 + 16*1]
 	ldp	x4, x5, [x29, #OFFSET_RG + DL_OFFSET_RG_X0 + 16*2]
 	ldp	x6, x7, [x29, #OFFSET_RG + DL_OFFSET_RG_X0 + 16*3]
-	ldp	d0, d1, [x29, #OFFSET_RG + DL_OFFSET_RG_D0 + 16*0]
-	ldp	d2, d3, [x29, #OFFSET_RG + DL_OFFSET_RG_D0 + 16*1]
-	ldp	d4, d5, [x29, #OFFSET_RG + DL_OFFSET_RG_D0 + 16*2]
-	ldp	d6, d7, [x29, #OFFSET_RG + DL_OFFSET_RG_D0 + 16*3]
+	ldr	x8,     [x29, #OFFSET_RG + DL_OFFSET_RG_X0 + 16*4]
+	ldp	q0, q1, [x29, #OFFSET_RG + DL_OFFSET_RG_V0 + 32*0]
+	ldp	q2, q3, [x29, #OFFSET_RG + DL_OFFSET_RG_V0 + 32*1]
+	ldp	q4, q5, [x29, #OFFSET_RG + DL_OFFSET_RG_V0 + 32*2]
+	ldp	q6, q7, [x29, #OFFSET_RG + DL_OFFSET_RG_V0 + 32*3]
 	blr	ip0
-	stp	x0, x1, [x29, #OFFSET_RV + DL_OFFSET_RV_X0]
-	stp	d0, d1, [x29, #OFFSET_RV + DL_OFFSET_RV_D0 + 16*0]
-	stp	d2, d3, [x29, #OFFSET_RV + DL_OFFSET_RV_D0 + 16*1]
+	stp	x0, x1, [x29, #OFFSET_RV + DL_OFFSET_RV_X0 + 16*0]
+	stp	x2, x3, [x29, #OFFSET_RV + DL_OFFSET_RV_X0 + 16*1]
+	stp	x4, x5, [x29, #OFFSET_RV + DL_OFFSET_RV_X0 + 16*2]
+	stp	x6, x7, [x29, #OFFSET_RV + DL_OFFSET_RV_X0 + 16*3]
+	str	x8,     [x29, #OFFSET_RG + DL_OFFSET_RG_X0 + 16*4]
+	stp	q0, q1, [x29, #OFFSET_RV + DL_OFFSET_RV_V0 + 32*0]
+	stp	q2, q3, [x29, #OFFSET_RV + DL_OFFSET_RV_V0 + 32*1]
+	stp	q4, q5, [x29, #OFFSET_RV + DL_OFFSET_RV_V0 + 32*2]
+	stp	q6, q7, [x29, #OFFSET_RV + DL_OFFSET_RV_V0 + 32*3]
+	str	xzr,    [X29, #OFFSET_RV + DL_OFFSET_RG_VPCS]
 
 	/* Setup call to pltexit  */
 	ldp	x0, x1, [x29, #OFFSET_SAVED_CALL_X0]
@@ -295,9 +315,16 @@ _dl_runtime_profile:
 	add	x3, x29, #OFFSET_RV
 	bl	_dl_audit_pltexit
 
-	ldp	x0, x1, [x29, #OFFSET_RV + DL_OFFSET_RV_X0]
-	ldp	d0, d1, [x29, #OFFSET_RV + DL_OFFSET_RV_D0 + 16*0]
-	ldp	d2, d3, [x29, #OFFSET_RV + DL_OFFSET_RV_D0 + 16*1]
+	ldp	x0, x1, [x29, #OFFSET_RV + DL_OFFSET_RV_X0 + 16*0]
+	ldp	x2, x3, [x29, #OFFSET_RV + DL_OFFSET_RV_X0 + 16*1]
+	ldp	x4, x5, [x29, #OFFSET_RV + DL_OFFSET_RV_X0 + 16*2]
+	ldp	x6, x7, [x29, #OFFSET_RV + DL_OFFSET_RV_X0 + 16*3]
+	ldr	x8,     [x29, #OFFSET_RV + DL_OFFSET_RV_X0 + 16*4]
+	ldp	q0, q1, [x29, #OFFSET_RV + DL_OFFSET_RV_V0 + 32*0]
+	ldp	q2, q3, [x29, #OFFSET_RV + DL_OFFSET_RV_V0 + 32*1]
+	ldp	q4, q5, [x29, #OFFSET_RV + DL_OFFSET_RV_V0 + 32*2]
+	ldp	q6, q7, [x29, #OFFSET_RV + DL_OFFSET_RV_V0 + 32*3]
+
 	/* LR from within La_aarch64_reg */
 	ldr	lr, [x29, #OFFSET_RG + DL_OFFSET_RG_LR]
 	cfi_restore(lr)
diff --git a/sysdeps/aarch64/tst-audit26.c b/sysdeps/aarch64/tst-audit26.c
new file mode 100644
index 0000000000..44d2479e08
--- /dev/null
+++ b/sysdeps/aarch64/tst-audit26.c
@@ -0,0 +1,37 @@
+/* Check DT_AUDIT for aarch64 ABI specifics.
+   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 <array_length.h>
+#include <string.h>
+#include <support/check.h>
+#include "tst-audit26mod.h"
+
+int
+do_test (void)
+{
+  /* Returning a large struct uses 'x8' as indirect result location.  */
+  struct large_struct r = tst_audit26_func (ARG1, ARG2, ARG3);
+
+  struct large_struct e = set_large_struct (ARG1, ARG2, ARG3);
+
+  TEST_COMPARE_BLOB (r.a, sizeof (r.a), e.a, sizeof (e.a));
+
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/sysdeps/aarch64/tst-audit26mod.c b/sysdeps/aarch64/tst-audit26mod.c
new file mode 100644
index 0000000000..f8d9270898
--- /dev/null
+++ b/sysdeps/aarch64/tst-audit26mod.c
@@ -0,0 +1,33 @@
+/* Check DT_AUDIT for aarch64 ABI specifics.
+   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 <stdlib.h>
+#include "tst-audit26mod.h"
+
+struct large_struct
+tst_audit26_func (char a, short b, long int c)
+{
+  if (a != ARG1)
+    abort ();
+  if (b != ARG2)
+    abort ();
+  if (c != ARG3)
+    abort ();
+
+  return set_large_struct (a, b, c);
+}
diff --git a/sysdeps/aarch64/tst-audit26mod.h b/sysdeps/aarch64/tst-audit26mod.h
new file mode 100644
index 0000000000..dd9ddcdada
--- /dev/null
+++ b/sysdeps/aarch64/tst-audit26mod.h
@@ -0,0 +1,50 @@
+/* Check DT_AUDIT for aarch64 specific ABI.
+   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/>.  */
+
+#ifndef _TST_AUDIT27MOD_H
+#define _TST_AUDIT27MOD_H 1
+
+#include <array_length.h>
+
+struct large_struct
+{
+  char a[16];
+  short b[8];
+  long int c[4];
+};
+
+static inline struct large_struct
+set_large_struct (char a, short b, long int c)
+{
+  struct large_struct r;
+  for (int i = 0; i < array_length (r.a); i++)
+    r.a[i] = a;
+  for (int i = 0; i < array_length (r.b); i++)
+    r.b[i] = b;
+  for (int i = 0; i < array_length (r.c); i++)
+    r.c[i] = c;
+  return r;
+}
+
+#define ARG1 0x12
+#define ARG2 0x1234
+#define ARG3 0x12345678
+
+struct large_struct tst_audit26_func (char a, short b, long int c);
+
+#endif
diff --git a/sysdeps/aarch64/tst-audit27.c b/sysdeps/aarch64/tst-audit27.c
new file mode 100644
index 0000000000..e19b58bc3b
--- /dev/null
+++ b/sysdeps/aarch64/tst-audit27.c
@@ -0,0 +1,64 @@
+/* Check DT_AUDIT for aarch64 ABI specifics.
+   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 <array_length.h>
+#include <string.h>
+#include <support/check.h>
+#include "tst-audit27mod.h"
+
+int
+do_test (void)
+{
+  {
+    float r = tst_audit27_func_float (FUNC_FLOAT_ARG0, FUNC_FLOAT_ARG1,
+				      FUNC_FLOAT_ARG2, FUNC_FLOAT_ARG3,
+				      FUNC_FLOAT_ARG4, FUNC_FLOAT_ARG5,
+				      FUNC_FLOAT_ARG6, FUNC_FLOAT_ARG7);
+    if (r != FUNC_FLOAT_RET)
+      FAIL_EXIT1 ("tst_audit27_func_float() returned %a, expected %a",
+		  r, FUNC_FLOAT_RET);
+  }
+
+  {
+    double r = tst_audit27_func_double (FUNC_DOUBLE_ARG0, FUNC_DOUBLE_ARG1,
+					FUNC_DOUBLE_ARG2, FUNC_DOUBLE_ARG3,
+					FUNC_DOUBLE_ARG4, FUNC_DOUBLE_ARG5,
+					FUNC_DOUBLE_ARG6, FUNC_DOUBLE_ARG7);
+    if (r != FUNC_DOUBLE_RET)
+      FAIL_EXIT1 ("tst_audit27_func_double() returned %la, expected %la",
+		  r, FUNC_DOUBLE_RET);
+  }
+
+  {
+    long double r = tst_audit27_func_ldouble (FUNC_LDOUBLE_ARG0,
+					      FUNC_LDOUBLE_ARG1,
+					      FUNC_LDOUBLE_ARG2,
+					      FUNC_LDOUBLE_ARG3,
+					      FUNC_LDOUBLE_ARG4,
+					      FUNC_LDOUBLE_ARG5,
+					      FUNC_LDOUBLE_ARG6,
+					      FUNC_LDOUBLE_ARG7);
+    if (r != FUNC_LDOUBLE_RET)
+      FAIL_EXIT1 ("tst_audit27_func_ldouble() returned %La, expected %La",
+		  r, FUNC_LDOUBLE_RET);
+  }
+
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/sysdeps/aarch64/tst-audit27mod.c b/sysdeps/aarch64/tst-audit27mod.c
new file mode 100644
index 0000000000..a8e8b28523
--- /dev/null
+++ b/sysdeps/aarch64/tst-audit27mod.c
@@ -0,0 +1,95 @@
+/* Check DT_AUDIT for aarch64 ABI specifics.
+   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 <array_length.h>
+#include <stdlib.h>
+#include <support/check.h>
+#include "tst-audit27mod.h"
+
+float
+tst_audit27_func_float (float a0, float a1, float a2, float a3, float a4,
+			float a5, float a6, float a7)
+{
+  if (a0 != FUNC_FLOAT_ARG0)
+    FAIL_EXIT1 ("a0: %a != %a", a0, FUNC_FLOAT_ARG0);
+  if (a1 != FUNC_FLOAT_ARG1)
+    FAIL_EXIT1 ("a1: %a != %a", a1, FUNC_FLOAT_ARG1);
+  if (a2 != FUNC_FLOAT_ARG2)
+    FAIL_EXIT1 ("a2: %a != %a", a2, FUNC_FLOAT_ARG2);
+  if (a3 != FUNC_FLOAT_ARG3)
+    FAIL_EXIT1 ("a3: %a != %a", a3, FUNC_FLOAT_ARG3);
+  if (a4 != FUNC_FLOAT_ARG4)
+    FAIL_EXIT1 ("a4: %a != %a", a4, FUNC_FLOAT_ARG4);
+  if (a5 != FUNC_FLOAT_ARG5)
+    FAIL_EXIT1 ("a5: %a != %a", a5, FUNC_FLOAT_ARG5);
+  if (a6 != FUNC_FLOAT_ARG6)
+    FAIL_EXIT1 ("a6: %a != %a", a6, FUNC_FLOAT_ARG6);
+  if (a7 != FUNC_FLOAT_ARG7)
+    FAIL_EXIT1 ("a7: %a != %a", a7, FUNC_FLOAT_ARG7);
+
+  return FUNC_FLOAT_RET;
+}
+
+double
+tst_audit27_func_double (double a0, double a1, double a2, double a3, double a4,
+			 double a5, double a6, double a7)
+{
+  if (a0 != FUNC_DOUBLE_ARG0)
+    FAIL_EXIT1 ("a0: %la != %la", a0, FUNC_DOUBLE_ARG0);
+  if (a1 != FUNC_DOUBLE_ARG1)
+    FAIL_EXIT1 ("a1: %la != %la", a1, FUNC_DOUBLE_ARG1);
+  if (a2 != FUNC_DOUBLE_ARG2)
+    FAIL_EXIT1 ("a2: %la != %la", a2, FUNC_DOUBLE_ARG2);
+  if (a3 != FUNC_DOUBLE_ARG3)
+    FAIL_EXIT1 ("a3: %la != %la", a3, FUNC_DOUBLE_ARG3);
+  if (a4 != FUNC_DOUBLE_ARG4)
+    FAIL_EXIT1 ("a4: %la != %la", a4, FUNC_DOUBLE_ARG4);
+  if (a5 != FUNC_DOUBLE_ARG5)
+    FAIL_EXIT1 ("a5: %la != %la", a5, FUNC_DOUBLE_ARG5);
+  if (a6 != FUNC_DOUBLE_ARG6)
+    FAIL_EXIT1 ("a6: %la != %la", a6, FUNC_DOUBLE_ARG6);
+  if (a7 != FUNC_DOUBLE_ARG7)
+    FAIL_EXIT1 ("a7: %la != %la", a7, FUNC_DOUBLE_ARG7);
+
+  return FUNC_DOUBLE_RET;
+}
+
+long double
+tst_audit27_func_ldouble (long double a0, long double a1, long double a2,
+			  long double a3, long double a4, long double a5,
+			  long double a6, long double a7)
+{
+  if (a0 != FUNC_LDOUBLE_ARG0)
+    FAIL_EXIT1 ("a0: %La != %La", a0, FUNC_LDOUBLE_ARG0);
+  if (a1 != FUNC_LDOUBLE_ARG1)
+    FAIL_EXIT1 ("a1: %La != %La", a1, FUNC_LDOUBLE_ARG1);
+  if (a2 != FUNC_LDOUBLE_ARG2)
+    FAIL_EXIT1 ("a2: %La != %La", a2, FUNC_LDOUBLE_ARG2);
+  if (a3 != FUNC_LDOUBLE_ARG3)
+    FAIL_EXIT1 ("a3: %La != %La", a3, FUNC_LDOUBLE_ARG3);
+  if (a4 != FUNC_LDOUBLE_ARG4)
+    FAIL_EXIT1 ("a4: %La != %La", a4, FUNC_LDOUBLE_ARG4);
+  if (a5 != FUNC_LDOUBLE_ARG5)
+    FAIL_EXIT1 ("a5: %La != %La", a5, FUNC_LDOUBLE_ARG5);
+  if (a6 != FUNC_LDOUBLE_ARG6)
+    FAIL_EXIT1 ("a6: %La != %La", a6, FUNC_LDOUBLE_ARG6);
+  if (a7 != FUNC_LDOUBLE_ARG7)
+    FAIL_EXIT1 ("a7: %La != %La", a7, FUNC_LDOUBLE_ARG7);
+
+  return FUNC_LDOUBLE_RET;
+}
diff --git a/sysdeps/aarch64/tst-audit27mod.h b/sysdeps/aarch64/tst-audit27mod.h
new file mode 100644
index 0000000000..cbd44c4bdf
--- /dev/null
+++ b/sysdeps/aarch64/tst-audit27mod.h
@@ -0,0 +1,67 @@
+/* Check DT_AUDIT for aarch64 specific ABI.
+   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/>.  */
+
+#ifndef _TST_AUDIT27MOD_H
+#define _TST_AUDIT27MOD_H 1
+
+#include <float.h>
+
+#define FUNC_FLOAT_ARG0 FLT_MIN
+#define FUNC_FLOAT_ARG1 FLT_MAX
+#define FUNC_FLOAT_ARG2 FLT_EPSILON
+#define FUNC_FLOAT_ARG3 FLT_TRUE_MIN
+#define FUNC_FLOAT_ARG4 0.0f
+#define FUNC_FLOAT_ARG5 1.0f
+#define FUNC_FLOAT_ARG6 2.0f
+#define FUNC_FLOAT_ARG7 3.0f
+#define FUNC_FLOAT_RET  4.0f
+
+float
+tst_audit27_func_float (float a0, float a1, float a2, float a3, float a4,
+			float a5, float a6, float a7);
+
+#define FUNC_DOUBLE_ARG0 DBL_MIN
+#define FUNC_DOUBLE_ARG1 DBL_MAX
+#define FUNC_DOUBLE_ARG2 DBL_EPSILON
+#define FUNC_DOUBLE_ARG3 DBL_TRUE_MIN
+#define FUNC_DOUBLE_ARG4 0.0
+#define FUNC_DOUBLE_ARG5 1.0
+#define FUNC_DOUBLE_ARG6 2.0
+#define FUNC_DOUBLE_ARG7 3.0
+#define FUNC_DOUBLE_RET  0x1.fffffe0000001p+127
+
+double
+tst_audit27_func_double (double a0, double a1, double a2, double a3, double a4,
+			 double a5, double a6, double a7);
+
+#define FUNC_LDOUBLE_ARG0 DBL_MAX + 1.0L
+#define FUNC_LDOUBLE_ARG1 DBL_MAX + 2.0L
+#define FUNC_LDOUBLE_ARG2 DBL_MAX + 3.0L
+#define FUNC_LDOUBLE_ARG3 DBL_MAX + 4.0L
+#define FUNC_LDOUBLE_ARG4 DBL_MAX + 5.0L
+#define FUNC_LDOUBLE_ARG5 DBL_MAX + 6.0L
+#define FUNC_LDOUBLE_ARG6 DBL_MAX + 7.0L
+#define FUNC_LDOUBLE_ARG7 DBL_MAX + 8.0L
+#define FUNC_LDOUBLE_RET  0x1.fffffffffffff000000000000001p+1023L
+
+long double
+tst_audit27_func_ldouble (long double a0, long double a1, long double a2,
+			  long double a3, long double a4, long double a5,
+			  long double a6, long double a7);
+
+#endif
diff --git a/sysdeps/aarch64/tst-auditmod26.c b/sysdeps/aarch64/tst-auditmod26.c
new file mode 100644
index 0000000000..e9d9ced331
--- /dev/null
+++ b/sysdeps/aarch64/tst-auditmod26.c
@@ -0,0 +1,103 @@
+/* Check DT_AUDIT for aarch64 specific ABI.
+   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 <assert.h>
+#include <link.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "tst-audit26mod.h"
+
+#define TEST_NAME  "tst-audit26"
+
+#define AUDIT26_COOKIE 0
+
+unsigned int
+la_version (unsigned int v)
+{
+  return v;
+}
+
+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;
+  uintptr_t ck = -1;
+  if (strncmp (l_name, TEST_NAME, strlen (TEST_NAME)) == 0)
+    ck = AUDIT26_COOKIE;
+  *cookie = ck;
+  printf ("objopen: %ld, %s [cookie=%ld]\n", lmid, l_name, ck);
+  return ck == -1 ? 0 : LA_FLG_BINDFROM | LA_FLG_BINDTO;
+}
+
+ElfW(Addr)
+la_aarch64_gnu_pltenter (ElfW(Sym) *sym __attribute__ ((unused)),
+                         unsigned int ndx __attribute__ ((unused)),
+                         uintptr_t *refcook, uintptr_t *defcook,
+                         La_aarch64_regs *regs, unsigned int *flags,
+                         const char *symname, long int *framesizep)
+{
+  printf ("pltenter: symname=%s, st_value=%#lx, ndx=%u, flags=%u\n",
+	  symname, (long int) sym->st_value, ndx, *flags);
+
+  if (strcmp (symname, "tst_audit26_func") == 0)
+    {
+      assert (regs->lr_xreg[0] == ARG1);
+      assert (regs->lr_xreg[1] == ARG2);
+      assert (regs->lr_xreg[2] == ARG3);
+    }
+  else
+    abort ();
+
+  assert (regs->lr_vpcs == 0);
+
+  /* Clobber 'x8'.  */
+  asm volatile ("mov x8, -1" : : : "x8");
+
+  *framesizep = 1024;
+
+  return sym->st_value;
+}
+
+unsigned int
+la_aarch64_gnu_pltexit (ElfW(Sym) *sym, unsigned int ndx, uintptr_t *refcook,
+                        uintptr_t *defcook,
+                        const struct La_aarch64_regs *inregs,
+                        struct La_aarch64_retval *outregs, const char *symname)
+{
+  printf ("pltexit: symname=%s, st_value=%#lx, ndx=%u\n",
+	  symname, (long int) sym->st_value, ndx);
+
+  if (strcmp (symname, "tst_audit26_func") == 0)
+    {
+      assert (inregs->lr_xreg[0] == ARG1);
+      assert (inregs->lr_xreg[1] == ARG2);
+      assert (inregs->lr_xreg[2] == ARG3);
+    }
+  else
+    abort ();
+
+  assert (inregs->lr_vpcs == 0);
+  assert (outregs->lrv_vpcs == 0);
+
+  /* Clobber 'x8'.  */
+  asm volatile ("mov x8, -1" : : : "x8");
+
+  return 0;
+}
diff --git a/sysdeps/aarch64/tst-auditmod27.c b/sysdeps/aarch64/tst-auditmod27.c
new file mode 100644
index 0000000000..c453775996
--- /dev/null
+++ b/sysdeps/aarch64/tst-auditmod27.c
@@ -0,0 +1,180 @@
+/* Check DT_AUDIT for aarch64 specific ABI.
+   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 <assert.h>
+#include <link.h>
+#include <string.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "tst-audit27mod.h"
+
+#define TEST_NAME  "tst-audit27"
+
+#define AUDIT27_COOKIE 0
+
+unsigned int
+la_version (unsigned int v)
+{
+  return v;
+}
+
+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;
+  uintptr_t ck = -1;
+  if (strncmp (l_name, TEST_NAME, strlen (TEST_NAME)) == 0)
+    ck = AUDIT27_COOKIE;
+  *cookie = ck;
+  printf ("objopen: %ld, %s [%ld]\n", lmid, l_name, ck);
+  return ck == -1 ? 0 : LA_FLG_BINDFROM | LA_FLG_BINDTO;
+}
+
+ElfW(Addr)
+la_aarch64_gnu_pltenter (ElfW(Sym) *sym, unsigned int ndx, uintptr_t *refcook,
+			 uintptr_t *defcook, La_aarch64_regs *regs,
+			 unsigned int *flags, const char *symname,
+			 long int *framesizep)
+{
+  printf ("pltenter: symname=%s, st_value=%#lx, ndx=%u, flags=%u\n",
+	  symname, (long int) sym->st_value, ndx, *flags);
+
+  if (strcmp (symname, "tst_audit27_func_float") == 0)
+    {
+      assert (regs->lr_vreg[0].s == FUNC_FLOAT_ARG0);
+      assert (regs->lr_vreg[1].s == FUNC_FLOAT_ARG1);
+      assert (regs->lr_vreg[2].s == FUNC_FLOAT_ARG2);
+      assert (regs->lr_vreg[3].s == FUNC_FLOAT_ARG3);
+      assert (regs->lr_vreg[4].s == FUNC_FLOAT_ARG4);
+      assert (regs->lr_vreg[5].s == FUNC_FLOAT_ARG5);
+      assert (regs->lr_vreg[6].s == FUNC_FLOAT_ARG6);
+      assert (regs->lr_vreg[7].s == FUNC_FLOAT_ARG7);
+    }
+  else if (strcmp (symname, "tst_audit27_func_double") == 0)
+    {
+      assert (regs->lr_vreg[0].d == FUNC_DOUBLE_ARG0);
+      assert (regs->lr_vreg[1].d == FUNC_DOUBLE_ARG1);
+      assert (regs->lr_vreg[2].d == FUNC_DOUBLE_ARG2);
+      assert (regs->lr_vreg[3].d == FUNC_DOUBLE_ARG3);
+      assert (regs->lr_vreg[4].d == FUNC_DOUBLE_ARG4);
+      assert (regs->lr_vreg[5].d == FUNC_DOUBLE_ARG5);
+      assert (regs->lr_vreg[6].d == FUNC_DOUBLE_ARG6);
+      assert (regs->lr_vreg[7].d == FUNC_DOUBLE_ARG7);
+    }
+  else if (strcmp (symname, "tst_audit27_func_ldouble") == 0)
+    {
+      assert (regs->lr_vreg[0].q == FUNC_LDOUBLE_ARG0);
+      assert (regs->lr_vreg[1].q == FUNC_LDOUBLE_ARG1);
+      assert (regs->lr_vreg[2].q == FUNC_LDOUBLE_ARG2);
+      assert (regs->lr_vreg[3].q == FUNC_LDOUBLE_ARG3);
+      assert (regs->lr_vreg[4].q == FUNC_LDOUBLE_ARG4);
+      assert (regs->lr_vreg[5].q == FUNC_LDOUBLE_ARG5);
+      assert (regs->lr_vreg[6].q == FUNC_LDOUBLE_ARG6);
+      assert (regs->lr_vreg[7].q == FUNC_LDOUBLE_ARG7);
+    }
+  else
+    abort ();
+
+  assert (regs->lr_vpcs == 0);
+
+  /* Clobber the q registers on exit.  */
+  uint8_t v = 0xff;
+  asm volatile ("dup v0.8b, %w0" : : "r" (v) : "v0");
+  asm volatile ("dup v1.8b, %w0" : : "r" (v) : "v1");
+  asm volatile ("dup v2.8b, %w0" : : "r" (v) : "v2");
+  asm volatile ("dup v3.8b, %w0" : : "r" (v) : "v3");
+  asm volatile ("dup v4.8b, %w0" : : "r" (v) : "v4");
+  asm volatile ("dup v5.8b, %w0" : : "r" (v) : "v5");
+  asm volatile ("dup v6.8b, %w0" : : "r" (v) : "v6");
+  asm volatile ("dup v7.8b, %w0" : : "r" (v) : "v7");
+
+  *framesizep = 1024;
+
+  return sym->st_value;
+}
+
+unsigned int
+la_aarch64_gnu_pltexit (ElfW(Sym) *sym, unsigned int ndx, uintptr_t *refcook,
+                        uintptr_t *defcook,
+			const struct La_aarch64_regs *inregs,
+                        struct La_aarch64_retval *outregs,
+			const char *symname)
+{
+  printf ("pltexit: symname=%s, st_value=%#lx, ndx=%u\n",
+	  symname, (long int) sym->st_value, ndx);
+
+  if (strcmp (symname, "tst_audit27_func_float") == 0)
+    {
+      assert (inregs->lr_vreg[0].s == FUNC_FLOAT_ARG0);
+      assert (inregs->lr_vreg[1].s == FUNC_FLOAT_ARG1);
+      assert (inregs->lr_vreg[2].s == FUNC_FLOAT_ARG2);
+      assert (inregs->lr_vreg[3].s == FUNC_FLOAT_ARG3);
+      assert (inregs->lr_vreg[4].s == FUNC_FLOAT_ARG4);
+      assert (inregs->lr_vreg[5].s == FUNC_FLOAT_ARG5);
+      assert (inregs->lr_vreg[6].s == FUNC_FLOAT_ARG6);
+      assert (inregs->lr_vreg[7].s == FUNC_FLOAT_ARG7);
+
+      assert (outregs->lrv_vreg[0].s == FUNC_FLOAT_RET);
+    }
+  else if (strcmp (symname, "tst_audit27_func_double") == 0)
+    {
+      assert (inregs->lr_vreg[0].d == FUNC_DOUBLE_ARG0);
+      assert (inregs->lr_vreg[1].d == FUNC_DOUBLE_ARG1);
+      assert (inregs->lr_vreg[2].d == FUNC_DOUBLE_ARG2);
+      assert (inregs->lr_vreg[3].d == FUNC_DOUBLE_ARG3);
+      assert (inregs->lr_vreg[4].d == FUNC_DOUBLE_ARG4);
+      assert (inregs->lr_vreg[5].d == FUNC_DOUBLE_ARG5);
+      assert (inregs->lr_vreg[6].d == FUNC_DOUBLE_ARG6);
+      assert (inregs->lr_vreg[7].d == FUNC_DOUBLE_ARG7);
+
+      assert (outregs->lrv_vreg[0].d == FUNC_DOUBLE_RET);
+    }
+  else if (strcmp (symname, "tst_audit27_func_ldouble") == 0)
+    {
+      assert (inregs->lr_vreg[0].q == FUNC_LDOUBLE_ARG0);
+      assert (inregs->lr_vreg[1].q == FUNC_LDOUBLE_ARG1);
+      assert (inregs->lr_vreg[2].q == FUNC_LDOUBLE_ARG2);
+      assert (inregs->lr_vreg[3].q == FUNC_LDOUBLE_ARG3);
+      assert (inregs->lr_vreg[4].q == FUNC_LDOUBLE_ARG4);
+      assert (inregs->lr_vreg[5].q == FUNC_LDOUBLE_ARG5);
+      assert (inregs->lr_vreg[6].q == FUNC_LDOUBLE_ARG6);
+      assert (inregs->lr_vreg[7].q == FUNC_LDOUBLE_ARG7);
+
+      assert (outregs->lrv_vreg[0].q == FUNC_LDOUBLE_RET);
+    }
+  else
+    abort ();
+
+  assert (inregs->lr_vpcs == 0);
+  assert (outregs->lrv_vpcs == 0);
+
+  /* Clobber the q registers on exit.  */
+  uint8_t v = 0xff;
+  asm volatile ("dup v0.8b, %w0" : : "r" (v) : "v0");
+  asm volatile ("dup v1.8b, %w0" : : "r" (v) : "v1");
+  asm volatile ("dup v2.8b, %w0" : : "r" (v) : "v2");
+  asm volatile ("dup v3.8b, %w0" : : "r" (v) : "v3");
+  asm volatile ("dup v4.8b, %w0" : : "r" (v) : "v4");
+  asm volatile ("dup v5.8b, %w0" : : "r" (v) : "v5");
+  asm volatile ("dup v6.8b, %w0" : : "r" (v) : "v6");
+  asm volatile ("dup v7.8b, %w0" : : "r" (v) : "v7");
+
+  return 0;
+}
diff --git a/sysdeps/generic/dl-audit-check.h b/sysdeps/generic/dl-audit-check.h
new file mode 100644
index 0000000000..f284382093
--- /dev/null
+++ b/sysdeps/generic/dl-audit-check.h
@@ -0,0 +1,23 @@
+/* rtld-audit version check.  Generic version.
+   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/>.  */
+
+static inline bool
+_dl_audit_check_version (unsigned int lav)
+{
+  return lav <= LAV_CURRENT;
+}
-- 
2.32.0


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

* Re: [PATCH v8 1/4] elf: Add la_activity during application exit
  2021-12-28 11:50 ` [PATCH v8 1/4] elf: Add la_activity during application exit Adhemerval Zanella
@ 2021-12-28 17:59   ` Jonathon Anderson
  2021-12-29 19:54     ` Adhemerval Zanella
  0 siblings, 1 reply; 10+ messages in thread
From: Jonathon Anderson @ 2021-12-28 17:59 UTC (permalink / raw)
  To: Adhemerval Zanella, libc-alpha
  Cc: John Mellor-Crummey, Ben Woodard, Florian Weimer

Thanks for the updated patch! The test looks much better now, I have a 
few minor comments on the details below.

-Jonathon

On 12/28/21 05:50, Adhemerval Zanella wrote:
> la_activity is not called during application exit, even though
> la_objclose is.
>
> Checked on x86_64-linux-gnu, i686-linux-gnu, and aarch64-linux-gnu.
>
> Reviewed-by: Florian Weimer<fweimer@redhat.com>
> ---
>   elf/Makefile         |   8 +-
>   elf/dl-fini.c        |  10 ++
>   elf/tst-audit23.c    | 214 +++++++++++++++++++++++++++++++++++++++++++
>   elf/tst-audit23mod.c |  23 +++++
>   elf/tst-auditmod23.c |  74 +++++++++++++++
>   5 files changed, 328 insertions(+), 1 deletion(-)
>   create mode 100644 elf/tst-audit23.c
>   create mode 100644 elf/tst-audit23mod.c
>   create mode 100644 elf/tst-auditmod23.c
>
> diff --git a/elf/Makefile b/elf/Makefile
> index d920586701..861c351510 100644
> --- a/elf/Makefile
> +++ b/elf/Makefile
> @@ -234,7 +234,7 @@ tests += restest1 preloadtest loadfail multiload origtest resolvfail \
>   	 tst-audit19b \
>   	 tst-audit20 \
>   	 tst-audit22 \
> -	 tst-rtld-run-static \
> +	 tst-audit23 \
>   #	 reldep9
>   tests-internal += loadtest unload unload2 circleload1 \
>   	 neededtest neededtest2 neededtest3 neededtest4 \
> @@ -386,6 +386,8 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \
>   		tst-audit19bmod \
>   		tst-auditmod20 \
>   		tst-auditmod22 \
> +		tst-auditmod23 \
> +		tst-audit23mod \
>   
>   # Most modules build with _ISOMAC defined, but those filtered out
>   # depend on internal headers.
> @@ -1604,6 +1606,10 @@ tst-audit20-ENV = LD_AUDIT=$(objpfx)tst-auditmod20.so
>   $(objpfx)tst-audit22.out: $(objpfx)tst-auditmod22.so
>   tst-audit22-ARGS = -- $(host-test-program-cmd)
>   
> +$(objpfx)tst-audit23.out: $(objpfx)tst-auditmod23.so \
> +			  $(objpfx)tst-audit23mod.so
> +tst-audit23-ARGS = -- $(host-test-program-cmd)
> +
>   # tst-sonamemove links against an older implementation of the library.
>   LDFLAGS-tst-sonamemove-linkmod1.so = \
>     -Wl,--version-script=tst-sonamemove-linkmod1.map \
> diff --git a/elf/dl-fini.c b/elf/dl-fini.c
> index b789cfb9f2..a955d0e207 100644
> --- a/elf/dl-fini.c
> +++ b/elf/dl-fini.c
> @@ -64,6 +64,11 @@ _dl_fini (void)
>   	__rtld_lock_unlock_recursive (GL(dl_load_lock));
>         else
>   	{
> +#ifdef SHARED
> +	  /* Auditing checkpoint: we will start deleting objects.  */
> +	  _dl_audit_activity_nsid (ns, LA_ACT_DELETE);
> +#endif
> +
>   	  /* Now we can allocate an array to hold all the pointers and
>   	     copy the pointers in.  */
>   	  struct link_map *maps[nloaded];
> @@ -153,6 +158,11 @@ _dl_fini (void)
>   	      /* Correct the previous increment.  */
>   	      --l->l_direct_opencount;
>   	    }
> +
> +#ifdef SHARED
> +	  /* Auditing checkpoint: we will start deleting objects.  */
> +	  _dl_audit_activity_nsid (ns, LA_ACT_CONSISTENT);
> +#endif
>   	}
>       }
>   
> diff --git a/elf/tst-audit23.c b/elf/tst-audit23.c
> new file mode 100644
> index 0000000000..1c2194f1a8
> --- /dev/null
> +++ b/elf/tst-audit23.c
> @@ -0,0 +1,214 @@
> +/* Check DT_AUDIT la_objopen and la_objclose for all objects.
> +   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 <errno.h>
> +#include <getopt.h>
> +#include <link.h>
> +#include <limits.h>
> +#include <inttypes.h>
> +#include <gnu/lib-names.h>
> +#include <string.h>
> +#include <stdlib.h>
> +#include <support/capture_subprocess.h>
> +#include <support/check.h>
> +#include <support/xstdio.h>
> +#include <support/xdlfcn.h>
> +#include <support/support.h>
> +
> +static int restart;
> +#define CMDLINE_OPTIONS \
> +  { "restart", no_argument, &restart, 1 },
> +
> +static int
> +handle_restart (void)
> +{
> +  xdlopen ("tst-audit23mod.so", RTLD_NOW);
> +  xdlmopen (LM_ID_NEWLM, LIBC_SO, RTLD_NOW);
> +
> +  return 0;
> +}
> +
> +static inline bool
> +startswith (const char *str, const char *pre)
> +{
> +  size_t lenpre = strlen (pre);
> +  size_t lenstr = strlen (str);
> +  return lenstr >= lenpre && memcmp (pre, str, lenpre) == 0;
> +}
> +
> +static inline bool
> +is_vdso (const char *str)
> +{
> +  return startswith (str, "linux-gate")
> +	 || startswith (str, "linux-vdso");
> +}
> +
> +static int
> +do_test (int argc, char *argv[])
> +{
> +  /* We must have either:
> +     - One our fource parameters left if called initially:
> +       + path to ld.so         optional
> +       + "--library-path"      optional
> +       + the library path      optional
> +       + the application name  */
> +  if (restart)
> +    return handle_restart ();
> +
> +  char *spargv[9];
> +  int i = 0;
> +  for (; i < argc - 1; i++)
> +    spargv[i] = argv[i + 1];
> +  spargv[i++] = (char *) "--direct";
> +  spargv[i++] = (char *) "--restart";
> +  spargv[i] = NULL;
> +
> +  setenv ("LD_AUDIT", "tst-auditmod23.so", 0);
> +  struct support_capture_subprocess result
> +    = support_capture_subprogram (spargv[0], spargv);
> +  support_capture_subprocess_check (&result, "tst-audit22", 0, sc_allow_stderr);
> +
> +  /* The expected la_objopen/la_objclose:
> +     1. executable
> +     2. loader
> +     3. libc.so
> +     4. tst-audit23mod.so
> +     5. libc.so (LM_ID_NEWLM).
> +     6. vdso (optional and ignored).  */
> +  enum { max_objs = 6 };
> +  struct la_obj_t
> +  {
> +    char *lname;
> +    uintptr_t laddr;
> +    Lmid_t lmid;
> +    bool closed;
> +  } objs[max_objs] = { [0 ... max_objs-1] = { .closed = false } };
> +  size_t nobjs = 0;
> +
> +  /* The expected namespaces are one for the audit module and another for
> +     the application.  */
This should be 2 namespaces for the application, the audit module does 
not get la_* callbacks for itself. AFAICT the second namespace is used 
by the dlmopen call in the test body (handle_restart).
> +  enum { max_ns = 2 };
> +  uintptr_t acts[max_ns];
> +  size_t nacts = 0;
> +  int last_act = -1;
> +  uintptr_t last_act_cookie = -1;
> +
> +  FILE *out = fmemopen (result.err.buffer, result.err.length, "r");
> +  TEST_VERIFY (out != NULL);
> +  char *buffer = NULL;
> +  size_t buffer_length = 0;
> +  while (xgetline (&buffer, &buffer_length, out))
> +    {
> +      printf ("%s", buffer);
> +      if (startswith (buffer, "la_activity: "))
> +	{
> +	  uintptr_t cookie;
> +	  int r = sscanf (buffer + strlen ("la_activity: "),
> +			  "%d %"SCNxPTR"", &last_act, &cookie);
> +	  TEST_COMPARE (r, 2);
> +	  /* The cookie identifies the object at the head of the link map,
> +	     so we only add a new namespace if it changes from previous
> +	     one.  */
> +	  if (last_act == LA_ACT_ADD && acts[nacts - 1] != cookie)
> +	    acts[nacts++] = cookie;
This works since the dlmopen is second/last in the test body. If there 
was another dlopen this would consider it a third namespace. Should this 
be noted in the comment?

This also does not abort if nacts > max_ns, which could cause a stack 
buffer overflow.
> +	  /* The LA_ACT_DELETE is called in the reverse order of
> +	     LA_ACT_ADD.  */
> +	  else if (last_act == LA_ACT_DELETE && cookie != last_act_cookie)
> +	    {
> +	      last_act_cookie = acts[--nacts];
> +	      TEST_COMPARE (acts[nacts], cookie);
> +	      acts[nacts] = 0;
> +	    }
Not sure about this one yet. Is this always the case or only because 
there are exactly 2 audited namespaces?

Also, this works since la_activity(LA_ACT_DELETE) is only called at 
program termination. If dlclose was called in the test body (or a dlopen 
of a library missing dependencies) this might fail. Should this be noted 
in the comment?
> +	}
> +      else if (startswith (buffer, "la_objopen: "))
> +	{
> +	  char *lname;
> +	  uintptr_t laddr;
> +	  Lmid_t lmid;
> +	  uintptr_t cookie;
> +	  int r = sscanf (buffer + strlen ("la_objopen: "),
> +			  "%"SCNxPTR"  %ms %"SCNxPTR" %ld", &cookie, &lname,
> +			  &laddr, &lmid);
> +	  TEST_COMPARE (r, 4);
> +
> +	  /* la_objclose is not triggered by vDSO because glibc does not
> +	     unload it.  */
> +	  if (is_vdso (lname))
> +	    continue;
> +	  if (nobjs == max_objs)
> +	    FAIL_EXIT1 ("non expected la_objopen: %s %"PRIxPTR" %ld",
> +			lname, laddr, lmid);
> +	  objs[nobjs].lname = lname;
> +	  objs[nobjs].laddr = laddr;
> +	  objs[nobjs].lmid = lmid;
> +	  objs[nobjs].closed = false;
> +	  nobjs++;
> +	}
> +      else if (startswith (buffer, "la_objclose: "))
> +	{
> +	  char *lname;
> +	  uintptr_t laddr;
> +	  Lmid_t lmid;
> +	  uintptr_t cookie;
> +	  int r = sscanf (buffer + strlen ("la_objclose: "),
> +			  "%"SCNxPTR" %ms %"SCNxPTR" %ld", &cookie, &lname,
> +			  &laddr, &lmid);
> +	  TEST_COMPARE (r, 4);
> +
> +	  for (size_t i = 0; i < nobjs; i++)
> +	    {
> +	      if (strcmp (lname, objs[i].lname) == 0 && lmid == objs[i].lmid)
> +		{
> +		  TEST_COMPARE (objs[i].closed, false);
> +		  objs[i].closed = true;
> +		  break;
> +		}
> +	    }
> +
> +	  /* la_objclose should be called after la_activity(LA_ACT_DELETE) for
> +	     the closed object's namespace.  */
> +	  TEST_COMPARE (last_act, LA_ACT_DELETE);
> +	  if (last_act_cookie != 0)
> +	    {
> +	      TEST_COMPARE (last_act_cookie, cookie);
> +	      last_act_cookie = 0;
> +	    }
This works because the la_objclose order for program termination is the 
same as the order in the link map (implementation detail), and because 
la_objclose is only called during program termination in this test. If 
dlclose was called in the test body this would fail. Should this be 
noted in the comment?
> +	}
> +    }
> +
> +  for (size_t i = 0; i < nobjs; i++)
> +    {
> +      TEST_COMPARE (objs[i].closed, true);
> +      free (objs[i].lname);
> +    }
> +
> +  /* la_activity(LA_ACT_CONSISTENT) should be the last callback received for
> +     every namespace.  */
> +  TEST_COMPARE (last_act, LA_ACT_CONSISTENT);
This only checks the last la_activity notification (AFAICT the main 
namespace), rather than the last for each namespace.
> +  /* Sanity check to check if all LA_ACT_DELETE are matched with
> +     la_objclose.  */
> +  TEST_COMPARE (last_act_cookie, 0);
Similarly, this only checks the last LA_ACT_DELETE notification, rather 
than last for each namespace.
> +
> +  free (buffer);
> +  xfclose (out);
> +
> +  return 0;
> +}
> +
> +#define TEST_FUNCTION_ARGV do_test
> +#include <support/test-driver.c>
> diff --git a/elf/tst-audit23mod.c b/elf/tst-audit23mod.c
> new file mode 100644
> index 0000000000..4ca66cf772
> --- /dev/null
> +++ b/elf/tst-audit23mod.c
> @@ -0,0 +1,23 @@
> +/* Extra modules for tst-audit23
> +   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/>.  */
> +
> +int
> +foo (void)
> +{
> +  return 0;
> +}
> diff --git a/elf/tst-auditmod23.c b/elf/tst-auditmod23.c
> new file mode 100644
> index 0000000000..7a6d24ee80
> --- /dev/null
> +++ b/elf/tst-auditmod23.c
> @@ -0,0 +1,74 @@
> +/* Audit modules loaded by tst-audit23.
> +   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 <link.h>
> +#include <inttypes.h>
> +#include <stdlib.h>
> +#include <stdio.h>
> +#include <string.h>
> +#include <sys/auxv.h>
> +
> +unsigned int
> +la_version (unsigned int version)
> +{
> +  return LAV_CURRENT;
> +}
> +
> +struct map_desc_t
> +{
> +  char *lname;
> +  uintptr_t laddr;
> +  Lmid_t lmid;
> +};
> +
> +void
> +la_activity (uintptr_t *cookie, unsigned int flag)
> +{
> +  fprintf (stderr, "%s: %d %"PRIxPTR"\n", __func__, flag, (uintptr_t) cookie);
> +}
> +
> +unsigned int
> +la_objopen (struct link_map *map, Lmid_t lmid, uintptr_t *cookie)
> +{
> +  const char *l_name = map->l_name[0] == '\0' ? "mainapp" : map->l_name;
> +  fprintf (stderr, "%s: %"PRIxPTR" %s %"PRIxPTR" %ld\n", __func__,
> +	   (uintptr_t) cookie, l_name, map->l_addr, lmid);
> +
> +  struct map_desc_t *map_desc = malloc (sizeof (struct map_desc_t));
> +  if (map_desc == NULL)
> +    abort ();
> +
> +  map_desc->lname = strdup (l_name);
> +  map_desc->laddr = map->l_addr;
> +  map_desc->lmid = lmid;
> +
> +  *cookie = (uintptr_t) map_desc;
> +
> +  return 0;
> +}
> +
> +unsigned int
> +la_objclose (uintptr_t *cookie)
> +{
> +  struct map_desc_t *map_desc = (struct map_desc_t *) *cookie;
> +  fprintf (stderr, "%s: %"PRIxPTR" %s %"PRIxPTR" %ld\n", __func__,
> +	   (uintptr_t) cookie, map_desc->lname, map_desc->laddr,
> +	   map_desc->lmid);
> +
> +  return 0;
> +}


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

* Re: [PATCH v8 1/4] elf: Add la_activity during application exit
  2021-12-28 17:59   ` Jonathon Anderson
@ 2021-12-29 19:54     ` Adhemerval Zanella
  2021-12-30 21:35       ` Jonathon Anderson
  0 siblings, 1 reply; 10+ messages in thread
From: Adhemerval Zanella @ 2021-12-29 19:54 UTC (permalink / raw)
  To: Jonathon Anderson, libc-alpha
  Cc: John Mellor-Crummey, Ben Woodard, Florian Weimer



On 28/12/2021 14:59, Jonathon Anderson wrote:
> Thanks for the updated patch! The test looks much better now, I have a few minor comments on the details below.
> 
> -Jonathon
> 
> On 12/28/21 05:50, Adhemerval Zanella wrote:
>> +  /* The expected la_objopen/la_objclose:
>> +     1. executable
>> +     2. loader
>> +     3. libc.so
>> +     4. tst-audit23mod.so
>> +     5. libc.so (LM_ID_NEWLM).
>> +     6. vdso (optional and ignored).  */
>> +  enum { max_objs = 6 };
>> +  struct la_obj_t
>> +  {
>> +    char *lname;
>> +    uintptr_t laddr;
>> +    Lmid_t lmid;
>> +    bool closed;
>> +  } objs[max_objs] = { [0 ... max_objs-1] = { .closed = false } };
>> +  size_t nobjs = 0;
>> +
>> +  /* The expected namespaces are one for the audit module and another for
>> +     the application.  */
> This should be 2 namespaces for the application, the audit module does not get la_* callbacks for itself. AFAICT the second namespace is used by the dlmopen call in the test body (handle_restart).

You are right, I forgot about the dlmopen usage.  I have adjusted the comment
to:

  /* The expected namespaces are one for the audit module, one for the
     application, and another for the dlmopen on handle_restart.  */

>> +  enum { max_ns = 2 };
>> +  uintptr_t acts[max_ns];
>> +  size_t nacts = 0;
>> +  int last_act = -1;
>> +  uintptr_t last_act_cookie = -1;
>> +
>> +  FILE *out = fmemopen (result.err.buffer, result.err.length, "r");
>> +  TEST_VERIFY (out != NULL);
>> +  char *buffer = NULL;
>> +  size_t buffer_length = 0;
>> +  while (xgetline (&buffer, &buffer_length, out))
>> +    {
>> +      printf ("%s", buffer);
>> +      if (startswith (buffer, "la_activity: "))
>> +    {
>> +      uintptr_t cookie;
>> +      int r = sscanf (buffer + strlen ("la_activity: "),
>> +              "%d %"SCNxPTR"", &last_act, &cookie);
>> +      TEST_COMPARE (r, 2);
>> +      /* The cookie identifies the object at the head of the link map,
>> +         so we only add a new namespace if it changes from previous
>> +         one.  */
>> +      if (last_act == LA_ACT_ADD && acts[nacts - 1] != cookie)
>> +        acts[nacts++] = cookie;
> This works since the dlmopen is second/last in the test body. If there was another dlopen this would consider it a third namespace. Should this be noted in the comment?

I thin it is worth to comment it, I have changed the comment to:

 /* The cookie identifies the object at the head of the link map,
    so we only add a new namespace if it changes from previous
    one.  This work since dlmopen is the last in the test body.  */

> 
> This also does not abort if nacts > max_ns, which could cause a stack buffer overflow.
>> +      /* The LA_ACT_DELETE is called in the reverse order of
>> +         LA_ACT_ADD.  */
>> +      else if (last_act == LA_ACT_DELETE && cookie != last_act_cookie)
>> +        {
>> +          last_act_cookie = acts[--nacts];
>> +          TEST_COMPARE (acts[nacts], cookie);
>> +          acts[nacts] = 0;
>> +        }
> Not sure about this one yet. Is this always the case or only because there are exactly 2 audited namespaces?
> 
> Also, this works since la_activity(LA_ACT_DELETE) is only called at program termination. If dlclose was called in the test body (or a dlopen of a library missing dependencies) this might fail. Should this be noted in the comment?

Yeah, this works because there is no dlclose before program termination 
and tst-audit23mod.so does not have any dependency not already mapped.
I have changed the comment to:

 /* The LA_ACT_DELETE is called in the reverse order of LA_ACT_ADD
    at program termination (if the tests adds a dlclose or a library
    with extra dependencies this require to be adapted).  */

>> +    }
>> +      else if (startswith (buffer, "la_objopen: "))
>> +    {
>> +      char *lname;
>> +      uintptr_t laddr;
>> +      Lmid_t lmid;
>> +      uintptr_t cookie;
>> +      int r = sscanf (buffer + strlen ("la_objopen: "),
>> +              "%"SCNxPTR"  %ms %"SCNxPTR" %ld", &cookie, &lname,
>> +              &laddr, &lmid);
>> +      TEST_COMPARE (r, 4);
>> +
>> +      /* la_objclose is not triggered by vDSO because glibc does not
>> +         unload it.  */
>> +      if (is_vdso (lname))
>> +        continue;
>> +      if (nobjs == max_objs)
>> +        FAIL_EXIT1 ("non expected la_objopen: %s %"PRIxPTR" %ld",
>> +            lname, laddr, lmid);
>> +      objs[nobjs].lname = lname;
>> +      objs[nobjs].laddr = laddr;
>> +      objs[nobjs].lmid = lmid;
>> +      objs[nobjs].closed = false;
>> +      nobjs++;
>> +    }
>> +      else if (startswith (buffer, "la_objclose: "))
>> +    {
>> +      char *lname;
>> +      uintptr_t laddr;
>> +      Lmid_t lmid;
>> +      uintptr_t cookie;
>> +      int r = sscanf (buffer + strlen ("la_objclose: "),
>> +              "%"SCNxPTR" %ms %"SCNxPTR" %ld", &cookie, &lname,
>> +              &laddr, &lmid);
>> +      TEST_COMPARE (r, 4);
>> +
>> +      for (size_t i = 0; i < nobjs; i++)
>> +        {
>> +          if (strcmp (lname, objs[i].lname) == 0 && lmid == objs[i].lmid)
>> +        {
>> +          TEST_COMPARE (objs[i].closed, false);
>> +          objs[i].closed = true;
>> +          break;
>> +        }
>> +        }
>> +
>> +      /* la_objclose should be called after la_activity(LA_ACT_DELETE) for
>> +         the closed object's namespace.  */
>> +      TEST_COMPARE (last_act, LA_ACT_DELETE);
>> +      if (last_act_cookie != 0)
>> +        {
>> +          TEST_COMPARE (last_act_cookie, cookie);
>> +          last_act_cookie = 0;
>> +        }
> This works because the la_objclose order for program termination is the same as the order in the link map (implementation detail), and because la_objclose is only called during program termination in this test. If dlclose was called in the test body this would fail. Should this be noted in the comment?

I think it makes way more sense to tie to the DT_FINI/DT_FINI_ARRAY execution 
order, but I agree it is an implementation detail (we could just iterate over
the namespace lists and call it for each objects as well).

I think the above comments it should be clear that if someone want to test
dlclose or shared objects with more dependencies, the tests will need to be
adapted.

>> +    }
>> +    }
>> +
>> +  for (size_t i = 0; i < nobjs; i++)
>> +    {
>> +      TEST_COMPARE (objs[i].closed, true);
>> +      free (objs[i].lname);
>> +    }
>> +
>> +  /* la_activity(LA_ACT_CONSISTENT) should be the last callback received for
>> +     every namespace.  */
>> +  TEST_COMPARE (last_act, LA_ACT_CONSISTENT);
> This only checks the last la_activity notification (AFAICT the main namespace), rather than the last for each namespace.
>> +  /* Sanity check to check if all LA_ACT_DELETE are matched with
>> +     la_objclose.  */
>> +  TEST_COMPARE (last_act_cookie, 0);
> Similarly, this only checks the last LA_ACT_DELETE notification, rather than last for each namespace.

Indeed I agree we can increase the coverage of both tests, I have added
a better la_activity and LA_ACT_DELETE one.

Below it is the updated version:

--

diff --git a/elf/Makefile b/elf/Makefile
index b23d17fd39..fe1a50fac0 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -240,7 +240,7 @@ tests += restest1 preloadtest loadfail multiload origtest resolvfail \
 	 tst-audit19b \
 	 tst-audit20 \
 	 tst-audit22 \
-	 tst-rtld-run-static \
+	 tst-audit23 \
 #	 reldep9
 tests-internal += loadtest unload unload2 circleload1 \
 	 neededtest neededtest2 neededtest3 neededtest4 \
@@ -393,6 +393,8 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \
 		tst-audit19bmod \
 		tst-auditmod20 \
 		tst-auditmod22 \
+		tst-auditmod23 \
+		tst-audit23mod \
 		tst-dl_find_object-mod1 \
 		tst-dl_find_object-mod2 \
 		tst-dl_find_object-mod3 \
@@ -1620,6 +1622,10 @@ tst-audit20-ENV = LD_AUDIT=$(objpfx)tst-auditmod20.so
 $(objpfx)tst-audit22.out: $(objpfx)tst-auditmod22.so
 tst-audit22-ARGS = -- $(host-test-program-cmd)
 
+$(objpfx)tst-audit23.out: $(objpfx)tst-auditmod23.so \
+			  $(objpfx)tst-audit23mod.so
+tst-audit23-ARGS = -- $(host-test-program-cmd)
+
 # tst-sonamemove links against an older implementation of the library.
 LDFLAGS-tst-sonamemove-linkmod1.so = \
   -Wl,--version-script=tst-sonamemove-linkmod1.map \
diff --git a/elf/dl-fini.c b/elf/dl-fini.c
index b789cfb9f2..a955d0e207 100644
--- a/elf/dl-fini.c
+++ b/elf/dl-fini.c
@@ -64,6 +64,11 @@ _dl_fini (void)
 	__rtld_lock_unlock_recursive (GL(dl_load_lock));
       else
 	{
+#ifdef SHARED
+	  /* Auditing checkpoint: we will start deleting objects.  */
+	  _dl_audit_activity_nsid (ns, LA_ACT_DELETE);
+#endif
+
 	  /* Now we can allocate an array to hold all the pointers and
 	     copy the pointers in.  */
 	  struct link_map *maps[nloaded];
@@ -153,6 +158,11 @@ _dl_fini (void)
 	      /* Correct the previous increment.  */
 	      --l->l_direct_opencount;
 	    }
+
+#ifdef SHARED
+	  /* Auditing checkpoint: we will start deleting objects.  */
+	  _dl_audit_activity_nsid (ns, LA_ACT_CONSISTENT);
+#endif
 	}
     }
 
diff --git a/elf/tst-audit23.c b/elf/tst-audit23.c
new file mode 100644
index 0000000000..63a0b3311b
--- /dev/null
+++ b/elf/tst-audit23.c
@@ -0,0 +1,222 @@
+/* Check DT_AUDIT la_objopen and la_objclose for all objects.
+   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 <errno.h>
+#include <getopt.h>
+#include <link.h>
+#include <limits.h>
+#include <inttypes.h>
+#include <gnu/lib-names.h>
+#include <string.h>
+#include <stdlib.h>
+#include <support/capture_subprocess.h>
+#include <support/check.h>
+#include <support/xstdio.h>
+#include <support/xdlfcn.h>
+#include <support/support.h>
+
+static int restart;
+#define CMDLINE_OPTIONS \
+  { "restart", no_argument, &restart, 1 },
+
+static int
+handle_restart (void)
+{
+  xdlopen ("tst-audit23mod.so", RTLD_NOW);
+  xdlmopen (LM_ID_NEWLM, LIBC_SO, RTLD_NOW);
+
+  return 0;
+}
+
+static inline bool
+startswith (const char *str, const char *pre)
+{
+  size_t lenpre = strlen (pre);
+  size_t lenstr = strlen (str);
+  return lenstr >= lenpre && memcmp (pre, str, lenpre) == 0;
+}
+
+static inline bool
+is_vdso (const char *str)
+{
+  return startswith (str, "linux-gate")
+	 || startswith (str, "linux-vdso");
+}
+
+static int
+do_test (int argc, char *argv[])
+{
+  /* We must have either:
+     - One our fource parameters left if called initially:
+       + path to ld.so         optional
+       + "--library-path"      optional
+       + the library path      optional
+       + the application name  */
+  if (restart)
+    return handle_restart ();
+
+  char *spargv[9];
+  int i = 0;
+  for (; i < argc - 1; i++)
+    spargv[i] = argv[i + 1];
+  spargv[i++] = (char *) "--direct";
+  spargv[i++] = (char *) "--restart";
+  spargv[i] = NULL;
+
+  setenv ("LD_AUDIT", "tst-auditmod23.so", 0);
+  struct support_capture_subprocess result
+    = support_capture_subprogram (spargv[0], spargv);
+  support_capture_subprocess_check (&result, "tst-audit22", 0, sc_allow_stderr);
+
+  /* The expected la_objopen/la_objclose:
+     1. executable
+     2. loader
+     3. libc.so
+     4. tst-audit23mod.so
+     5. libc.so (LM_ID_NEWLM).
+     6. vdso (optional and ignored).  */
+  enum { max_objs = 6 };
+  struct la_obj_t
+  {
+    char *lname;
+    uintptr_t laddr;
+    Lmid_t lmid;
+    bool closed;
+  } objs[max_objs] = { [0 ... max_objs-1] = { .closed = false } };
+  size_t nobjs = 0;
+
+  /* The expected namespaces are one for the audit module, one for the
+     application, and another for the dlmopen on handle_restart.  */
+  enum { max_ns = 3 };
+  uintptr_t acts[max_ns];
+  size_t nacts = 0;
+  int last_act = -1;
+  uintptr_t last_act_cookie = -1;
+  bool first_objclose = false;
+
+  FILE *out = fmemopen (result.err.buffer, result.err.length, "r");
+  TEST_VERIFY (out != NULL);
+  char *buffer = NULL;
+  size_t buffer_length = 0;
+  while (xgetline (&buffer, &buffer_length, out))
+    {
+      printf ("%s", buffer);
+      if (startswith (buffer, "la_activity: "))
+	{
+	  uintptr_t cookie;
+	  int r = sscanf (buffer + strlen ("la_activity: "),
+			  "%d %"SCNxPTR"", &last_act, &cookie);
+	  TEST_COMPARE (r, 2);
+	  /* The cookie identifies the object at the head of the link map,
+	     so we only add a new namespace if it changes from previous
+	     one.  This work since dlmopen is the last in the test body.  */
+	  if (last_act == LA_ACT_ADD && acts[nacts - 1] != cookie)
+	    {
+	      acts[nacts++] = cookie;
+	      last_act_cookie = cookie;
+	    }
+	  /* The LA_ACT_DELETE is called in the reverse order of LA_ACT_ADD
+	     at program termination (if the tests adds a dlclose or a library
+	     with extra dependencies this require to be adapted).  */
+	  else if (last_act == LA_ACT_DELETE) // && cookie != last_act_cookie)
+	    {
+	      last_act_cookie = acts[--nacts];
+	      TEST_COMPARE (acts[nacts], cookie);
+	      acts[nacts] = 0;
+	    }
+	  else if (last_act == LA_ACT_CONSISTENT)
+	    TEST_COMPARE (cookie, last_act_cookie);
+
+	  first_objclose = false;
+	}
+      else if (startswith (buffer, "la_objopen: "))
+	{
+	  char *lname;
+	  uintptr_t laddr;
+	  Lmid_t lmid;
+	  uintptr_t cookie;
+	  int r = sscanf (buffer + strlen ("la_objopen: "),
+			  "%"SCNxPTR"  %ms %"SCNxPTR" %ld", &cookie, &lname,
+			  &laddr, &lmid);
+	  TEST_COMPARE (r, 4);
+
+	  /* la_objclose is not triggered by vDSO because glibc does not
+	     unload it.  */
+	  if (is_vdso (lname))
+	    continue;
+	  if (nobjs == max_objs)
+	    FAIL_EXIT1 ("non expected la_objopen: %s %"PRIxPTR" %ld",
+			lname, laddr, lmid);
+	  objs[nobjs].lname = lname;
+	  objs[nobjs].laddr = laddr;
+	  objs[nobjs].lmid = lmid;
+	  objs[nobjs].closed = false;
+	  nobjs++;
+
+	  first_objclose = false;
+	}
+      else if (startswith (buffer, "la_objclose: "))
+	{
+	  char *lname;
+	  uintptr_t laddr;
+	  Lmid_t lmid;
+	  uintptr_t cookie;
+	  int r = sscanf (buffer + strlen ("la_objclose: "),
+			  "%"SCNxPTR" %ms %"SCNxPTR" %ld", &cookie, &lname,
+			  &laddr, &lmid);
+	  TEST_COMPARE (r, 4);
+
+	  for (size_t i = 0; i < nobjs; i++)
+	    {
+	      if (strcmp (lname, objs[i].lname) == 0 && lmid == objs[i].lmid)
+		{
+		  TEST_COMPARE (objs[i].closed, false);
+		  objs[i].closed = true;
+		  break;
+		}
+	    }
+
+	  /* la_objclose should be called after la_activity(LA_ACT_DELETE) for
+	     the closed object's namespace.  */
+	  TEST_COMPARE (last_act, LA_ACT_DELETE);
+	  if (!first_objclose)
+	    {
+	      TEST_COMPARE (last_act_cookie, cookie);
+	      first_objclose = true;
+	    }
+	}
+    }
+
+  for (size_t i = 0; i < nobjs; i++)
+    {
+      TEST_COMPARE (objs[i].closed, true);
+      free (objs[i].lname);
+    }
+
+  /* la_activity(LA_ACT_CONSISTENT) should be the last callback received for
+     every namespace.  */
+  TEST_COMPARE (last_act, LA_ACT_CONSISTENT);
+
+  free (buffer);
+  xfclose (out);
+
+  return 0;
+}
+
+#define TEST_FUNCTION_ARGV do_test
+#include <support/test-driver.c>
diff --git a/elf/tst-audit23mod.c b/elf/tst-audit23mod.c
new file mode 100644
index 0000000000..4ca66cf772
--- /dev/null
+++ b/elf/tst-audit23mod.c
@@ -0,0 +1,23 @@
+/* Extra modules for tst-audit23
+   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/>.  */
+
+int
+foo (void)
+{
+  return 0;
+}
diff --git a/elf/tst-auditmod23.c b/elf/tst-auditmod23.c
new file mode 100644
index 0000000000..7a6d24ee80
--- /dev/null
+++ b/elf/tst-auditmod23.c
@@ -0,0 +1,74 @@
+/* Audit modules loaded by tst-audit23.
+   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 <link.h>
+#include <inttypes.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/auxv.h>
+
+unsigned int
+la_version (unsigned int version)
+{
+  return LAV_CURRENT;
+}
+
+struct map_desc_t
+{
+  char *lname;
+  uintptr_t laddr;
+  Lmid_t lmid;
+};
+
+void
+la_activity (uintptr_t *cookie, unsigned int flag)
+{
+  fprintf (stderr, "%s: %d %"PRIxPTR"\n", __func__, flag, (uintptr_t) cookie);
+}
+
+unsigned int
+la_objopen (struct link_map *map, Lmid_t lmid, uintptr_t *cookie)
+{
+  const char *l_name = map->l_name[0] == '\0' ? "mainapp" : map->l_name;
+  fprintf (stderr, "%s: %"PRIxPTR" %s %"PRIxPTR" %ld\n", __func__,
+	   (uintptr_t) cookie, l_name, map->l_addr, lmid);
+
+  struct map_desc_t *map_desc = malloc (sizeof (struct map_desc_t));
+  if (map_desc == NULL)
+    abort ();
+
+  map_desc->lname = strdup (l_name);
+  map_desc->laddr = map->l_addr;
+  map_desc->lmid = lmid;
+
+  *cookie = (uintptr_t) map_desc;
+
+  return 0;
+}
+
+unsigned int
+la_objclose (uintptr_t *cookie)
+{
+  struct map_desc_t *map_desc = (struct map_desc_t *) *cookie;
+  fprintf (stderr, "%s: %"PRIxPTR" %s %"PRIxPTR" %ld\n", __func__,
+	   (uintptr_t) cookie, map_desc->lname, map_desc->laddr,
+	   map_desc->lmid);
+
+  return 0;
+}


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

* Re: [PATCH v8 1/4] elf: Add la_activity during application exit
  2021-12-29 19:54     ` Adhemerval Zanella
@ 2021-12-30 21:35       ` Jonathon Anderson
  2021-12-31 12:24         ` Adhemerval Zanella
  0 siblings, 1 reply; 10+ messages in thread
From: Jonathon Anderson @ 2021-12-30 21:35 UTC (permalink / raw)
  To: Adhemerval Zanella, libc-alpha
  Cc: John Mellor-Crummey, Ben Woodard, Florian Weimer



On 12/29/21 13:54, Adhemerval Zanella wrote:
> On 28/12/2021 14:59, Jonathon Anderson wrote:
>> On 12/28/21 05:50, Adhemerval Zanella wrote:
>>> +  /* The expected namespaces are one for the audit module and another for
>>> +     the application.  */
>> This should be 2 namespaces for the application, the audit module does not get la_* callbacks for itself. AFAICT the second namespace is used by the dlmopen call in the test body (handle_restart).
> You are right, I forgot about the dlmopen usage.  I have adjusted the comment
> to:
>
>    /* The expected namespaces are one for the audit module, one for the
>       application, and another for the dlmopen on handle_restart.  */
Thanks!
>>> +      /* The cookie identifies the object at the head of the link map,
>>> +         so we only add a new namespace if it changes from previous
>>> +         one.  */
>>> +      if (last_act == LA_ACT_ADD && acts[nacts - 1] != cookie)
>>> +        acts[nacts++] = cookie;
>> This works since the dlmopen is second/last in the test body. If there was another dlopen this would consider it a third namespace. Should this be noted in the comment?
> I thin it is worth to comment it, I have changed the comment to:
>
>   /* The cookie identifies the object at the head of the link map,
>      so we only add a new namespace if it changes from previous
>      one.  This work since dlmopen is the last in the test body.  */
Thanks!
>>> +      /* The LA_ACT_DELETE is called in the reverse order of
>>> +         LA_ACT_ADD.  */
>>> +      else if (last_act == LA_ACT_DELETE && cookie != last_act_cookie)
>>> +        {
>>> +          last_act_cookie = acts[--nacts];
>>> +          TEST_COMPARE (acts[nacts], cookie);
>>> +          acts[nacts] = 0;
>>> +        }
>> Not sure about this one yet. Is this always the case or only because there are exactly 2 audited namespaces?
>>
>> Also, this works since la_activity(LA_ACT_DELETE) is only called at program termination. If dlclose was called in the test body (or a dlopen of a library missing dependencies) this might fail. Should this be noted in the comment?
> Yeah, this works because there is no dlclose before program termination
> and tst-audit23mod.so does not have any dependency not already mapped.
> I have changed the comment to:
>
>   /* The LA_ACT_DELETE is called in the reverse order of LA_ACT_ADD
>      at program termination (if the tests adds a dlclose or a library
>      with extra dependencies this require to be adapted).  */
Thanks!
>>> +      /* la_objclose should be called after la_activity(LA_ACT_DELETE) for
>>> +         the closed object's namespace.  */
>>> +      TEST_COMPARE (last_act, LA_ACT_DELETE);
>>> +      if (last_act_cookie != 0)
>>> +        {
>>> +          TEST_COMPARE (last_act_cookie, cookie);
>>> +          last_act_cookie = 0;
>>> +        }
>> This works because the la_objclose order for program termination is the same as the order in the link map (implementation detail), and because la_objclose is only called during program termination in this test. If dlclose was called in the test body this would fail. Should this be noted in the comment?
> I think it makes way more sense to tie to the DT_FINI/DT_FINI_ARRAY execution
> order, but I agree it is an implementation detail (we could just iterate over
> the namespace lists and call it for each objects as well).
Is that the same order in the end? IIUC there was a patch posted to 
reorder DT_FINI to be the opposite of DT_INIT order: 
https://sourceware.org/pipermail/libc-alpha/2021-December/134167.html

I agree DT_FINI order makes much more sense.
> I think the above comments it should be clear that if someone want to test
> dlclose or shared objects with more dependencies, the tests will need to be
> adapted.
Agreed.
>>> +  /* la_activity(LA_ACT_CONSISTENT) should be the last callback received for
>>> +     every namespace.  */
>>> +  TEST_COMPARE (last_act, LA_ACT_CONSISTENT);
>> This only checks the last la_activity notification (AFAICT the main namespace), rather than the last for each namespace.
>>> +  /* Sanity check to check if all LA_ACT_DELETE are matched with
>>> +     la_objclose.  */
>>> +  TEST_COMPARE (last_act_cookie, 0);
>> Similarly, this only checks the last LA_ACT_DELETE notification, rather than last for each namespace.
> Indeed I agree we can increase the coverage of both tests, I have added
> a better la_activity and LA_ACT_DELETE one.
Thanks, but (unless I'm missing something) I'm not seeing the increased 
coverage. There is a new check that LA_ACT_CONSISTENT is always preceded 
by a matching LA_ACT_* (thanks!), but the check that LA_ACT_DELETE is 
matched with la_objclose is gone and there isn't a check that 
LA_ACT_CONSISTENT is received for every namespace.

I think adjusting the la_activity logic as below would catch these last 
couple of cases (although the first check is also AFAIK an undocumented 
implementation detail):

     uintptr_t cookie;
     int this_act;
     int r = sscanf (buffer + strlen ("la_activity: "),
                     "%d %"SCNxPTR"", &this_act, &cookie);
     TEST_COMPARE (r, 2);

     /* The cookie identifies the object at the head of the link map.
        Only one link map may be not-CONSISTENT at a time.  */
     if (cookie != last_act_cookie && last_act_cookie != -1)
        TEST_COMPARE (last_act, LA_ACT_CONSISTENT);

     if (this_act == LA_ACT_ADD && ...
     ...
     /* LA_ACT_CONSISTENT must be preceded by a matching LA_ACT_ADD
        or LA_ACT_DELETE for the same link map.  */
     else if (this_act == LA_ACT_CONSISTENT)
       {
         TEST_COMPARE (cookie, last_act_cookie);

         /* LA_ACT_DELETE must always be followed by an la_objclose. */
         if (last_act == LA_ACT_DELETE)
           TEST_COMPARE (first_objclose, true);
         else
           TEST_COMPARE (last_act, LA_ACT_ADD);
       }

     last_act = this_act;
     first_objclose = false;
>
> Below it is the updated version:
Thank you! Below are my more minor nits:
>
> --
>
> +
> +  /* The expected namespaces are one for the audit module, one for the
> +     application, and another for the dlmopen on handle_restart.  */
> +  enum { max_ns = 3 };
> +  uintptr_t acts[max_ns];
> +  size_t nacts = 0;
> +  int last_act = -1;
> +  uintptr_t last_act_cookie = -1;
> +  bool first_objclose = false;
Naming nit: should this variable be `seen_first_objclose` or 
`seen_objclose`? It seems to be inverted from "first."
> +
> +  FILE *out = fmemopen (result.err.buffer, result.err.length, "r");
> +  TEST_VERIFY (out != NULL);
> +  char *buffer = NULL;
> +  size_t buffer_length = 0;
> +  while (xgetline (&buffer, &buffer_length, out))
> +    {
> +      printf ("%s", buffer);
> +      if (startswith (buffer, "la_activity: "))
> +	{
> +	  uintptr_t cookie;
> +	  int r = sscanf (buffer + strlen ("la_activity: "),
> +			  "%d %"SCNxPTR"", &last_act, &cookie);
> +	  TEST_COMPARE (r, 2);
> +	  /* The cookie identifies the object at the head of the link map,
> +	     so we only add a new namespace if it changes from previous
> +	     one.  This work since dlmopen is the last in the test body.  */
> +	  if (last_act == LA_ACT_ADD && acts[nacts - 1] != cookie)
> +	    {
> +	      acts[nacts++] = cookie;
> +	      last_act_cookie = cookie;
> +	    }
> +	  /* The LA_ACT_DELETE is called in the reverse order of LA_ACT_ADD
> +	     at program termination (if the tests adds a dlclose or a library
> +	     with extra dependencies this require to be adapted).  */
> +	  else if (last_act == LA_ACT_DELETE) // && cookie != last_act_cookie)
Code in a comment here? Since there are no libraries with missing 
dependencies the commented clause is not needed.
> +	    {
> +	      last_act_cookie = acts[--nacts];
> +	      TEST_COMPARE (acts[nacts], cookie);
> +	      acts[nacts] = 0;
> +	    }
> +	  else if (last_act == LA_ACT_CONSISTENT)
> +	    TEST_COMPARE (cookie, last_act_cookie);
> +
> +	  first_objclose = false;
> +	}
> +      else if (startswith (buffer, "la_objopen: "))
> +	{
> +	  char *lname;
> +	  uintptr_t laddr;
> +	  Lmid_t lmid;
> +	  uintptr_t cookie;
> +	  int r = sscanf (buffer + strlen ("la_objopen: "),
> +			  "%"SCNxPTR"  %ms %"SCNxPTR" %ld", &cookie, &lname,
> +			  &laddr, &lmid);
> +	  TEST_COMPARE (r, 4);
> +
> +	  /* la_objclose is not triggered by vDSO because glibc does not
> +	     unload it.  */
> +	  if (is_vdso (lname))
> +	    continue;
> +	  if (nobjs == max_objs)
> +	    FAIL_EXIT1 ("non expected la_objopen: %s %"PRIxPTR" %ld",
> +			lname, laddr, lmid);
> +	  objs[nobjs].lname = lname;
> +	  objs[nobjs].laddr = laddr;
> +	  objs[nobjs].lmid = lmid;
> +	  objs[nobjs].closed = false;
> +	  nobjs++;
> +
> +	  first_objclose = false;
IIUC this indirectly checks that la_objopen always comes before 
la_objclose between la_activity calls. Does it need a comment and/or a 
more explicit check?
> +	}
> +      else if (startswith (buffer, "la_objclose: "))
> +	{
> +	  char *lname;
> +	  uintptr_t laddr;
> +	  Lmid_t lmid;
> +	  uintptr_t cookie;
> +	  int r = sscanf (buffer + strlen ("la_objclose: "),
> +			  "%"SCNxPTR" %ms %"SCNxPTR" %ld", &cookie, &lname,
> +			  &laddr, &lmid);
> +	  TEST_COMPARE (r, 4);
> +
> +	  for (size_t i = 0; i < nobjs; i++)
> +	    {
> +	      if (strcmp (lname, objs[i].lname) == 0 && lmid == objs[i].lmid)
> +		{
> +		  TEST_COMPARE (objs[i].closed, false);
> +		  objs[i].closed = true;
> +		  break;
> +		}
> +	    }
> +
> +	  /* la_objclose should be called after la_activity(LA_ACT_DELETE) for
> +	     the closed object's namespace.  */
> +	  TEST_COMPARE (last_act, LA_ACT_DELETE);
> +	  if (!first_objclose)
> +	    {
> +	      TEST_COMPARE (last_act_cookie, cookie);
> +	      first_objclose = true;
> +	    }
> +	}
> +    }
> +
> +  for (size_t i = 0; i < nobjs; i++)
> +    {
> +      TEST_COMPARE (objs[i].closed, true);
> +      free (objs[i].lname);
> +    }
> +
> +  /* la_activity(LA_ACT_CONSISTENT) should be the last callback received for
> +     every namespace.  */
> +  TEST_COMPARE (last_act, LA_ACT_CONSISTENT);
The comment here still seems misleading given the check. If you use 
something like the logic suggested above, maybe this should read 
something like:

     /* la_activity(LA_ACT_CONSISTENT) should be the last callback received.
        Since only one link map may be not-CONSISTENT at a time, this also
        ensures la_activity(LA_ACT_CONSISTENT) is the last callback received
        for every namespace.  */
> +
> +  free (buffer);
> +  xfclose (out);
> +
> +  return 0;
> +}
> +
> +#define TEST_FUNCTION_ARGV do_test
> +#include <support/test-driver.c>

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

* Re: [PATCH v8 1/4] elf: Add la_activity during application exit
  2021-12-30 21:35       ` Jonathon Anderson
@ 2021-12-31 12:24         ` Adhemerval Zanella
  0 siblings, 0 replies; 10+ messages in thread
From: Adhemerval Zanella @ 2021-12-31 12:24 UTC (permalink / raw)
  To: Jonathon Anderson, libc-alpha
  Cc: John Mellor-Crummey, Ben Woodard, Florian Weimer



On 30/12/2021 18:35, Jonathon Anderson wrote:
> 
> 
> On 12/29/21 13:54, Adhemerval Zanella wrote:
>> On 28/12/2021 14:59, Jonathon Anderson wrote:
>>> On 12/28/21 05:50, Adhemerval Zanella wrote:
>>>> +  /* The expected namespaces are one for the audit module and another for
>>>> +     the application.  */
>>> This should be 2 namespaces for the application, the audit module does not get la_* callbacks for itself. AFAICT the second namespace is used by the dlmopen call in the test body (handle_restart).
>> You are right, I forgot about the dlmopen usage.  I have adjusted the comment
>> to:
>>
>>    /* The expected namespaces are one for the audit module, one for the
>>       application, and another for the dlmopen on handle_restart.  */
> Thanks!
>>>> +      /* The cookie identifies the object at the head of the link map,
>>>> +         so we only add a new namespace if it changes from previous
>>>> +         one.  */
>>>> +      if (last_act == LA_ACT_ADD && acts[nacts - 1] != cookie)
>>>> +        acts[nacts++] = cookie;
>>> This works since the dlmopen is second/last in the test body. If there was another dlopen this would consider it a third namespace. Should this be noted in the comment?
>> I thin it is worth to comment it, I have changed the comment to:
>>
>>   /* The cookie identifies the object at the head of the link map,
>>      so we only add a new namespace if it changes from previous
>>      one.  This work since dlmopen is the last in the test body.  */
> Thanks!
>>>> +      /* The LA_ACT_DELETE is called in the reverse order of
>>>> +         LA_ACT_ADD.  */
>>>> +      else if (last_act == LA_ACT_DELETE && cookie != last_act_cookie)
>>>> +        {
>>>> +          last_act_cookie = acts[--nacts];
>>>> +          TEST_COMPARE (acts[nacts], cookie);
>>>> +          acts[nacts] = 0;
>>>> +        }
>>> Not sure about this one yet. Is this always the case or only because there are exactly 2 audited namespaces?
>>>
>>> Also, this works since la_activity(LA_ACT_DELETE) is only called at program termination. If dlclose was called in the test body (or a dlopen of a library missing dependencies) this might fail. Should this be noted in the comment?
>> Yeah, this works because there is no dlclose before program termination
>> and tst-audit23mod.so does not have any dependency not already mapped.
>> I have changed the comment to:
>>
>>   /* The LA_ACT_DELETE is called in the reverse order of LA_ACT_ADD
>>      at program termination (if the tests adds a dlclose or a library
>>      with extra dependencies this require to be adapted).  */
> Thanks!
>>>> +      /* la_objclose should be called after la_activity(LA_ACT_DELETE) for
>>>> +         the closed object's namespace.  */
>>>> +      TEST_COMPARE (last_act, LA_ACT_DELETE);
>>>> +      if (last_act_cookie != 0)
>>>> +        {
>>>> +          TEST_COMPARE (last_act_cookie, cookie);
>>>> +          last_act_cookie = 0;
>>>> +        }
>>> This works because the la_objclose order for program termination is the same as the order in the link map (implementation detail), and because la_objclose is only called during program termination in this test. If dlclose was called in the test body this would fail. Should this be noted in the comment?
>> I think it makes way more sense to tie to the DT_FINI/DT_FINI_ARRAY execution
>> order, but I agree it is an implementation detail (we could just iterate over
>> the namespace lists and call it for each objects as well).
> Is that the same order in the end? IIUC there was a patch posted to reorder DT_FINI to be the opposite of DT_INIT order: https://sourceware.org/pipermail/libc-alpha/2021-December/134167.html

Florian's patch fixes it for dlclose, my understanding is it should not
really interfere with this test in specific.  I would probably review
this set next week and check if I would need to adapt the audit tests.

> 
> I agree DT_FINI order makes much more sense.
>> I think the above comments it should be clear that if someone want to test
>> dlclose or shared objects with more dependencies, the tests will need to be
>> adapted.
> Agreed.
>>>> +  /* la_activity(LA_ACT_CONSISTENT) should be the last callback received for
>>>> +     every namespace.  */
>>>> +  TEST_COMPARE (last_act, LA_ACT_CONSISTENT);
>>> This only checks the last la_activity notification (AFAICT the main namespace), rather than the last for each namespace.
>>>> +  /* Sanity check to check if all LA_ACT_DELETE are matched with
>>>> +     la_objclose.  */
>>>> +  TEST_COMPARE (last_act_cookie, 0);
>>> Similarly, this only checks the last LA_ACT_DELETE notification, rather than last for each namespace.
>> Indeed I agree we can increase the coverage of both tests, I have added
>> a better la_activity and LA_ACT_DELETE one.
> Thanks, but (unless I'm missing something) I'm not seeing the increased coverage. There is a new check that LA_ACT_CONSISTENT is always preceded by a matching LA_ACT_* (thanks!), but the check that LA_ACT_DELETE is matched with la_objclose is gone and there isn't a check that LA_ACT_CONSISTENT is received for every namespace.

Indeed, it only now checks if the last cookie from la_activity matches the
the first la_objclose.  I will add a check for the la_activity flag as well.

> 
> I think adjusting the la_activity logic as below would catch these last couple of cases (although the first check is also AFAIK an undocumented implementation detail):
> 
>     uintptr_t cookie;
>     int this_act;
>     int r = sscanf (buffer + strlen ("la_activity: "),
>                     "%d %"SCNxPTR"", &this_act, &cookie);
>     TEST_COMPARE (r, 2);
> 
>     /* The cookie identifies the object at the head of the link map.
>        Only one link map may be not-CONSISTENT at a time.  */
>     if (cookie != last_act_cookie && last_act_cookie != -1)
>        TEST_COMPARE (last_act, LA_ACT_CONSISTENT);
> 
>     if (this_act == LA_ACT_ADD && ...
>     ...
>     /* LA_ACT_CONSISTENT must be preceded by a matching LA_ACT_ADD
>        or LA_ACT_DELETE for the same link map.  */
>     else if (this_act == LA_ACT_CONSISTENT)
>       {
>         TEST_COMPARE (cookie, last_act_cookie);
> 
>         /* LA_ACT_DELETE must always be followed by an la_objclose. */
>         if (last_act == LA_ACT_DELETE)
>           TEST_COMPARE (first_objclose, true);
>         else
>           TEST_COMPARE (last_act, LA_ACT_ADD);
>       }
> 
>     last_act = this_act;
>     first_objclose = false;
>>

Thanks, I added these checks on the patch.

>> Below it is the updated version:
> Thank you! Below are my more minor nits:
>>
>> -- 
>>
>> +
>> +  /* The expected namespaces are one for the audit module, one for the
>> +     application, and another for the dlmopen on handle_restart.  */
>> +  enum { max_ns = 3 };
>> +  uintptr_t acts[max_ns];
>> +  size_t nacts = 0;
>> +  int last_act = -1;
>> +  uintptr_t last_act_cookie = -1;
>> +  bool first_objclose = false;
> Naming nit: should this variable be `seen_first_objclose` or `seen_objclose`? It seems to be inverted from "first."

Yeah, it does make more sense. I changed to seen_first_objclose.

>> +
>> +  FILE *out = fmemopen (result.err.buffer, result.err.length, "r");
>> +  TEST_VERIFY (out != NULL);
>> +  char *buffer = NULL;
>> +  size_t buffer_length = 0;
>> +  while (xgetline (&buffer, &buffer_length, out))
>> +    {
>> +      printf ("%s", buffer);
>> +      if (startswith (buffer, "la_activity: "))
>> +    {
>> +      uintptr_t cookie;
>> +      int r = sscanf (buffer + strlen ("la_activity: "),
>> +              "%d %"SCNxPTR"", &last_act, &cookie);
>> +      TEST_COMPARE (r, 2);
>> +      /* The cookie identifies the object at the head of the link map,
>> +         so we only add a new namespace if it changes from previous
>> +         one.  This work since dlmopen is the last in the test body.  */
>> +      if (last_act == LA_ACT_ADD && acts[nacts - 1] != cookie)
>> +        {
>> +          acts[nacts++] = cookie;
>> +          last_act_cookie = cookie;
>> +        }
>> +      /* The LA_ACT_DELETE is called in the reverse order of LA_ACT_ADD
>> +         at program termination (if the tests adds a dlclose or a library
>> +         with extra dependencies this require to be adapted).  */
>> +      else if (last_act == LA_ACT_DELETE) // && cookie != last_act_cookie)
> Code in a comment here? Since there are no libraries with missing dependencies the commented clause is not needed.

I forgot to remove this comment in fact.

>> +        {
>> +          last_act_cookie = acts[--nacts];
>> +          TEST_COMPARE (acts[nacts], cookie);
>> +          acts[nacts] = 0;
>> +        }
>> +      else if (last_act == LA_ACT_CONSISTENT)
>> +        TEST_COMPARE (cookie, last_act_cookie);
>> +
>> +      first_objclose = false;
>> +    }
>> +      else if (startswith (buffer, "la_objopen: "))
>> +    {
>> +      char *lname;
>> +      uintptr_t laddr;
>> +      Lmid_t lmid;
>> +      uintptr_t cookie;
>> +      int r = sscanf (buffer + strlen ("la_objopen: "),
>> +              "%"SCNxPTR"  %ms %"SCNxPTR" %ld", &cookie, &lname,
>> +              &laddr, &lmid);
>> +      TEST_COMPARE (r, 4);
>> +
>> +      /* la_objclose is not triggered by vDSO because glibc does not
>> +         unload it.  */
>> +      if (is_vdso (lname))
>> +        continue;
>> +      if (nobjs == max_objs)
>> +        FAIL_EXIT1 ("non expected la_objopen: %s %"PRIxPTR" %ld",
>> +            lname, laddr, lmid);
>> +      objs[nobjs].lname = lname;
>> +      objs[nobjs].laddr = laddr;
>> +      objs[nobjs].lmid = lmid;
>> +      objs[nobjs].closed = false;
>> +      nobjs++;
>> +
>> +      first_objclose = false;
> IIUC this indirectly checks that la_objopen always comes before la_objclose between la_activity calls. Does it need a comment and/or a more explicit check?

I added a note, thanks.

>> +    }
>> +      else if (startswith (buffer, "la_objclose: "))
>> +    {
>> +      char *lname;
>> +      uintptr_t laddr;
>> +      Lmid_t lmid;
>> +      uintptr_t cookie;
>> +      int r = sscanf (buffer + strlen ("la_objclose: "),
>> +              "%"SCNxPTR" %ms %"SCNxPTR" %ld", &cookie, &lname,
>> +              &laddr, &lmid);
>> +      TEST_COMPARE (r, 4);
>> +
>> +      for (size_t i = 0; i < nobjs; i++)
>> +        {
>> +          if (strcmp (lname, objs[i].lname) == 0 && lmid == objs[i].lmid)
>> +        {
>> +          TEST_COMPARE (objs[i].closed, false);
>> +          objs[i].closed = true;
>> +          break;
>> +        }
>> +        }
>> +
>> +      /* la_objclose should be called after la_activity(LA_ACT_DELETE) for
>> +         the closed object's namespace.  */
>> +      TEST_COMPARE (last_act, LA_ACT_DELETE);
>> +      if (!first_objclose)
>> +        {
>> +          TEST_COMPARE (last_act_cookie, cookie);
>> +          first_objclose = true;
>> +        }
>> +    }
>> +    }
>> +
>> +  for (size_t i = 0; i < nobjs; i++)
>> +    {
>> +      TEST_COMPARE (objs[i].closed, true);
>> +      free (objs[i].lname);
>> +    }
>> +
>> +  /* la_activity(LA_ACT_CONSISTENT) should be the last callback received for
>> +     every namespace.  */
>> +  TEST_COMPARE (last_act, LA_ACT_CONSISTENT);
> The comment here still seems misleading given the check. If you use something like the logic suggested above, maybe this should read something like:
> 
>     /* la_activity(LA_ACT_CONSISTENT) should be the last callback received.
>        Since only one link map may be not-CONSISTENT at a time, this also
>        ensures la_activity(LA_ACT_CONSISTENT) is the last callback received
>        for every namespace.  */

It is indeed better, thanks.

>> +
>> +  free (buffer);
>> +  xfclose (out);
>> +
>> +  return 0;
>> +}
>> +
>> +#define TEST_FUNCTION_ARGV do_test
>> +#include <support/test-driver.c>

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

* Re: [PATCH v8 2/4] elf: Fix initial-exec TLS access on audit modules (BZ #28096)
  2021-12-28 11:50 ` [PATCH v8 2/4] elf: Fix initial-exec TLS access on audit modules (BZ #28096) Adhemerval Zanella
@ 2021-12-31 12:25   ` Adhemerval Zanella
  0 siblings, 0 replies; 10+ messages in thread
From: Adhemerval Zanella @ 2021-12-31 12:25 UTC (permalink / raw)
  To: libc-alpha, jma14; +Cc: John Mellor-Crummey, Ben Woodard



On 28/12/2021 08:50, Adhemerval Zanella wrote:
> diff --git a/elf/dl-tls.c b/elf/dl-tls.c
> index 273f60f233..c57fc13be6 100644
> --- a/elf/dl-tls.c
> +++ b/elf/dl-tls.c
> @@ -593,10 +593,18 @@ _dl_allocate_tls_init (void *result)
>  	     some platforms use in static programs requires it.  */
>  	  dtv[map->l_tls_modid].pointer.val = dest;
>  
> -	  /* Copy the initialization image and clear the BSS part.  */
> -	  memset (__mempcpy (dest, map->l_tls_initimage,
> -			     map->l_tls_initimage_size), '\0',
> -		  map->l_tls_blocksize - map->l_tls_initimage_size);
> +	  /* Copy the initialization image and clear the BSS part.  For
> +	     audit modules or depedencies with initial-exec TLS, we can not
> +	     set the initial TLS image on default loader initialization
> +	     because it would already be set by the audit setup.  However,
> +	     subsequent thread creation would need to follow the default
> +	     behaviour.   */
> +	  if (__glibc_likely (map->l_ns == LM_ID_BASE))
> +	    memset (__mempcpy (dest, map->l_tls_initimage,
> +			       map->l_tls_initimage_size), '\0',
> +		    map->l_tls_blocksize - map->l_tls_initimage_size);
> +	  //else
> +	  //  map->l_dont_set_tls_static = 0;
>  	}
>  
>        total += cnt;

This is wrong is triggers a regression (nptl/tst-audit-threads).  I will
send an updated version.

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

end of thread, other threads:[~2021-12-31 12:25 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-12-28 11:50 [PATCH v8 0/4] Multiple rtld-audit fixes Adhemerval Zanella
2021-12-28 11:50 ` [PATCH v8 1/4] elf: Add la_activity during application exit Adhemerval Zanella
2021-12-28 17:59   ` Jonathon Anderson
2021-12-29 19:54     ` Adhemerval Zanella
2021-12-30 21:35       ` Jonathon Anderson
2021-12-31 12:24         ` Adhemerval Zanella
2021-12-28 11:50 ` [PATCH v8 2/4] elf: Fix initial-exec TLS access on audit modules (BZ #28096) Adhemerval Zanella
2021-12-31 12:25   ` Adhemerval Zanella
2021-12-28 11:50 ` [PATCH v8 3/4] elf: Issue la_symbind for bind-now (BZ #23734) Adhemerval Zanella
2021-12-28 11:50 ` [PATCH v8 4/4] elf: Fix runtime linker auditing on aarch64 (BZ #26643) Adhemerval Zanella

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).