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
This commit is contained in:
Daniel Drake 2018-07-27 11:30:22 -05:00 committed by Florian Müllner
parent 4b522a02c3
commit 49d8ff38e7
5 changed files with 122 additions and 1 deletions

View File

@ -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

View File

@ -62,7 +62,11 @@ var RunDialog = new Lang.Class({
'rt': () => {
Main.reloadThemeResource();
Main.loadTheme();
}
},
'check_cloexec_fds': () => {
Shell.util_check_cloexec_fds();
},
};

View File

@ -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',

View File

@ -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");
}

View File

@ -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__ */