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