e354a5
commit 3b856d093f5197637a5927c37d6c07dad8c86d45
e354a5
Author: Florian Weimer <fweimer@redhat.com>
e354a5
Date:   Tue Feb 12 13:36:56 2019 +0100
e354a5
e354a5
    elf: Ignore LD_AUDIT interfaces if la_version returns 0 [BZ #24122]
e354a5
    
e354a5
    This change moves the audit module loading and early notification into
e354a5
    separate functions out of dl_main.
e354a5
    
e354a5
    It restores the bug fix from commit
e354a5
    8e889c5da3c5981c5a46a93fec02de40131ac5a6  ("elf: Fix LD_AUDIT for
e354a5
    modules with invalid version (BZ#24122)") which was reverted in commit
e354a5
    83e6b59625f45db1eee93e5684091f740c52a083  ("[elf] Revert 8e889c5da3
e354a5
    (BZ#24122)").
e354a5
    
e354a5
    The actual bug fix is the separate error message for the case when
e354a5
    la_version returns zero.  The dynamic linker error message (which is
e354a5
    NULL in this case) is no longer used.  Based on the intended use of
e354a5
    version zero (ignore this module due to explicit request), the message
e354a5
    is only printed if debugging is enabled.
e354a5
e354a5
diff --git a/elf/rtld.c b/elf/rtld.c
e354a5
index 8bb5f548a0ff8eb4..375e0de8fa2e049e 100644
e354a5
--- a/elf/rtld.c
e354a5
+++ b/elf/rtld.c
e354a5
@@ -864,6 +864,205 @@ handle_preload_list (const char *preloadlist, struct link_map *main_map,
e354a5
   return npreloads;
e354a5
 }
e354a5
 
e354a5
+/* Called if the audit DSO cannot be used: if it does not have the
e354a5
+   appropriate interfaces, or it expects a more recent version library
e354a5
+   version than what the dynamic linker provides.  */
e354a5
+static void
e354a5
+unload_audit_module (struct link_map *map, int original_tls_idx)
e354a5
+{
e354a5
+#ifndef NDEBUG
e354a5
+  Lmid_t ns = map->l_ns;
e354a5
+#endif
e354a5
+  _dl_close (map);
e354a5
+
e354a5
+  /* Make sure the namespace has been cleared entirely.  */
e354a5
+  assert (GL(dl_ns)[ns]._ns_loaded == NULL);
e354a5
+  assert (GL(dl_ns)[ns]._ns_nloaded == 0);
e354a5
+
e354a5
+  GL(dl_tls_max_dtv_idx) = original_tls_idx;
e354a5
+}
e354a5
+
e354a5
+/* Called to print an error message if loading of an audit module
e354a5
+   failed.  */
e354a5
+static void
e354a5
+report_audit_module_load_error (const char *name, const char *err_str,
e354a5
+				bool malloced)
e354a5
+{
e354a5
+  _dl_error_printf ("\
e354a5
+ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n",
e354a5
+		    name, err_str);
e354a5
+  if (malloced)
e354a5
+    free ((char *) err_str);
e354a5
+}
e354a5
+
e354a5
+/* Load one audit module.  */
e354a5
+static void
e354a5
+load_audit_module (const char *name, struct audit_ifaces **last_audit)
e354a5
+{
e354a5
+  int original_tls_idx = GL(dl_tls_max_dtv_idx);
e354a5
+
e354a5
+  struct dlmopen_args dlmargs;
e354a5
+  dlmargs.fname = name;
e354a5
+  dlmargs.map = NULL;
e354a5
+
e354a5
+  const char *objname;
e354a5
+  const char *err_str = NULL;
e354a5
+  bool malloced;
e354a5
+  _dl_catch_error (&objname, &err_str, &malloced, dlmopen_doit, &dlmargs);
e354a5
+  if (__glibc_unlikely (err_str != NULL))
e354a5
+    {
e354a5
+      report_audit_module_load_error (name, err_str, malloced);
e354a5
+      return;
e354a5
+    }
e354a5
+
e354a5
+  struct lookup_args largs;
e354a5
+  largs.name = "la_version";
e354a5
+  largs.map = dlmargs.map;
e354a5
+  _dl_catch_error (&objname, &err_str, &malloced, lookup_doit, &largs);
e354a5
+  if (__glibc_likely (err_str != NULL))
e354a5
+    {
e354a5
+      unload_audit_module (dlmargs.map, original_tls_idx);
e354a5
+      report_audit_module_load_error (name, err_str, malloced);
e354a5
+      return;
e354a5
+    }
e354a5
+
e354a5
+  unsigned int (*laversion) (unsigned int) = largs.result;
e354a5
+
e354a5
+ /* A null symbol indicates that something is very wrong with the
e354a5
+    loaded object because defined symbols are supposed to have a
e354a5
+    valid, non-null address.  */
e354a5
+  assert (laversion != NULL);
e354a5
+
e354a5
+  unsigned int lav = laversion (LAV_CURRENT);
e354a5
+  if (lav == 0)
e354a5
+    {
e354a5
+      /* Only print an error message if debugging because this can
e354a5
+	 happen deliberately.  */
e354a5
+      if (GLRO(dl_debug_mask) & DL_DEBUG_FILES)
e354a5
+	_dl_debug_printf ("\
e354a5
+file=%s [%lu]; audit interface function la_version returned zero; ignored.\n",
e354a5
+			  dlmargs.map->l_name, dlmargs.map->l_ns);
e354a5
+      unload_audit_module (dlmargs.map, original_tls_idx);
e354a5
+      return;
e354a5
+    }
e354a5
+
e354a5
+  if (lav > LAV_CURRENT)
e354a5
+    {
e354a5
+      _dl_debug_printf ("\
e354a5
+ERROR: audit interface '%s' requires version %d (maximum supported version %d); ignored.\n",
e354a5
+			name, lav, LAV_CURRENT);
e354a5
+      unload_audit_module (dlmargs.map, original_tls_idx);
e354a5
+      return;
e354a5
+    }
e354a5
+
e354a5
+  enum { naudit_ifaces = 8 };
e354a5
+  union
e354a5
+  {
e354a5
+    struct audit_ifaces ifaces;
e354a5
+    void (*fptr[naudit_ifaces]) (void);
e354a5
+  } *newp = malloc (sizeof (*newp));
e354a5
+  if (newp == NULL)
e354a5
+    _dl_fatal_printf ("Out of memory while loading audit modules\n");
e354a5
+
e354a5
+  /* Names of the auditing interfaces.  All in one
e354a5
+     long string.  */
e354a5
+  static const char audit_iface_names[] =
e354a5
+    "la_activity\0"
e354a5
+    "la_objsearch\0"
e354a5
+    "la_objopen\0"
e354a5
+    "la_preinit\0"
e354a5
+#if __ELF_NATIVE_CLASS == 32
e354a5
+    "la_symbind32\0"
e354a5
+#elif __ELF_NATIVE_CLASS == 64
e354a5
+    "la_symbind64\0"
e354a5
+#else
e354a5
+# error "__ELF_NATIVE_CLASS must be defined"
e354a5
+#endif
e354a5
+#define STRING(s) __STRING (s)
e354a5
+    "la_" STRING (ARCH_LA_PLTENTER) "\0"
e354a5
+    "la_" STRING (ARCH_LA_PLTEXIT) "\0"
e354a5
+    "la_objclose\0";
e354a5
+  unsigned int cnt = 0;
e354a5
+  const char *cp = audit_iface_names;
e354a5
+  do
e354a5
+    {
e354a5
+      largs.name = cp;
e354a5
+      _dl_catch_error (&objname, &err_str, &malloced, lookup_doit, &largs);
e354a5
+
e354a5
+      /* Store the pointer.  */
e354a5
+      if (err_str == NULL && largs.result != NULL)
e354a5
+	{
e354a5
+	  newp->fptr[cnt] = largs.result;
e354a5
+
e354a5
+	  /* The dynamic linker link map is statically allocated,
e354a5
+	     initialize the data now.  */
e354a5
+	  GL(dl_rtld_map).l_audit[cnt].cookie = (intptr_t) &GL(dl_rtld_map);
e354a5
+	}
e354a5
+      else
e354a5
+	newp->fptr[cnt] = NULL;
e354a5
+      ++cnt;
e354a5
+
e354a5
+      cp = rawmemchr (cp, '\0') + 1;
e354a5
+    }
e354a5
+  while (*cp != '\0');
e354a5
+  assert (cnt == naudit_ifaces);
e354a5
+
e354a5
+  /* Now append the new auditing interface to the list.  */
e354a5
+  newp->ifaces.next = NULL;
e354a5
+  if (*last_audit == NULL)
e354a5
+    *last_audit = GLRO(dl_audit) = &newp->ifaces;
e354a5
+  else
e354a5
+    *last_audit = (*last_audit)->next = &newp->ifaces;
e354a5
+  ++GLRO(dl_naudit);
e354a5
+
e354a5
+  /* Mark the DSO as being used for auditing.  */
e354a5
+  dlmargs.map->l_auditing = 1;
e354a5
+}
e354a5
+
e354a5
+/* Notify the the audit modules that the object MAP has already been
e354a5
+   loaded.  */
e354a5
+static void
e354a5
+notify_audit_modules_of_loaded_object (struct link_map *map)
e354a5
+{
e354a5
+  struct audit_ifaces *afct = GLRO(dl_audit);
e354a5
+  for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
e354a5
+    {
e354a5
+      if (afct->objopen != NULL)
e354a5
+	{
e354a5
+	  map->l_audit[cnt].bindflags
e354a5
+	    = afct->objopen (map, LM_ID_BASE, &map->l_audit[cnt].cookie);
e354a5
+	  map->l_audit_any_plt |= map->l_audit[cnt].bindflags != 0;
e354a5
+	}
e354a5
+
e354a5
+      afct = afct->next;
e354a5
+    }
e354a5
+}
e354a5
+
e354a5
+/* Load all audit modules.  */
e354a5
+static void
e354a5
+load_audit_modules (struct link_map *main_map)
e354a5
+{
e354a5
+  struct audit_ifaces *last_audit = NULL;
e354a5
+  struct audit_list_iter al_iter;
e354a5
+  audit_list_iter_init (&al_iter);
e354a5
+
e354a5
+  while (true)
e354a5
+    {
e354a5
+      const char *name = audit_list_iter_next (&al_iter);
e354a5
+      if (name == NULL)
e354a5
+	break;
e354a5
+      load_audit_module (name, &last_audit);
e354a5
+    }
e354a5
+
e354a5
+  /* Notify audit modules of the initially loaded modules (the main
e354a5
+     program and the dynamic linker itself).  */
e354a5
+  if (GLRO(dl_naudit) > 0)
e354a5
+    {
e354a5
+      notify_audit_modules_of_loaded_object (main_map);
e354a5
+      notify_audit_modules_of_loaded_object (&GL(dl_rtld_map));
e354a5
+    }
e354a5
+}
e354a5
+
e354a5
 static void
e354a5
 dl_main (const ElfW(Phdr) *phdr,
e354a5
 	 ElfW(Word) phnum,
e354a5
@@ -1402,10 +1601,6 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]);
e354a5
   if (__glibc_unlikely (audit_list != NULL)
e354a5
       || __glibc_unlikely (audit_list_string != NULL))
e354a5
     {
e354a5
-      struct audit_ifaces *last_audit = NULL;
e354a5
-      struct audit_list_iter al_iter;
e354a5
-      audit_list_iter_init (&al_iter);
e354a5
-
e354a5
       /* Since we start using the auditing DSOs right away we need to
e354a5
 	 initialize the data structures now.  */
e354a5
       tcbp = init_tls ();
e354a5
@@ -1417,164 +1612,7 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]);
e354a5
       security_init ();
e354a5
       need_security_init = false;
e354a5
 
e354a5
-      while (true)
e354a5
-	{
e354a5
-	  const char *name = audit_list_iter_next (&al_iter);
e354a5
-	  if (name == NULL)
e354a5
-	    break;
e354a5
-
e354a5
-	  int tls_idx = GL(dl_tls_max_dtv_idx);
e354a5
-
e354a5
-	  /* Now it is time to determine the layout of the static TLS
e354a5
-	     block and allocate it for the initial thread.  Note that we
e354a5
-	     always allocate the static block, we never defer it even if
e354a5
-	     no DF_STATIC_TLS bit is set.  The reason is that we know
e354a5
-	     glibc will use the static model.  */
e354a5
-	  struct dlmopen_args dlmargs;
e354a5
-	  dlmargs.fname = name;
e354a5
-	  dlmargs.map = NULL;
e354a5
-
e354a5
-	  const char *objname;
e354a5
-	  const char *err_str = NULL;
e354a5
-	  bool malloced;
e354a5
-	  (void) _dl_catch_error (&objname, &err_str, &malloced, dlmopen_doit,
e354a5
-				  &dlmargs);
e354a5
-	  if (__glibc_unlikely (err_str != NULL))
e354a5
-	    {
e354a5
-	    not_loaded:
e354a5
-	      _dl_error_printf ("\
e354a5
-ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n",
e354a5
-				name, err_str);
e354a5
-	      if (malloced)
e354a5
-		free ((char *) err_str);
e354a5
-	    }
e354a5
-	  else
e354a5
-	    {
e354a5
-	      struct lookup_args largs;
e354a5
-	      largs.name = "la_version";
e354a5
-	      largs.map = dlmargs.map;
e354a5
-
e354a5
-	      /* Check whether the interface version matches.  */
e354a5
-	      (void) _dl_catch_error (&objname, &err_str, &malloced,
e354a5
-				      lookup_doit, &largs);
e354a5
-
e354a5
-	      unsigned int (*laversion) (unsigned int);
e354a5
-	      unsigned int lav;
e354a5
-	      if  (err_str == NULL
e354a5
-		   && (laversion = largs.result) != NULL
e354a5
-		   && (lav = laversion (LAV_CURRENT)) > 0
e354a5
-		   && lav <= LAV_CURRENT)
e354a5
-		{
e354a5
-		  /* Allocate structure for the callback function pointers.
e354a5
-		     This call can never fail.  */
e354a5
-		  union
e354a5
-		  {
e354a5
-		    struct audit_ifaces ifaces;
e354a5
-#define naudit_ifaces 8
e354a5
-		    void (*fptr[naudit_ifaces]) (void);
e354a5
-		  } *newp = malloc (sizeof (*newp));
e354a5
-
e354a5
-		  /* Names of the auditing interfaces.  All in one
e354a5
-		     long string.  */
e354a5
-		  static const char audit_iface_names[] =
e354a5
-		    "la_activity\0"
e354a5
-		    "la_objsearch\0"
e354a5
-		    "la_objopen\0"
e354a5
-		    "la_preinit\0"
e354a5
-#if __ELF_NATIVE_CLASS == 32
e354a5
-		    "la_symbind32\0"
e354a5
-#elif __ELF_NATIVE_CLASS == 64
e354a5
-		    "la_symbind64\0"
e354a5
-#else
e354a5
-# error "__ELF_NATIVE_CLASS must be defined"
e354a5
-#endif
e354a5
-#define STRING(s) __STRING (s)
e354a5
-		    "la_" STRING (ARCH_LA_PLTENTER) "\0"
e354a5
-		    "la_" STRING (ARCH_LA_PLTEXIT) "\0"
e354a5
-		    "la_objclose\0";
e354a5
-		  unsigned int cnt = 0;
e354a5
-		  const char *cp = audit_iface_names;
e354a5
-		  do
e354a5
-		    {
e354a5
-		      largs.name = cp;
e354a5
-		      (void) _dl_catch_error (&objname, &err_str, &malloced,
e354a5
-					      lookup_doit, &largs);
e354a5
-
e354a5
-		      /* Store the pointer.  */
e354a5
-		      if (err_str == NULL && largs.result != NULL)
e354a5
-			{
e354a5
-			  newp->fptr[cnt] = largs.result;
e354a5
-
e354a5
-			  /* The dynamic linker link map is statically
e354a5
-			     allocated, initialize the data now.   */
e354a5
-			  GL(dl_rtld_map).l_audit[cnt].cookie
e354a5
-			    = (intptr_t) &GL(dl_rtld_map);
e354a5
-			}
e354a5
-		      else
e354a5
-			newp->fptr[cnt] = NULL;
e354a5
-		      ++cnt;
e354a5
-
e354a5
-		      cp = (char *) rawmemchr (cp, '\0') + 1;
e354a5
-		    }
e354a5
-		  while (*cp != '\0');
e354a5
-		  assert (cnt == naudit_ifaces);
e354a5
-
e354a5
-		  /* Now append the new auditing interface to the list.  */
e354a5
-		  newp->ifaces.next = NULL;
e354a5
-		  if (last_audit == NULL)
e354a5
-		    last_audit = GLRO(dl_audit) = &newp->ifaces;
e354a5
-		  else
e354a5
-		    last_audit = last_audit->next = &newp->ifaces;
e354a5
-		  ++GLRO(dl_naudit);
e354a5
-
e354a5
-		  /* Mark the DSO as being used for auditing.  */
e354a5
-		  dlmargs.map->l_auditing = 1;
e354a5
-		}
e354a5
-	      else
e354a5
-		{
e354a5
-		  /* We cannot use the DSO, it does not have the
e354a5
-		     appropriate interfaces or it expects something
e354a5
-		     more recent.  */
e354a5
-#ifndef NDEBUG
e354a5
-		  Lmid_t ns = dlmargs.map->l_ns;
e354a5
-#endif
e354a5
-		  _dl_close (dlmargs.map);
e354a5
-
e354a5
-		  /* Make sure the namespace has been cleared entirely.  */
e354a5
-		  assert (GL(dl_ns)[ns]._ns_loaded == NULL);
e354a5
-		  assert (GL(dl_ns)[ns]._ns_nloaded == 0);
e354a5
-
e354a5
-		  GL(dl_tls_max_dtv_idx) = tls_idx;
e354a5
-		  goto not_loaded;
e354a5
-		}
e354a5
-	    }
e354a5
-	}
e354a5
-
e354a5
-      /* If we have any auditing modules, announce that we already
e354a5
-	 have two objects loaded.  */
e354a5
-      if (__glibc_unlikely (GLRO(dl_naudit) > 0))
e354a5
-	{
e354a5
-	  struct link_map *ls[2] = { main_map, &GL(dl_rtld_map) };
e354a5
-
e354a5
-	  for (unsigned int outer = 0; outer < 2; ++outer)
e354a5
-	    {
e354a5
-	      struct audit_ifaces *afct = GLRO(dl_audit);
e354a5
-	      for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
e354a5
-		{
e354a5
-		  if (afct->objopen != NULL)
e354a5
-		    {
e354a5
-		      ls[outer]->l_audit[cnt].bindflags
e354a5
-			= afct->objopen (ls[outer], LM_ID_BASE,
e354a5
-					 &ls[outer]->l_audit[cnt].cookie);
e354a5
-
e354a5
-		      ls[outer]->l_audit_any_plt
e354a5
-			|= ls[outer]->l_audit[cnt].bindflags != 0;
e354a5
-		    }
e354a5
-
e354a5
-		  afct = afct->next;
e354a5
-		}
e354a5
-	    }
e354a5
-	}
e354a5
+      load_audit_modules (main_map);
e354a5
     }
e354a5
 
e354a5
   /* Keep track of the currently loaded modules to count how many