summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2021-10-12 15:53:27 +0200
committerLennart Poettering <lennart@poettering.net>2021-10-27 17:56:36 +0200
commit11966552a88039869972ca4b450f622664bd1c5e (patch)
tree6d6142393eb02dab8d7ea9098e3e645bd7f64192
parentc85cb3bc7f00e857ea90e374b916b2fd7eb773ec (diff)
downloadsystemd-11966552a88039869972ca4b450f622664bd1c5e.tar.gz
fd-util: split out inner fallback loop of close_all_fds() as close_all_fds_without_malloc()
-rw-r--r--src/basic/fd-util.c67
-rw-r--r--src/basic/fd-util.h1
2 files changed, 38 insertions, 30 deletions
diff --git a/src/basic/fd-util.c b/src/basic/fd-util.c
index dec083daaf..274bbb32cc 100644
--- a/src/basic/fd-util.c
+++ b/src/basic/fd-util.c
@@ -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;
diff --git a/src/basic/fd-util.h b/src/basic/fd-util.h
index 459059c64e..e929386b53 100644
--- a/src/basic/fd-util.h
+++ b/src/basic/fd-util.h
@@ -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);