about summary refs log tree commit diff
path: root/elf
diff options
context:
space:
mode:
Diffstat (limited to 'elf')
-rw-r--r--elf/dl-deps.c8
-rw-r--r--elf/dl-load.c61
-rw-r--r--elf/dl-open.c2
-rw-r--r--elf/link.h8
-rw-r--r--elf/rtld.c12
5 files changed, 69 insertions, 22 deletions
diff --git a/elf/dl-deps.c b/elf/dl-deps.c
index 27de231dff..c069fab0c8 100644
--- a/elf/dl-deps.c
+++ b/elf/dl-deps.c
@@ -1,5 +1,5 @@
 /* Load the dependencies of a mapped object.
-   Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+   Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -53,7 +53,7 @@ openaux (void *a)
 {
   struct openaux_args *args = (struct openaux_args *) a;
 
-  args->aux = _dl_map_object (args->map, args->strtab + args->d->d_un.d_val,
+  args->aux = _dl_map_object (args->map, args->strtab + args->d->d_un.d_val, 0,
 			      (args->map->l_type == lt_executable
 			       ? lt_library : args->map->l_type),
 			      args->trace_mode);
@@ -160,7 +160,7 @@ _dl_map_object_deps (struct link_map *map,
 	      {
 		/* Map in the needed object.  */
 		struct link_map *dep
-		  = _dl_map_object (l, strtab + d->d_un.d_val,
+		  = _dl_map_object (l, strtab + d->d_un.d_val, 0,
 				    l->l_type == lt_executable ? lt_library :
 				    l->l_type, trace_mode);
 		/* Allocate new entry.  */
@@ -216,7 +216,7 @@ _dl_map_object_deps (struct link_map *map,
 		  }
 		else
 		  /* For filter objects the dependency must be available.  */
-		  args.aux = _dl_map_object (l, strtab + d->d_un.d_val,
+		  args.aux = _dl_map_object (l, strtab + d->d_un.d_val, 0,
 					     (l->l_type == lt_executable
 					      ? lt_library : l->l_type),
 					     trace_mode);
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
     {
diff --git a/elf/dl-open.c b/elf/dl-open.c
index d095f5e65d..c97321edf0 100644
--- a/elf/dl-open.c
+++ b/elf/dl-open.c
@@ -61,7 +61,7 @@ _dl_open (const char *file, int mode)
   __libc_lock_lock (_dl_load_lock);
 
   /* Load the named object.  */
-  new = _dl_map_object (NULL, file, lt_loaded, 0);
+  new = _dl_map_object (NULL, file, 0, lt_loaded, 0);
   if (new->l_searchlist)
     {
       /* It was already open.  */
diff --git a/elf/link.h b/elf/link.h
index 7f2dc674db..67701a13b7 100644
--- a/elf/link.h
+++ b/elf/link.h
@@ -296,10 +296,12 @@ extern int _dlerror_run (void (*operate) (void *), void *args);
 
 /* Open the shared object NAME and map in its segments.
    LOADER's DT_RPATH is used in searching for NAME.
-   If the object is already opened, returns its existing map.  */
+   If the object is already opened, returns its existing map.
+   For preloaded shared objects PRELOADED is set to a non-zero
+   value to allow additional security checks.  */
 extern struct link_map *_dl_map_object (struct link_map *loader,
-					const char *name, int type,
-					int trace_mode);
+					const char *name, int preloaded,
+					int type, int trace_mode);
 
 /* Call _dl_map_object on the dependencies of MAP, and set up
    MAP->l_searchlist.  PRELOADS points to a vector of NPRELOADS previously
diff --git a/elf/rtld.c b/elf/rtld.c
index 9529b9c14e..2ca1692584 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -187,7 +187,7 @@ static void
 map_doit (void *a)
 {
   struct map_args *args = (struct map_args *)a;
-  args->main_map = _dl_map_object (NULL, args->str, lt_library, 0);
+  args->main_map = _dl_map_object (NULL, args->str, 0, lt_library, 0);
 }
 
 static void
@@ -394,7 +394,7 @@ of this helper program; chances are you did not intend to run this program.\n",
 	    }
 	}
       else
-	main_map = _dl_map_object (NULL, _dl_argv[0], lt_library, 0);
+	main_map = _dl_map_object (NULL, _dl_argv[0], 0, lt_library, 0);
 
       phdr = main_map->l_phdr;
       phent = main_map->l_phnum;
@@ -509,7 +509,8 @@ of this helper program; chances are you did not intend to run this program.\n",
       while ((p = strsep (&list, " :")) != NULL)
 	if (! __libc_enable_secure || strchr (p, '/') == NULL)
 	  {
-	    struct link_map *new_map = _dl_map_object (NULL, p, lt_library, 0);
+	    struct link_map *new_map = _dl_map_object (NULL, p, 1,
+						       lt_library, 0);
 	    if (new_map->l_opencount == 1)
 	      /* It is no duplicate.  */
 	      ++npreloads;
@@ -569,7 +570,7 @@ of this helper program; chances are you did not intend to run this program.\n",
 	  runp = file + strspn (file, ": \t\n");
 	  while ((p = strsep (&runp, ": \t\n")) != NULL)
 	    {
-	      struct link_map *new_map = _dl_map_object (NULL, p,
+	      struct link_map *new_map = _dl_map_object (NULL, p, 1,
 							 lt_library, 0);
 	      if (new_map->l_opencount == 1)
 		/* It is no duplicate.  */
@@ -583,7 +584,8 @@ of this helper program; chances are you did not intend to run this program.\n",
       if (problem != NULL)
 	{
 	  char *p = strndupa (problem, file_size - (problem - file));
-	  struct link_map *new_map = _dl_map_object (NULL, p, lt_library, 0);
+	  struct link_map *new_map = _dl_map_object (NULL, p, 1,
+						     lt_library, 0);
 	  if (new_map->l_opencount == 1)
 	    /* It is no duplicate.  */
 	    ++npreloads;