08c3a6
commit d1b9bee29a1c4e0b80db53f228e22550c3604894
08c3a6
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
08c3a6
Date:   Mon Jul 19 18:42:26 2021 -0300
08c3a6
08c3a6
    elf: Issue audit la_objopen for vDSO
08c3a6
    
08c3a6
    The vDSO is is listed in the link_map chain, but is never the subject of
08c3a6
    an la_objopen call.  A new internal flag __RTLD_VDSO is added that
08c3a6
    acts as __RTLD_OPENEXEC to allocate the required 'struct auditstate'
08c3a6
    extra space for the 'struct link_map'.
08c3a6
    
08c3a6
    The return value from the callback is currently ignored, since there
08c3a6
    is no PLT call involved by glibc when using the vDSO, neither the vDSO
08c3a6
    are exported directly.
08c3a6
    
08c3a6
    Checked on x86_64-linux-gnu, i686-linux-gnu, and aarch64-linux-gnu.
08c3a6
    
08c3a6
    Reviewed-by: Florian Weimer <fweimer@redhat.com>
08c3a6
    (cherry picked from commit f0e23d34a7bdf6b90fba954ee741419171ac41b2)
08c3a6
    
08c3a6
    Resolved conflicts:
08c3a6
            elf/Makefile
08c3a6
08c3a6
diff --git a/elf/Makefile b/elf/Makefile
08c3a6
index 29f545d2272bf6e2..465442bf59fa9794 100644
08c3a6
--- a/elf/Makefile
08c3a6
+++ b/elf/Makefile
08c3a6
@@ -366,6 +366,7 @@ tests += \
08c3a6
   tst-audit17 \
08c3a6
   tst-audit18 \
08c3a6
   tst-audit19b \
08c3a6
+  tst-audit22 \
08c3a6
   tst-auditmany \
08c3a6
   tst-auxobj \
08c3a6
   tst-auxobj-dlopen \
08c3a6
@@ -649,6 +650,7 @@ modules-names = \
08c3a6
   tst-auditmod18 \
08c3a6
   tst-auditmod19a \
08c3a6
   tst-auditmod19b \
08c3a6
+  tst-auditmod22 \
08c3a6
   tst-auxvalmod \
08c3a6
   tst-big-note-lib \
08c3a6
   tst-deep1mod1 \
08c3a6
@@ -2035,6 +2037,9 @@ $(objpfx)tst-audit19b.out: $(objpfx)tst-auditmod19b.so
08c3a6
 $(objpfx)tst-audit19b: $(objpfx)tst-audit19bmod.so
08c3a6
 tst-audit19b-ARGS = -- $(host-test-program-cmd)
08c3a6
 
08c3a6
+$(objpfx)tst-audit22.out: $(objpfx)tst-auditmod22.so
08c3a6
+tst-audit22-ARGS = -- $(host-test-program-cmd)
08c3a6
+
08c3a6
 # tst-sonamemove links against an older implementation of the library.
08c3a6
 LDFLAGS-tst-sonamemove-linkmod1.so = \
08c3a6
   -Wl,--version-script=tst-sonamemove-linkmod1.map \
08c3a6
diff --git a/elf/dl-object.c b/elf/dl-object.c
08c3a6
index 1875599eb274dc35..dee49a32d4fdf07d 100644
08c3a6
--- a/elf/dl-object.c
08c3a6
+++ b/elf/dl-object.c
08c3a6
@@ -59,16 +59,19 @@ _dl_new_object (char *realname, const char *libname, int type,
08c3a6
 {
08c3a6
 #ifdef SHARED
08c3a6
   unsigned int naudit;
08c3a6
-  if (__glibc_unlikely ((mode & __RTLD_OPENEXEC) != 0))
08c3a6
+  if (__glibc_unlikely ((mode & (__RTLD_OPENEXEC | __RTLD_VDSO)) != 0))
08c3a6
     {
08c3a6
-      assert (type == lt_executable);
08c3a6
-      assert (nsid == LM_ID_BASE);
08c3a6
+      if (mode & __RTLD_OPENEXEC)
08c3a6
+	{
08c3a6
+	  assert (type == lt_executable);
08c3a6
+	  assert (nsid == LM_ID_BASE);
08c3a6
 
08c3a6
-      /* Ignore the specified libname for the main executable.  It is
08c3a6
-	 only known with an explicit loader invocation.  */
08c3a6
-      libname = "";
08c3a6
+	  /* Ignore the specified libname for the main executable.  It is
08c3a6
+	     only known with an explicit loader invocation.  */
08c3a6
+	  libname = "";
08c3a6
+	}
08c3a6
 
08c3a6
-      /* We create the map for the executable before we know whether
08c3a6
+      /* We create the map for the executable and vDSO before we know whether
08c3a6
 	 we have auditing libraries and if yes, how many.  Assume the
08c3a6
 	 worst.  */
08c3a6
       naudit = DL_NNS;
08c3a6
diff --git a/elf/rtld.c b/elf/rtld.c
08c3a6
index f632a767d7a269ef..b089e5cf4740443e 100644
08c3a6
--- a/elf/rtld.c
08c3a6
+++ b/elf/rtld.c
08c3a6
@@ -1922,6 +1922,12 @@ dl_main (const ElfW(Phdr) *phdr,
08c3a6
       assert (i == npreloads);
08c3a6
     }
08c3a6
 
08c3a6
+#ifdef NEED_DL_SYSINFO_DSO
08c3a6
+  /* Now that the audit modules are opened, call la_objopen for the vDSO.  */
08c3a6
+  if (GLRO(dl_sysinfo_map) != NULL)
08c3a6
+    _dl_audit_objopen (GLRO(dl_sysinfo_map), LM_ID_BASE);
08c3a6
+#endif
08c3a6
+
08c3a6
   /* Load all the libraries specified by DT_NEEDED entries.  If LD_PRELOAD
08c3a6
      specified some libraries to load, these are inserted before the actual
08c3a6
      dependencies in the executable's searchlist for symbol resolution.  */
08c3a6
diff --git a/elf/setup-vdso.h b/elf/setup-vdso.h
08c3a6
index 3f20578046de76ed..2b013d974a377a83 100644
08c3a6
--- a/elf/setup-vdso.h
08c3a6
+++ b/elf/setup-vdso.h
08c3a6
@@ -30,7 +30,7 @@ setup_vdso (struct link_map *main_map __attribute__ ((unused)),
08c3a6
      We just want our data structures to describe it as if we had just
08c3a6
      mapped and relocated it normally.  */
08c3a6
   struct link_map *l = _dl_new_object ((char *) "", "", lt_library, NULL,
08c3a6
-				       0, LM_ID_BASE);
08c3a6
+				       __RTLD_VDSO, LM_ID_BASE);
08c3a6
   if (__glibc_likely (l != NULL))
08c3a6
     {
08c3a6
       l->l_phdr = ((const void *) GLRO(dl_sysinfo_dso)
08c3a6
diff --git a/elf/tst-audit22.c b/elf/tst-audit22.c
08c3a6
new file mode 100644
08c3a6
index 0000000000000000..18fd22a760ddc3d8
08c3a6
--- /dev/null
08c3a6
+++ b/elf/tst-audit22.c
08c3a6
@@ -0,0 +1,124 @@
08c3a6
+/* Check DTAUDIT and vDSO interaction.
08c3a6
+   Copyright (C) 2021 Free Software Foundation, Inc.
08c3a6
+   This file is part of the GNU C Library.
08c3a6
+
08c3a6
+   The GNU C Library is free software; you can redistribute it and/or
08c3a6
+   modify it under the terms of the GNU Lesser General Public
08c3a6
+   License as published by the Free Software Foundation; either
08c3a6
+   version 2.1 of the License, or (at your option) any later version.
08c3a6
+
08c3a6
+   The GNU C Library is distributed in the hope that it will be useful,
08c3a6
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
08c3a6
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
08c3a6
+   Lesser General Public License for more details.
08c3a6
+
08c3a6
+   You should have received a copy of the GNU Lesser General Public
08c3a6
+   License along with the GNU C Library; if not, see
08c3a6
+   <https://www.gnu.org/licenses/>.  */
08c3a6
+
08c3a6
+#include <errno.h>
08c3a6
+#include <getopt.h>
08c3a6
+#include <limits.h>
08c3a6
+#include <inttypes.h>
08c3a6
+#include <string.h>
08c3a6
+#include <stdlib.h>
08c3a6
+#include <support/capture_subprocess.h>
08c3a6
+#include <support/check.h>
08c3a6
+#include <support/xstdio.h>
08c3a6
+#include <support/support.h>
08c3a6
+#include <sys/auxv.h>
08c3a6
+
08c3a6
+static int restart;
08c3a6
+#define CMDLINE_OPTIONS \
08c3a6
+  { "restart", no_argument, &restart, 1 },
08c3a6
+
08c3a6
+static uintptr_t vdso_addr;
08c3a6
+
08c3a6
+static int
08c3a6
+handle_restart (void)
08c3a6
+{
08c3a6
+  fprintf (stderr, "vdso: %p\n", (void*) vdso_addr);
08c3a6
+  return 0;
08c3a6
+}
08c3a6
+
08c3a6
+static uintptr_t
08c3a6
+parse_address (const char *str)
08c3a6
+{
08c3a6
+  void *r;
08c3a6
+  TEST_COMPARE (sscanf (str, "%p\n", &r), 1);
08c3a6
+  return (uintptr_t) r;
08c3a6
+}
08c3a6
+
08c3a6
+static inline bool
08c3a6
+startswith (const char *str, const char *pre)
08c3a6
+{
08c3a6
+  size_t lenpre = strlen (pre);
08c3a6
+  size_t lenstr = strlen (str);
08c3a6
+  return lenstr >= lenpre && memcmp (pre, str, lenpre) == 0;
08c3a6
+}
08c3a6
+
08c3a6
+static int
08c3a6
+do_test (int argc, char *argv[])
08c3a6
+{
08c3a6
+  vdso_addr = getauxval (AT_SYSINFO_EHDR);
08c3a6
+  if (vdso_addr == 0)
08c3a6
+    FAIL_UNSUPPORTED ("getauxval (AT_SYSINFO_EHDR) returned 0");
08c3a6
+
08c3a6
+  /* We must have either:
08c3a6
+     - One our fource parameters left if called initially:
08c3a6
+       + path to ld.so         optional
08c3a6
+       + "--library-path"      optional
08c3a6
+       + the library path      optional
08c3a6
+       + the application name  */
08c3a6
+  if (restart)
08c3a6
+    return handle_restart ();
08c3a6
+
08c3a6
+  char *spargv[9];
08c3a6
+  int i = 0;
08c3a6
+  for (; i < argc - 1; i++)
08c3a6
+    spargv[i] = argv[i + 1];
08c3a6
+  spargv[i++] = (char *) "--direct";
08c3a6
+  spargv[i++] = (char *) "--restart";
08c3a6
+  spargv[i] = NULL;
08c3a6
+
08c3a6
+  setenv ("LD_AUDIT", "tst-auditmod22.so", 0);
08c3a6
+  struct support_capture_subprocess result
08c3a6
+    = support_capture_subprogram (spargv[0], spargv);
08c3a6
+  support_capture_subprocess_check (&result, "tst-audit22", 0, sc_allow_stderr);
08c3a6
+
08c3a6
+  /* The respawned process should always print the vDSO address (otherwise it
08c3a6
+     will fails as unsupported).  However, on some architectures the audit
08c3a6
+     module might see the vDSO with l_addr being 0, meaning a fixed mapping
08c3a6
+     (linux-gate.so).  In this case we don't check its value against
08c3a6
+     AT_SYSINFO_EHDR one.  */
08c3a6
+  uintptr_t vdso_process = 0;
08c3a6
+  bool vdso_audit_found = false;
08c3a6
+  uintptr_t vdso_audit = 0;
08c3a6
+
08c3a6
+  FILE *out = fmemopen (result.err.buffer, result.err.length, "r");
08c3a6
+  TEST_VERIFY (out != NULL);
08c3a6
+  char *buffer = NULL;
08c3a6
+  size_t buffer_length = 0;
08c3a6
+  while (xgetline (&buffer, &buffer_length, out))
08c3a6
+    {
08c3a6
+      if (startswith (buffer, "vdso: "))
08c3a6
+	vdso_process = parse_address (buffer + strlen ("vdso: "));
08c3a6
+      else if (startswith (buffer, "vdso found: "))
08c3a6
+	{
08c3a6
+	  vdso_audit = parse_address (buffer + strlen ("vdso found: "));
08c3a6
+          vdso_audit_found = true;
08c3a6
+	}
08c3a6
+    }
08c3a6
+
08c3a6
+  TEST_COMPARE (vdso_audit_found, true);
08c3a6
+  if (vdso_audit != 0)
08c3a6
+    TEST_COMPARE (vdso_process, vdso_audit);
08c3a6
+
08c3a6
+  free (buffer);
08c3a6
+  xfclose (out);
08c3a6
+
08c3a6
+  return 0;
08c3a6
+}
08c3a6
+
08c3a6
+#define TEST_FUNCTION_ARGV do_test
08c3a6
+#include <support/test-driver.c>
08c3a6
diff --git a/elf/tst-auditmod22.c b/elf/tst-auditmod22.c
08c3a6
new file mode 100644
08c3a6
index 0000000000000000..8e05ce8cbb215dd5
08c3a6
--- /dev/null
08c3a6
+++ b/elf/tst-auditmod22.c
08c3a6
@@ -0,0 +1,51 @@
08c3a6
+/* Check DTAUDIT and vDSO interaction.
08c3a6
+   Copyright (C) 2021 Free Software Foundation, Inc.
08c3a6
+   This file is part of the GNU C Library.
08c3a6
+
08c3a6
+   The GNU C Library is free software; you can redistribute it and/or
08c3a6
+   modify it under the terms of the GNU Lesser General Public
08c3a6
+   License as published by the Free Software Foundation; either
08c3a6
+   version 2.1 of the License, or (at your option) any later version.
08c3a6
+
08c3a6
+   The GNU C Library is distributed in the hope that it will be useful,
08c3a6
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
08c3a6
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
08c3a6
+   Lesser General Public License for more details.
08c3a6
+
08c3a6
+   You should have received a copy of the GNU Lesser General Public
08c3a6
+   License along with the GNU C Library; if not, see
08c3a6
+   <https://www.gnu.org/licenses/>.  */
08c3a6
+
08c3a6
+#include <link.h>
08c3a6
+#include <inttypes.h>
08c3a6
+#include <stdbool.h>
08c3a6
+#include <string.h>
08c3a6
+#include <stdio.h>
08c3a6
+#include <sys/auxv.h>
08c3a6
+
08c3a6
+static inline bool
08c3a6
+startswith (const char *str, const char *pre)
08c3a6
+{
08c3a6
+  size_t lenpre = strlen (pre);
08c3a6
+  size_t lenstr = strlen (str);
08c3a6
+  return lenstr < lenpre ? false : memcmp (pre, str, lenpre) == 0;
08c3a6
+}
08c3a6
+
08c3a6
+unsigned int
08c3a6
+la_version (unsigned int version)
08c3a6
+{
08c3a6
+  return LAV_CURRENT;
08c3a6
+}
08c3a6
+
08c3a6
+unsigned int
08c3a6
+la_objopen (struct link_map *map, Lmid_t lmid, uintptr_t *cookie)
08c3a6
+{
08c3a6
+  /* The linux-gate.so is placed at a fixed address, thus l_addr being 0,
08c3a6
+     and it might be the value reported as the AT_SYSINFO_EHDR.  */
08c3a6
+  if (map->l_addr == 0 && startswith (map->l_name, "linux-gate.so"))
08c3a6
+    fprintf (stderr, "vdso found: %p\n", NULL);
08c3a6
+  else if (map->l_addr == getauxval (AT_SYSINFO_EHDR))
08c3a6
+    fprintf (stderr, "vdso found: %p\n", (void*) map->l_addr);
08c3a6
+
08c3a6
+  return 0;
08c3a6
+}
08c3a6
diff --git a/include/dlfcn.h b/include/dlfcn.h
08c3a6
index a4c283728f94deb4..e73294b0af587913 100644
08c3a6
--- a/include/dlfcn.h
08c3a6
+++ b/include/dlfcn.h
08c3a6
@@ -12,6 +12,8 @@
08c3a6
 #define __RTLD_AUDIT	0x08000000
08c3a6
 #define __RTLD_SECURE	0x04000000 /* Apply additional security checks.  */
08c3a6
 #define __RTLD_NOIFUNC	0x02000000 /* Suppress calling ifunc functions.  */
08c3a6
+#define __RTLD_VDSO	0x01000000 /* Tell _dl_new_object the object is
08c3a6
+				      system-loaded.  */
08c3a6
 
08c3a6
 #define __LM_ID_CALLER	-2
08c3a6