[gnome-shell] Add check_cloexec_fds debug command



commit 49d8ff38e76e2ebcfc7fe6e3d4dca3f55f56d79a
Author: Daniel Drake <drake endlessm com>
Date:   Fri Jul 27 11:30:22 2018 -0500

    Add check_cloexec_fds debug command
    
    Add a debug command (to be executed manually via Alt+F2) to check
    that all of gnome-shell's file descriptors have the CLOEXEC flag set.
    This is important so that internal file descriptors do not get passed
    to apps when they are launched.
    
    It prints a warning message for every fd that does not have the flag set.
    
    fdwalk() is used from the standard library if available (it is not
    available in glibc), otherwise we use the same implementation as glib
    has internally.
    
    https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/132

 config.h.meson     |   3 ++
 js/ui/runDialog.js |   6 ++-
 meson.build        |   4 ++
 src/shell-util.c   | 108 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/shell-util.h   |   2 +
 5 files changed, 122 insertions(+), 1 deletion(-)
---
diff --git a/config.h.meson b/config.h.meson
index 0dac17b94..141b2240a 100644
--- a/config.h.meson
+++ b/config.h.meson
@@ -27,3 +27,6 @@
 
 /* Define if you have the `g_desktop_app_info_launch_uris_as_manager_with_fds` function */
 #mesondefine HAVE_GIO_DESKTOP_LAUNCH_URIS_WITH_FDS
+
+/* Define if fdwalk is available in libc */
+#mesondefine HAVE_FDWALK
diff --git a/js/ui/runDialog.js b/js/ui/runDialog.js
index 606a68396..b514f5b9f 100644
--- a/js/ui/runDialog.js
+++ b/js/ui/runDialog.js
@@ -62,7 +62,11 @@ var RunDialog = new Lang.Class({
                                    'rt': () => {
                                        Main.reloadThemeResource();
                                        Main.loadTheme();
-                                   }
+                                   },
+
+                                   'check_cloexec_fds': () => {
+                                       Shell.util_check_cloexec_fds();
+                                   },
                                  };
 
 
diff --git a/meson.build b/meson.build
index 5750b4fec..cafba27a8 100644
--- a/meson.build
+++ b/meson.build
@@ -173,6 +173,10 @@ cdata.set('HAVE__NL_TIME_FIRST_WEEKDAY',
   cc.has_header_symbol('langinfo.h', '_NL_TIME_FIRST_WEEKDAY')
 )
 
+cdata.set('HAVE_FDWALK',
+          cc.has_function('fdwalk')
+)
+
 config_h = configure_file(
   input: 'config.h.meson',
   output: 'config.h',
diff --git a/src/shell-util.c b/src/shell-util.c
index 70b8c0611..411f5fad7 100644
--- a/src/shell-util.c
+++ b/src/shell-util.c
@@ -2,8 +2,15 @@
 
 #include "config.h"
 
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
 #include <sys/types.h>
 #include <sys/wait.h>
+#ifdef HAVE_SYS_RESOURCE_H
+#include <sys/resource.h>
+#endif
 
 #include <GL/gl.h>
 #include <cogl/cogl.h>
@@ -514,3 +521,104 @@ shell_util_composite_capture_images (ClutterCapture  *captures,
 
   return image;
 }
+
+#ifndef HAVE_FDWALK
+static int
+fdwalk (int (*cb)(void *data, int fd), void *data)
+{
+  gint open_max;
+  gint fd;
+  gint res = 0;
+
+#ifdef HAVE_SYS_RESOURCE_H
+  struct rlimit rl;
+#endif
+
+#ifdef __linux__
+  DIR *d;
+
+  if ((d = opendir("/proc/self/fd"))) {
+      struct dirent *de;
+
+      while ((de = readdir(d))) {
+          glong l;
+          gchar *e = NULL;
+
+          if (de->d_name[0] == '.')
+              continue;
+
+          errno = 0;
+          l = strtol(de->d_name, &e, 10);
+          if (errno != 0 || !e || *e)
+              continue;
+
+          fd = (gint) l;
+
+          if ((glong) fd != l)
+              continue;
+
+          if (fd == dirfd(d))
+              continue;
+
+          if ((res = cb (data, fd)) != 0)
+              break;
+        }
+
+      closedir(d);
+      return res;
+  }
+
+  /* If /proc is not mounted or not accessible we fall back to the old
+   * rlimit trick */
+
+#endif
+
+#ifdef HAVE_SYS_RESOURCE_H
+  if (getrlimit(RLIMIT_NOFILE, &rl) == 0 && rl.rlim_max != RLIM_INFINITY)
+      open_max = rl.rlim_max;
+  else
+#endif
+      open_max = sysconf (_SC_OPEN_MAX);
+
+  for (fd = 0; fd < open_max; fd++)
+      if ((res = cb (data, fd)) != 0)
+          break;
+
+  return res;
+}
+#endif
+
+static int
+check_cloexec(void *data, gint fd)
+{
+  int r;
+
+  if (fd < 3)
+    return 0;
+
+  r = fcntl (fd, F_GETFD);
+  if (r < 0)
+    return 0;
+
+  if (!(r & FD_CLOEXEC))
+    g_warning ("fd %d is not CLOEXEC", fd);
+
+  return 0;
+}
+
+/**
+ * shell_util_check_cloexec_fds:
+ *
+ * Walk over all open file descriptors. Check them for the FD_CLOEXEC flag.
+ * If this flag is not set, log the offending file descriptor number.
+ *
+ * It is important that gnome-shell's file descriptors are all marked CLOEXEC,
+ * so that the shell's open file descriptors are not passed to child processes
+ * that we launch.
+ */
+void
+shell_util_check_cloexec_fds (void)
+{
+  fdwalk (check_cloexec, NULL);
+  g_info ("Open fd CLOEXEC check complete");
+}
diff --git a/src/shell-util.h b/src/shell-util.h
index 2218594c1..408b55f68 100644
--- a/src/shell-util.h
+++ b/src/shell-util.h
@@ -60,6 +60,8 @@ cairo_surface_t * shell_util_composite_capture_images (ClutterCapture  *captures
                                                        int              width,
                                                        int              height);
 
+void shell_util_check_cloexec_fds (void);
+
 G_END_DECLS
 
 #endif /* __SHELL_UTIL_H__ */


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]