]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
fd-util: split out inner fallback loop of close_all_fds() as close_all_fds_without_ma...
authorLennart Poettering <lennart@poettering.net>
Tue, 12 Oct 2021 13:53:27 +0000 (15:53 +0200)
committerLennart Poettering <lennart@poettering.net>
Wed, 27 Oct 2021 15:56:36 +0000 (17:56 +0200)
src/basic/fd-util.c
src/basic/fd-util.h

index dec083daaf90bd6fb2806c756a9d39f271abad04..274bbb32cc04b32b3b0e62e80535da522bfa4c40 100644 (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;
index 459059c64ee733015f974c36ddd2476aaea19d55..e929386b539218f0ed5ca14899d2ff2a94245b08 100644 (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);