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.c61
1 files changed, 52 insertions, 9 deletions
diff --git a/elf/dl-load.c b/elf/dl-load.c
index 96c1eb6bc6..cc94d7b510 100644
--- a/elf/dl-load.c
+++ b/elf/dl-load.c
@@ -793,7 +793,7 @@ _dl_map_object_from_fd (char *name, int fd, char *realname,
    with the malloc'd full directory name.  */
 
 static int
-open_path (const char *name, size_t namelen,
+open_path (const char *name, size_t namelen, int preloaded,
 	   struct r_search_path_elem **dirs,
 	   char **realname)
 {
@@ -839,9 +839,31 @@ open_path (const char *name, size_t namelen,
 		else
 		  this_dir->machdirstatus = existing;
 	      }
+	  if (fd != -1 && preloaded && __libc_enable_secure)
+	    {
+	      /* This is an extra security effort to make sure nobody can
+		 preload broken shared objects which are in the trusted
+		 directories and so exploit the bugs.  */
+	      struct stat st;
+
+	      if (__fxstat (_STAT_VER, fd, &st) != 0
+		  || (st.st_mode & S_ISUID) == 0)
+		{
+		  /* The shared object cannot be tested for being SUID
+		     or this bit is not set.  In this case we must not
+		     use this object.  */
+		  __close (fd);
+		  fd = -1;
+		  /* We simply ignore the file, signal this by setting
+		     the error value which would have been set by `open'.  */
+		  errno = ENOENT;
+		}
+	    }
 	}
+      else
+	errno = ENOENT;
 
-      if (fd == -1 && this_dir->dirstatus != nonexisting)
+      if (fd == -1 && errno == ENOENT && this_dir->dirstatus != nonexisting)
 	{
 	  /* Construct the pathname to try.  */
 	  buflen = ((char *) __mempcpy (__mempcpy (buf, this_dir->dirname,
@@ -871,12 +893,32 @@ open_path (const char *name, size_t namelen,
 		  else
 		    this_dir->dirstatus = existing;
 		}
+	  if (fd != -1 && preloaded && __libc_enable_secure)
+	    {
+	      /* This is an extra security effort to make sure nobody can
+		 preload broken shared objects which are in the trusted
+		 directories and so exploit the bugs.  */
+	      struct stat st;
+
+	      if (__fxstat (_STAT_VER, fd, &st) != 0
+		  || (st.st_mode & S_ISUID) == 0)
+		{
+		  /* The shared object cannot be tested for being SUID
+		     or this bit is not set.  In this case we must not
+		     use this object.  */
+		  __close (fd);
+		  fd = -1;
+		  /* We simply ignore the file, signal this by setting
+		     the error value which would have been set by `open'.  */
+		  errno = ENOENT;
+		}
+	    }
 	}
 
       if (fd != -1)
 	{
 	  *realname = malloc (buflen);
-	  if (*realname)
+	  if (*realname != NULL)
 	    {
 	      memcpy (*realname, buf, buflen);
 	      return fd;
@@ -901,8 +943,8 @@ open_path (const char *name, size_t namelen,
 /* Map in the shared object file NAME.  */
 
 struct link_map *
-_dl_map_object (struct link_map *loader, const char *name, int type,
-		int trace_mode)
+_dl_map_object (struct link_map *loader, const char *name, int preloaded,
+		int type, int trace_mode)
 {
   int fd;
   char *realname;
@@ -963,7 +1005,8 @@ _dl_map_object (struct link_map *loader, const char *name, int type,
 	      }
 
 	    if (l->l_rpath_dirs != (struct r_search_path_elem **) -1l)
-	      fd = open_path (name, namelen, l->l_rpath_dirs, &realname);
+	      fd = open_path (name, namelen, preloaded, l->l_rpath_dirs,
+			      &realname);
 	  }
 
       /* If dynamically linked, try the DT_RPATH of the executable itself
@@ -971,12 +1014,12 @@ _dl_map_object (struct link_map *loader, const char *name, int type,
       l = _dl_loaded;
       if (fd == -1 && l && l->l_type != lt_loaded
 	  && l->l_rpath_dirs != (struct r_search_path_elem **) -1l)
-	fd = open_path (name, namelen, l->l_rpath_dirs, &realname);
+	fd = open_path (name, namelen, preloaded, l->l_rpath_dirs, &realname);
 
       /* This is used if a static binary uses dynamic loading and there
 	 is a LD_LIBRARY_PATH given.  */
       if (fd == -1 && fake_path_list != NULL)
-	fd = open_path (name, namelen, fake_path_list, &realname);
+	fd = open_path (name, namelen, preloaded, fake_path_list, &realname);
 
       if (fd == -1)
 	{
@@ -1001,7 +1044,7 @@ _dl_map_object (struct link_map *loader, const char *name, int type,
 
       /* Finally, try the default path.  */
       if (fd == -1)
-	fd = open_path (name, namelen, rtld_search_dirs, &realname);
+	fd = open_path (name, namelen, preloaded, rtld_search_dirs, &realname);
     }
   else
     {