about summary refs log tree commit diff
path: root/elf/dl-load.c
diff options
context:
space:
mode:
Diffstat (limited to 'elf/dl-load.c')
-rw-r--r--elf/dl-load.c90
1 files changed, 48 insertions, 42 deletions
diff --git a/elf/dl-load.c b/elf/dl-load.c
index ad29386823..21c3274ae9 100644
--- a/elf/dl-load.c
+++ b/elf/dl-load.c
@@ -126,6 +126,8 @@ static const size_t system_dirs_len[] =
 {
   SYSTEM_DIRS_LEN
 };
+#define nsystem_dirs_len \
+  (sizeof (system_dirs_len) / sizeof (system_dirs_len[0]))
 
 
 /* Local version of `strdup' function.  */
@@ -362,32 +364,6 @@ fillin_rpath (char *rpath, struct r_search_path_elem **result, const char *sep,
       if (len > 0 && cp[len - 1] != '/')
 	cp[len++] = '/';
 
-      /* Make sure we don't use untrusted directories if we run SUID.  */
-      if (check_trusted)
-	{
-	  const char *trun = system_dirs;
-	  size_t idx;
-
-	  /* All trusted directories must be complete names.  */
-	  if (cp[0] != '/')
-	    continue;
-
-	  for (idx = 0;
-	       idx < sizeof (system_dirs_len) / sizeof (system_dirs_len[0]);
-	       ++idx)
-	    {
-	      if (len == system_dirs_len[idx] && memcmp (trun, cp, len) == 0)
-		/* Found it.  */
-		break;
-
-	      trun += system_dirs_len[idx] + 1;
-	    }
-
-	  if (idx == sizeof (system_dirs_len) / sizeof (system_dirs_len[0]))
-	    /* It's no trusted directory, skip it.  */
-	    continue;
-	}
-
       /* See if this directory is already known.  */
       for (dirp = all_dirs; dirp != NULL; dirp = dirp->next)
 	if (dirp->dirnamelen == len && memcmp (cp, dirp->dirname, len) == 0)
@@ -408,7 +384,7 @@ fillin_rpath (char *rpath, struct r_search_path_elem **result, const char *sep,
 	{
 	  size_t cnt;
 	  enum r_dir_status init_val;
-	  size_t where_len = strlen (where) + 1;
+	  size_t where_len = where ? strlen (where) + 1 : 0;
 
 	  /* It's a new directory.  Create an entry and add it.  */
 	  dirp = (struct r_search_path_elem *)
@@ -424,17 +400,51 @@ fillin_rpath (char *rpath, struct r_search_path_elem **result, const char *sep,
 	  if (len > max_dirnamelen)
 	    max_dirnamelen = len;
 
-	  /* We have to make sure all the relative directories are never
-	     ignored.  The current directory might change and all our
-	     saved information would be void.  */
-	  init_val = cp[0] != '/' ? existing : unknown;
+	  /* Make sure we don't use untrusted directories if we run SUID.  */
+	  if (__builtin_expect (check_trusted, 0))
+	    {
+	      const char *trun = system_dirs;
+	      size_t idx;
+
+	      /* By default we don't trust anything.  */
+	      init_val = nonexisting;
+
+	      /* All trusted directories must be complete names.  */
+	      if (cp[0] == '/')
+		{
+		  for (idx = 0; idx < nsystem_dirs_len; ++idx)
+		    {
+		      if (len == system_dirs_len[idx]
+			  && memcmp (trun, cp, len) == 0)
+			/* Found it.  */
+			break;
+
+		      trun += system_dirs_len[idx] + 1;
+		    }
+
+		  if (idx < nsystem_dirs_len)
+		    /* It's a trusted directory so allow checking for it.  */
+		    init_val = unknown;
+		}
+	    }
+	  else
+	    /* We don't have to check for trusted directories and can
+	       accept everything.  We have to make sure all the
+	       relative directories are never ignored.  The current
+	       directory might change and all our saved information
+	       would be void.  */
+	    init_val = cp[0] != '/' ? existing : unknown;
+
 	  for (cnt = 0; cnt < ncapstr; ++cnt)
 	    dirp->status[cnt] = init_val;
 
 	  dirp->what = what;
-	  dirp->where = memcpy ((char *) dirp + sizeof (*dirp)
-				+ ncapstr * sizeof (enum r_dir_status),
-				where, where_len);
+	  if (__builtin_expect (where != NULL, 1))
+	    dirp->where = memcpy ((char *) dirp + sizeof (*dirp)
+				  + ncapstr * sizeof (enum r_dir_status),
+				  where, where_len);
+	  else
+	    dirp->where = NULL;
 
 	  dirp->next = all_dirs;
 	  all_dirs = dirp;
@@ -531,8 +541,7 @@ _dl_init_paths (const char *llp)
 
   /* First set up the rest of the default search directory entries.  */
   aelem = rtld_search_dirs = (struct r_search_path_elem **)
-    malloc ((sizeof (system_dirs_len) / sizeof (system_dirs_len[0]) + 1)
-	     * sizeof (struct r_search_path_elem *));
+    malloc ((nsystem_dirs_len + 1) * sizeof (struct r_search_path_elem *));
   if (rtld_search_dirs == NULL)
     _dl_signal_error (ENOMEM, NULL, N_("cannot create search path array"));
 
@@ -570,13 +579,11 @@ _dl_init_paths (const char *llp)
 	for (cnt = 0; cnt < ncapstr; ++cnt)
 	  pelem->status[cnt] = unknown;
 
-      pelem->next = (++idx == (sizeof (system_dirs_len)
-			       / sizeof (system_dirs_len[0]))
-		     ? NULL : (pelem + round_size));
+      pelem->next = (++idx == nsystem_dirs_len ? NULL : (pelem + round_size));
 
       pelem += round_size;
     }
-  while (idx < sizeof (system_dirs_len) / sizeof (system_dirs_len[0]));
+  while (idx < nsystem_dirs_len);
 
   max_dirnamelen = SYSTEM_DIRS_MAX_LEN;
   *aelem = NULL;
@@ -1506,8 +1513,7 @@ _dl_map_object (struct link_map *loader, const char *name, int preloaded,
 		      dirp += system_dirs_len[cnt] + 1;
 		      ++cnt;
 		    }
-		  while (cnt < (sizeof (system_dirs_len)
-				/ sizeof (system_dirs_len[0])));
+		  while (cnt < nsystem_dirs_len);
 		}
 
 	      if (cached)