Optimise closing file descriptors.

Dnsmasq needs to close all the file descriptors it inherits, for security
reasons. This is traditionally done by calling close() on every possible
file descriptor (most of which won't be open.) On big servers where
"every possible file descriptor" is a rather large set, this gets
rather slow, so we use the /proc/<pid>/fd directory to get a list
of the fds which are acually open.

This only works on Linux. On other platforms, and on Linux systems
without a /proc filesystem, we fall back to the old way.
This commit is contained in:
Simon Kelley
2020-03-02 17:42:51 +00:00
parent 0541a1adf7
commit 48755ebf09

View File

@@ -708,6 +708,38 @@ int read_write(int fd, unsigned char *packet, int size, int rw)
/* close all fds except STDIN, STDOUT and STDERR, spare1, spare2 and spare3 */
void close_fds(long max_fd, int spare1, int spare2, int spare3)
{
/* On Linux, use the /proc/ filesystem to find which files
are actually open, rather than iterate over the whole space,
for efficiency reasons. If this fails we drop back to the dumb code. */
#ifdef HAVE_LINUX_NETWORK
DIR *d;
if ((d = opendir("/proc/self/fd")))
{
struct dirent *de;
while ((de = readdir(d)))
{
long fd;
char *e = NULL;
errno = 0;
fd = strtol(de->d_name, &e, 10);
if (errno != 0 || !e || *e || fd == dirfd(d) ||
fd == STDOUT_FILENO || fd == STDERR_FILENO || fd == STDIN_FILENO ||
fd == spare1 || fd == spare2 || fd == spare3)
continue;
close(fd);
}
closedir(d);
return;
}
#endif
/* fallback, dumb code. */
for (max_fd--; max_fd >= 0; max_fd--)
if (max_fd != STDOUT_FILENO && max_fd != STDERR_FILENO && max_fd != STDIN_FILENO &&
max_fd != spare1 && max_fd != spare2 && max_fd != spare3)