Skip to content

Commit

Permalink
fd-util: split out inner fallback loop of close_all_fds() as close_al…
Browse files Browse the repository at this point in the history
…l_fds_without_malloc()
  • Loading branch information
poettering committed Oct 27, 2021
1 parent c85cb3b commit 1196655
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 30 deletions.
67 changes: 37 additions & 30 deletions src/basic/fd-util.c
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,41 @@ static int get_max_fd(void) {
return (int) (m - 1);
}

int close_all_fds_without_malloc(const int except[], size_t n_except) {
int max_fd, r = 0;

assert(n_except == 0 || except);

/* This is the inner fallback core of close_all_fds(). This never calls malloc() or opendir() or so
* and hence is safe to be called in signal handler context. Most users should call close_all_fds(),
* but when we assume we are called from signal handler context, then use this simpler call
* instead. */

max_fd = get_max_fd();
if (max_fd < 0)
return max_fd;

/* Refuse to do the loop over more too many elements. It's better to fail immediately than to
* spin the CPU for a long time. */
if (max_fd > MAX_FD_LOOP_LIMIT)
return log_debug_errno(SYNTHETIC_ERRNO(EPERM),
"Refusing to loop over %d potential fds.",
max_fd);

for (int fd = 3; fd >= 0; fd = fd < max_fd ? fd + 1 : -1) {
int q;

if (fd_in_set(fd, except, n_except))
continue;

q = close_nointr(fd);
if (q < 0 && q != -EBADF && r >= 0)
r = q;
}

return r;
}

int close_all_fds(const int except[], size_t n_except) {
static bool have_close_range = true; /* Assume we live in the future */
_cleanup_closedir_ DIR *d = NULL;
Expand Down Expand Up @@ -301,36 +336,8 @@ int close_all_fds(const int except[], size_t n_except) {
}

d = opendir("/proc/self/fd");
if (!d) {
int fd, max_fd;

/* When /proc isn't available (for example in chroots) the fallback is brute forcing through
* the fd table */

max_fd = get_max_fd();
if (max_fd < 0)
return max_fd;

/* Refuse to do the loop over more too many elements. It's better to fail immediately than to
* spin the CPU for a long time. */
if (max_fd > MAX_FD_LOOP_LIMIT)
return log_debug_errno(SYNTHETIC_ERRNO(EPERM),
"/proc/self/fd is inaccessible. Refusing to loop over %d potential fds.",
max_fd);

for (fd = 3; fd >= 0; fd = fd < max_fd ? fd + 1 : -1) {
int q;

if (fd_in_set(fd, except, n_except))
continue;

q = close_nointr(fd);
if (q < 0 && q != -EBADF && r >= 0)
r = q;
}

return r;
}
if (!d)
return close_all_fds_without_malloc(except, n_except); /* ultimate fallback if /proc/ is not available */

FOREACH_DIRENT(de, d, return -errno) {
int fd = -1, q;
Expand Down
1 change: 1 addition & 0 deletions src/basic/fd-util.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ int fd_nonblock(int fd, bool nonblock);
int fd_cloexec(int fd, bool cloexec);

int close_all_fds(const int except[], size_t n_except);
int close_all_fds_without_malloc(const int except[], size_t n_except);

int same_fd(int a, int b);

Expand Down

0 comments on commit 1196655

Please sign in to comment.