1
1
mirror of https://github.com/systemd/systemd-stable.git synced 2025-01-07 17:17:44 +03:00

fd-util: split out inner fallback loop of close_all_fds() as close_all_fds_without_malloc()

This commit is contained in:
Lennart Poettering 2021-10-12 15:53:27 +02:00
parent c85cb3bc7f
commit 11966552a8
2 changed files with 38 additions and 30 deletions

View File

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

View File

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