Prevent unintended file desriptor leak in grantpt.
authorUlrich Drepper <drepper@redhat.com>
Wed, 25 Nov 2009 02:24:14 +0000 (18:24 -0800)
committerUlrich Drepper <drepper@redhat.com>
Wed, 25 Nov 2009 02:24:14 +0000 (18:24 -0800)
The pt_chown program is completely transparently called.  It might
not be able to live with the various file descriptors the program
has open at the time of the call (e.g., under SELinux).  Close all
but the needed descriptor and connect stdin, stdout, and stderr
with /dev/null.  pt_chown shouldn't print anything when called to
do real work.

ChangeLog
login/programs/pt_chown.c
sysdeps/unix/grantpt.c
sysdeps/unix/sysv/linux/grantpt.c [new file with mode: 0644]

index c78e190..173fe78 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,11 @@
 2009-11-24  Ulrich Drepper  <drepper@redhat.com>
 
+       * sysdeps/unix/grantpt.c (grantpt): Use CLOSE_ALL_FDS is available
+       before the exec.
+       * sysdeps/unix/sysv/linux/grantpt.c: New file.
+       * login/programs/pt_chown.c (main): Don't print message on errors
+       when doing real work.
+
        * sysdeps/unix/grantpt.c (grantpt): Only get tty group information
        once.
 
index 7e279a5..4c36f2c 100644 (file)
@@ -154,8 +154,7 @@ main (int argc, char *argv[])
 # define ncap_list (sizeof (cap_list) / sizeof (cap_list[0]))
          cap_t caps = cap_init ();
          if (caps == NULL)
-           error (FAIL_ENOMEM, errno,
-                  _("Failed to initialize drop of capabilities"));
+           return FAIL_ENOMEM;
 
          /* There is no reason why these should not work.  */
          cap_set_flag (caps, CAP_PERMITTED, ncap_list, cap_list, CAP_SET);
@@ -166,7 +165,7 @@ main (int argc, char *argv[])
          cap_free (caps);
 
          if (__builtin_expect (res != 0, 0))
-           error (FAIL_EXEC, errno, _("cap_set_proc failed"));
+           return FAIL_EXEC;
        }
 #endif
 
index e140fb2..2a7a963 100644 (file)
@@ -194,6 +194,10 @@ grantpt (int fd)
        if (__dup2 (fd, PTY_FILENO) < 0)
          _exit (FAIL_EBADF);
 
+#ifdef CLOSE_ALL_FDS
+      CLOSE_ALL_FDS ();
+#endif
+
       execle (_PATH_PT_CHOWN, basename (_PATH_PT_CHOWN), NULL, NULL);
       _exit (FAIL_EXEC);
     }
diff --git a/sysdeps/unix/sysv/linux/grantpt.c b/sysdeps/unix/sysv/linux/grantpt.c
new file mode 100644 (file)
index 0000000..6305ed4
--- /dev/null
@@ -0,0 +1,42 @@
+#include <assert.h>
+#include <ctype.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <paths.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "not-cancel.h"
+#include "pty-private.h"
+
+
+/* Close all file descriptors except the one specified.  */
+static void
+close_all_fds (void)
+{
+  DIR *dir = opendir ("/proc/self/fd");
+  if (dir != NULL)
+    {
+      struct dirent64 *d;
+      while ((d = readdir64 (dir)) != NULL)
+       if (isdigit (d->d_name[0]))
+         {
+           char *endp;
+           long int fd = strtol (d->d_name, &endp, 10);
+           if (*endp == '\0' && fd != PTY_FILENO && fd != dirfd (dir))
+             close_not_cancel_no_status (fd);
+         }
+
+      closedir (dir);
+
+      int nullfd = open_not_cancel_2 (_PATH_DEVNULL, O_RDONLY);
+      assert (nullfd == STDIN_FILENO);
+      nullfd = open_not_cancel_2 (_PATH_DEVNULL, O_WRONLY);
+      assert (nullfd == STDOUT_FILENO);
+      __dup2 (STDOUT_FILENO, STDERR_FILENO);
+    }
+}
+#define CLOSE_ALL_FDS() close_all_fds()
+
+#include <sysdeps/unix/grantpt.c>