]> granicus.if.org Git - linux-pam/commitdiff
libpam/pam_modutil_sanitize.c: optimize the way to close fds
authorChristophe Besson <cbesson@redhat.com>
Wed, 7 Aug 2019 12:25:51 +0000 (14:25 +0200)
committerTomáš Mráz <t8m@users.noreply.github.com>
Mon, 26 Aug 2019 13:10:15 +0000 (15:10 +0200)
configure.ac
libpam/pam_modutil_sanitize.c

index e9d4476904451d3fb09e819a0ef3d4772e28c8c1..e4995fc9499e1690c12891881681bc565d899ff2 100644 (file)
@@ -508,7 +508,7 @@ dnl Checks for header files.
 AC_HEADER_DIRENT
 AC_HEADER_STDC
 AC_HEADER_SYS_WAIT
-AC_CHECK_HEADERS(fcntl.h limits.h malloc.h sys/file.h sys/ioctl.h sys/time.h syslog.h net/if.h termio.h unistd.h sys/fsuid.h inittypes.h)
+AC_CHECK_HEADERS(fcntl.h limits.h malloc.h sys/file.h sys/ioctl.h sys/time.h syslog.h net/if.h termio.h unistd.h sys/fsuid.h inittypes.h sys/vfs.h linux/magic.h)
 
 dnl For module/pam_lastlog
 AC_CHECK_HEADERS(lastlog.h utmp.h utmpx.h)
index 65f85d011bfc9d7f954e2e563acea07b1c6c03e7..605c859db4622023804b38fdf8890de108c76f65 100644 (file)
 #include <fcntl.h>
 #include <syslog.h>
 #include <sys/resource.h>
+#include <dirent.h>
+#ifdef HAVE_SYS_VFS_H
+#include <sys/vfs.h>
+#endif
+#ifdef HAVE_LINUX_MAGIC_H
+#include <linux/magic.h>
+#endif
 
 /*
  * Creates a pipe, closes its write end, redirects fd to its read end.
@@ -112,31 +119,69 @@ redirect_out(pam_handle_t *pamh, enum pam_modutil_redirect_fd mode,
        return fd;
 }
 
+/* Check if path is in a procfs. */
+static int
+is_in_procfs(int fd)
+{
+#if defined HAVE_SYS_VFS_H && defined PROC_SUPER_MAGIC
+       struct statfs stfs;
+
+       if (fstatfs(fd, &stfs) == 0) {
+               if (stfs.f_type == PROC_SUPER_MAGIC)
+                       return 1;
+       } else {
+               return 0;
+       }
+#endif /* HAVE_SYS_VFS_H && PROC_SUPER_MAGIC */
+
+       return -1;
+}
+
 /* Closes all descriptors after stderr. */
 static void
 close_fds(void)
 {
+       DIR *dir = NULL;
+       struct dirent *dent;
+       int dfd = -1;
+       int fd;
+       struct rlimit rlim;
+
        /*
         * An arbitrary upper limit for the maximum file descriptor number
         * returned by RLIMIT_NOFILE.
         */
-       const int MAX_FD_NO = 65535;
+       const unsigned int MAX_FD_NO = 65535;
 
        /* The lower limit is the same as for _POSIX_OPEN_MAX. */
-       const int MIN_FD_NO = 20;
-
-       int fd;
-       struct rlimit rlim;
-
-       if (getrlimit(RLIMIT_NOFILE, &rlim) || rlim.rlim_max > MAX_FD_NO)
-               fd = MAX_FD_NO;
-       else if (rlim.rlim_max < MIN_FD_NO)
-               fd = MIN_FD_NO;
-       else
-               fd = rlim.rlim_max - 1;
+       const unsigned int MIN_FD_NO = 20;
+
+       /* If /proc is mounted, we can optimize which fd can be closed. */
+       if ((dir = opendir("/proc/self/fd")) != NULL) {
+               if ((dfd = dirfd(dir)) >= 0 && is_in_procfs(dfd) > 0) {
+                       while ((dent = readdir(dir)) != NULL) {
+                               fd = atoi(dent->d_name);
+                               if (fd > STDERR_FILENO && fd != dfd)
+                                       close(fd);
+                       }
+               } else {
+                       dfd = -1;
+               }
+               closedir(dir);
+       }
 
-       for (; fd > STDERR_FILENO; --fd)
-               close(fd);
+       /* If /proc isn't available, fallback to the previous behavior. */
+       if (dfd < 0) {
+               if (getrlimit(RLIMIT_NOFILE, &rlim) || rlim.rlim_max > MAX_FD_NO)
+                       fd = MAX_FD_NO;
+               else if (rlim.rlim_max < MIN_FD_NO)
+                       fd = MIN_FD_NO;
+               else
+                       fd = rlim.rlim_max - 1;
+
+               for (; fd > STDERR_FILENO; --fd)
+                       close(fd);
+       }
 }
 
 int