12b68e
commit TBD
12b68e
Author: Florian Weimer <fweimer@redhat.com>
12b68e
Date:   Fri May 19 17:46:47 2017 +0200
12b68e
12b68e
    rtld: Reject overly long LD_AUDIT path elements
12b68e
12b68e
Also only process the last LD_AUDIT entry.
12b68e
12b68e
Index: b/elf/rtld.c
12b68e
===================================================================
12b68e
--- a/elf/rtld.c
12b68e
+++ b/elf/rtld.c
12b68e
@@ -116,13 +116,91 @@ dso_name_valid_for_suid (const char *p)
12b68e
   return *p != '\0';
12b68e
 }
12b68e
 
12b68e
-/* List of auditing DSOs.  */
12b68e
+/* LD_AUDIT variable contents.  Must be processed before the
12b68e
+   audit_list below.  */
12b68e
+const char *audit_list_string;
12b68e
+
12b68e
+/* Cyclic list of auditing DSOs.  audit_list->next is the first
12b68e
+   element.  */
12b68e
 static struct audit_list
12b68e
 {
12b68e
   const char *name;
12b68e
   struct audit_list *next;
12b68e
 } *audit_list;
12b68e
 
12b68e
+/* Iterator for audit_list_string followed by audit_list.  */
12b68e
+struct audit_list_iter
12b68e
+{
12b68e
+  /* Tail of audit_list_string still needing processing, or NULL.  */
12b68e
+  const char *audit_list_tail;
12b68e
+
12b68e
+  /* The list element returned in the previous iteration.  NULL before
12b68e
+     the first element.  */
12b68e
+  struct audit_list *previous;
12b68e
+
12b68e
+  /* Scratch buffer for returning a name which is part of
12b68e
+     audit_list_string.  */
12b68e
+  char fname[PATH_MAX];
12b68e
+};
12b68e
+
12b68e
+/* Initialize an audit list iterator.  */
12b68e
+static void
12b68e
+audit_list_iter_init (struct audit_list_iter *iter)
12b68e
+{
12b68e
+  iter->audit_list_tail = audit_list_string;
12b68e
+  iter->previous = NULL;
12b68e
+}
12b68e
+
12b68e
+/* Iterate through both audit_list_string and audit_list.  */
12b68e
+static const char *
12b68e
+audit_list_iter_next (struct audit_list_iter *iter)
12b68e
+{
12b68e
+  if (iter->audit_list_tail != NULL)
12b68e
+    {
12b68e
+      /* First iterate over audit_list_string.  */
12b68e
+      while (*iter->audit_list_tail != '\0')
12b68e
+	{
12b68e
+	  /* Split audit list at colon.  */
12b68e
+	  size_t len = strcspn (iter->audit_list_tail, ":");
12b68e
+	  if (len > 0 && len < PATH_MAX)
12b68e
+	    {
12b68e
+	      memcpy (iter->fname, iter->audit_list_tail, len);
12b68e
+	      iter->fname[len] = '\0';
12b68e
+	    }
12b68e
+	  else
12b68e
+	    /* Do not return this name to the caller.  */
12b68e
+	    iter->fname[0] = '\0';
12b68e
+
12b68e
+	  /* Skip over the substring and the following delimiter.  */
12b68e
+	  iter->audit_list_tail += len;
12b68e
+	  if (*iter->audit_list_tail == ':')
12b68e
+	    ++iter->audit_list_tail;
12b68e
+
12b68e
+	  /* If the name is valid, return it.  */
12b68e
+	  if (dso_name_valid_for_suid (iter->fname))
12b68e
+	    return iter->fname;
12b68e
+	  /* Otherwise, wrap around and try the next name.  */
12b68e
+	}
12b68e
+      /* Fall through to the procesing of audit_list.  */
12b68e
+    }
12b68e
+
12b68e
+  if (iter->previous == NULL)
12b68e
+    {
12b68e
+      if (audit_list == NULL)
12b68e
+	/* No pre-parsed audit list.  */
12b68e
+	return NULL;
12b68e
+      /* Start of audit list.  The first list element is at
12b68e
+	 audit_list->next (cyclic list).  */
12b68e
+      iter->previous = audit_list->next;
12b68e
+      return iter->previous->name;
12b68e
+    }
12b68e
+  if (iter->previous == audit_list)
12b68e
+    /* Cyclic list wrap-around.  */
12b68e
+    return NULL;
12b68e
+  iter->previous = iter->previous->next;
12b68e
+  return iter->previous->name;
12b68e
+}
12b68e
+
12b68e
 /* Set nonzero during loading and initialization of executable and
12b68e
    libraries, cleared before the executable's entry point runs.  This
12b68e
    must not be initialized to nonzero, because the unused dynamic
12b68e
@@ -1441,11 +1519,13 @@ of this helper program; chances are you
12b68e
     GL(dl_rtld_map).l_tls_modid = _dl_next_tls_modid ();
12b68e
 
12b68e
   /* If we have auditing DSOs to load, do it now.  */
12b68e
-  if (__builtin_expect (audit_list != NULL, 0))
12b68e
+  bool need_security_init = true;
12b68e
+  if (__builtin_expect (audit_list != NULL, 0)
12b68e
+      || __builtin_expect (audit_list_string != NULL, 0))
12b68e
     {
12b68e
-      /* Iterate over all entries in the list.  The order is important.  */
12b68e
       struct audit_ifaces *last_audit = NULL;
12b68e
-      struct audit_list *al = audit_list->next;
12b68e
+      struct audit_list_iter al_iter;
12b68e
+      audit_list_iter_init (&al_iter);
12b68e
 
12b68e
       /* Since we start using the auditing DSOs right away we need to
12b68e
 	 initialize the data structures now.  */
12b68e
@@ -1456,9 +1536,14 @@ of this helper program; chances are you
12b68e
 	 use different values (especially the pointer guard) and will
12b68e
 	 fail later on.  */
12b68e
       security_init ();
12b68e
+      need_security_init = false;
12b68e
 
12b68e
-      do
12b68e
+      while (true)
12b68e
 	{
12b68e
+	  const char *name = audit_list_iter_next (&al_iter);
12b68e
+	  if (name == NULL)
12b68e
+	    break;
12b68e
+
12b68e
 	  int tls_idx = GL(dl_tls_max_dtv_idx);
12b68e
 
12b68e
 	  /* Now it is time to determine the layout of the static TLS
12b68e
@@ -1467,7 +1552,7 @@ of this helper program; chances are you
12b68e
 	     no DF_STATIC_TLS bit is set.  The reason is that we know
12b68e
 	     glibc will use the static model.  */
12b68e
 	  struct dlmopen_args dlmargs;
12b68e
-	  dlmargs.fname = al->name;
12b68e
+	  dlmargs.fname = name;
12b68e
 	  dlmargs.map = NULL;
12b68e
 
12b68e
 	  const char *objname;
12b68e
@@ -1480,7 +1565,7 @@ of this helper program; chances are you
12b68e
 	    not_loaded:
12b68e
 	      _dl_error_printf ("\
12b68e
 ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n",
12b68e
-				al->name, err_str);
12b68e
+				name, err_str);
12b68e
 	      if (malloced)
12b68e
 		free ((char *) err_str);
12b68e
 	    }
12b68e
@@ -1584,10 +1669,7 @@ ERROR: ld.so: object '%s' cannot be load
12b68e
 		  goto not_loaded;
12b68e
 		}
12b68e
 	    }
12b68e
-
12b68e
-	  al = al->next;
12b68e
 	}
12b68e
-      while (al != audit_list->next);
12b68e
 
12b68e
       /* If we have any auditing modules, announce that we already
12b68e
 	 have two objects loaded.  */
12b68e
@@ -1851,7 +1933,7 @@ ERROR: ld.so: object '%s' cannot be load
12b68e
   if (tcbp == NULL)
12b68e
     tcbp = init_tls ();
12b68e
 
12b68e
-  if (__builtin_expect (audit_list == NULL, 1))
12b68e
+  if (need_security_init)
12b68e
     /* Initialize security features.  But only if we have not done it
12b68e
        earlier.  */
12b68e
     security_init ();
12b68e
@@ -2495,9 +2577,7 @@ process_dl_audit (char *str)
12b68e
   char *p;
12b68e
 
12b68e
   while ((p = (strsep) (&str, ":")) != NULL)
12b68e
-    if (p[0] != '\0'
12b68e
-	&& (__builtin_expect (! INTUSE(__libc_enable_secure), 1)
12b68e
-	    || strchr (p, '/') == NULL))
12b68e
+    if (dso_name_valid_for_suid (p))
12b68e
       {
12b68e
 	/* This is using the local malloc, not the system malloc.  The
12b68e
 	   memory can never be freed.  */
12b68e
@@ -2561,7 +2641,7 @@ process_envvars (enum mode *modep)
12b68e
 	      break;
12b68e
 	    }
12b68e
 	  if (memcmp (envline, "AUDIT", 5) == 0)
12b68e
-	    process_dl_audit (&envline[6]);
12b68e
+	    audit_list_string = &envline[6];
12b68e
 	  break;
12b68e
 
12b68e
 	case 7: