c6d234
CVE-2017-16997: Incorrect handling of RPATH or RUNPATH containing $ORIGIN
c6d234
for AT_SECURE or SUID binaries could be used to load libraries from the
c6d234
current directory.
c6d234
c6d234
Depends on f6110a8fee2ca36f8e2d2abecf3cba9fa7b8ea7d which is already
c6d234
backported by glibc-rh1452721-1.patch.
c6d234
c6d234
commit 3e3c904daef69b8bf7d5cc07f793c9f07c3553ef
c6d234
Author: Aurelien Jarno <aurelien@aurel32.net>
c6d234
Date:   Sat Dec 30 10:54:23 2017 +0100
c6d234
c6d234
    elf: Check for empty tokens before dynamic string token expansion [BZ #22625]
c6d234
c6d234
    The fillin_rpath function in elf/dl-load.c loops over each RPATH or
c6d234
    RUNPATH tokens and interprets empty tokens as the current directory
c6d234
    ("./"). In practice the check for empty token is done *after* the
c6d234
    dynamic string token expansion. The expansion process can return an
c6d234
    empty string for the $ORIGIN token if __libc_enable_secure is set
c6d234
    or if the path of the binary can not be determined (/proc not mounted).
c6d234
c6d234
    Fix that by moving the check for empty tokens before the dynamic string
c6d234
    token expansion. In addition, check for NULL pointer or empty strings
c6d234
    return by expand_dynamic_string_token.
c6d234
c6d234
    The above changes highlighted a bug in decompose_rpath, an empty array
c6d234
    is represented by the first element being NULL at the fillin_rpath
c6d234
    level, but by using a -1 pointer in decompose_rpath and other functions.
c6d234
c6d234
    Changelog:
c6d234
            [BZ #22625]
c6d234
            * elf/dl-load.c (fillin_rpath): Check for empty tokens before dynamic
c6d234
            string token expansion. Check for NULL pointer or empty string possibly
c6d234
            returned by expand_dynamic_string_token.
c6d234
            (decompose_rpath): Check for empty path after dynamic string
c6d234
            token expansion.
c6d234
c6d234
Index: glibc-2.17-c758a686/elf/dl-load.c
c6d234
===================================================================
c6d234
--- glibc-2.17-c758a686.orig/elf/dl-load.c
c6d234
+++ glibc-2.17-c758a686/elf/dl-load.c
c6d234
@@ -447,31 +447,39 @@ fillin_rpath (char *rpath, struct r_sear
c6d234
 {
c6d234
   char *cp;
c6d234
   size_t nelems = 0;
c6d234
-  char *to_free;
c6d234
 
c6d234
   while ((cp = __strsep (&rpath, sep)) != NULL)
c6d234
     {
c6d234
       struct r_search_path_elem *dirp;
c6d234
+      char *to_free = NULL;
c6d234
+      size_t len = 0;
c6d234
 
c6d234
-      to_free = cp = expand_dynamic_string_token (l, cp);
c6d234
-
c6d234
-      size_t len = strlen (cp);
c6d234
-
c6d234
-      /* `strsep' can pass an empty string.  This has to be
c6d234
-	 interpreted as `use the current directory'. */
c6d234
-      if (len == 0)
c6d234
+      /* `strsep' can pass an empty string.  */
c6d234
+      if (*cp != '\0')
c6d234
 	{
c6d234
-	  static const char curwd[] = "./";
c6d234
-	  cp = (char *) curwd;
c6d234
-	}
c6d234
+	  to_free = cp = expand_dynamic_string_token (l, cp);
c6d234
+	  /* expand_dynamic_string_token can return NULL in case of empty
c6d234
+	     path or memory allocation failure.  */
c6d234
+	  if (cp == NULL)
c6d234
+	    continue;
c6d234
+
c6d234
+	  /* Compute the length after dynamic string token expansion and
c6d234
+	     ignore empty paths.  */
c6d234
+	  len = strlen (cp);
c6d234
+	  if (len == 0)
c6d234
+	    {
c6d234
+	      free (to_free);
c6d234
+	      continue;
c6d234
+	    }
c6d234
 
c6d234
-      /* Remove trailing slashes (except for "/").  */
c6d234
-      while (len > 1 && cp[len - 1] == '/')
c6d234
-	--len;
c6d234
-
c6d234
-      /* Now add one if there is none so far.  */
c6d234
-      if (len > 0 && cp[len - 1] != '/')
c6d234
-	cp[len++] = '/';
c6d234
+	  /* Remove trailing slashes (except for "/").  */
c6d234
+	  while (len > 1 && cp[len - 1] == '/')
c6d234
+	    --len;
c6d234
+
c6d234
+	  /* Now add one if there is none so far.  */
c6d234
+	  if (len > 0 && cp[len - 1] != '/')
c6d234
+	    cp[len++] = '/';
c6d234
+	}
c6d234
 
c6d234
       /* See if this directory is already known.  */
c6d234
       for (dirp = GL(dl_all_dirs); dirp != NULL; dirp = dirp->next)
c6d234
@@ -626,6 +634,14 @@ decompose_rpath (struct r_search_path_st
c6d234
      necessary.  */
c6d234
   free (copy);
c6d234
 
c6d234
+  /* There is no path after expansion.  */
c6d234
+  if (result[0] == NULL)
c6d234
+    {
c6d234
+      free (result);
c6d234
+      sps->dirs = (struct r_search_path_elem **) -1;
c6d234
+      return false;
c6d234
+    }
c6d234
+
c6d234
   sps->dirs = result;
c6d234
   /* The caller will change this value if we haven't used a real malloc.  */
c6d234
   sps->malloced = 1;