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