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