Skip to content

Commit

Permalink
catatoinit: close fds >= 3
Browse files Browse the repository at this point in the history
close any additional fd that was already leaked into the child
process.

Closes: #12

Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com>
  • Loading branch information
giuseppe committed Sep 2, 2021
1 parent 932bfab commit 047ac8e
Showing 1 changed file with 81 additions and 0 deletions.
81 changes: 81 additions & 0 deletions catatonit.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/syscall.h>
#include <limits.h>
#include <dirent.h>

#include "config.h"

Expand Down Expand Up @@ -136,6 +139,82 @@ int kernel_signals[] = {SIGFPE, SIGILL, SIGSEGV, SIGBUS, SIGABRT, SIGTRAP, SIGSY

#define ARRAY_LEN(arr) (sizeof(arr) / sizeof(*arr))

static int syscall_close_range(unsigned int fd, unsigned int max_fd, unsigned int flags)
{
#ifdef __NR_close_range
return (int) syscall(__NR_close_range, fd, max_fd, flags);
#else
errno = ENOSYS;
return -1;
#endif
}


/*
* Close every fd >= n that is different from exclude_fd using close_range.
*/
static int close_range_fds_ge_than(int n, int exclude_fd)
{
int r;

/* exclude_fd is not in the [n, UINT_MAX] range. */
if (exclude_fd < n)
return syscall_close_range(n, UINT_MAX, 0);

/* exclude_fd is the first fd in the [n, UINT_MAX] range. */
if (exclude_fd == n)
return syscall_close_range(n + 1, UINT_MAX, 0);

/* exclude_fd is between n and UINT_MAX. */
r = syscall_close_range(n, exclude_fd - 1, 0);
if (r < 0)
return r;
if (exclude_fd < UINT_MAX)
return syscall_close_range(exclude_fd + 1, UINT_MAX, 0);

return 0;
}

/*
* Close every fd >= n that is different from exclude_fd.
*/
static void close_fds_ge_than(int n, int exclude_fd)
{
struct dirent *next;
DIR *dir;
int fd;

if (close_range_fds_ge_than(n, exclude_fd) == 0)
return;

/* Fallback when close_range fails. */

dir = opendir("/proc/self/fd");
if (dir == NULL) {
warn("cannot opendir /proc/self/fd: %m");
return;
}

fd = dirfd(dir);
for (next = readdir (dir); next; next = readdir (dir)) {
long long val;
const char *name = next->d_name;
int r;

if (name[0] == '.')
continue;

val = strtoll (name, NULL, 10);
if (val < n || val == fd || val == exclude_fd)
continue;

r = close(val);
if (r < 0)
warn("cannot close %d: %m", val);
}
closedir(dir);
}

/*
* Makes the current process a "foreground" process, by making it the leader of
* a process group and session leader. It also updates the sigmask to include
Expand Down Expand Up @@ -361,6 +440,8 @@ int main(int argc, char **argv)
bail("self-check that pid1 (%d) was spawned failed: %m", pid1);
debug("pid1 (%d) spawned: %s", pid1, argv[0]);

close_fds_ge_than(3, sfd);

/*
* The "pid" we send signals to. With -g we send signals to the entire
* process group which pid1 is in, which is represented by a -ve pid.
Expand Down

0 comments on commit 047ac8e

Please sign in to comment.