Blob Blame History Raw
From 5a73027642b826793658774df8a0536975120b19 Mon Sep 17 00:00:00 2001
From: John Eckersberg <jeckersb@redhat.com>
Date: Fri, 11 Oct 2019 08:59:41 -0400
Subject: [PATCH] Fix: libcrmservice: try not to spam close() file descriptors

With large file descriptor limits, action_launch_child can close
millions of non-existent file descriptors.

Instead, try to read open file descriptors from /proc or /dev/fd and
close only those which are open.

See rhbz#1762025
---
 lib/services/services_linux.c | 26 ++++++++++++++++++++++++--
 1 file changed, 24 insertions(+), 2 deletions(-)

diff --git a/lib/services/services_linux.c b/lib/services/services_linux.c
index 90c1f44..464fc5b 100644
--- a/lib/services/services_linux.c
+++ b/lib/services/services_linux.c
@@ -445,6 +445,7 @@ static void
 action_launch_child(svc_action_t *op)
 {
     int lpc;
+    DIR *dir;
 
     /* SIGPIPE is ignored (which is different from signal blocking) by the gnutls library.
      * Depending on the libqb version in use, libqb may set SIGPIPE to be ignored as well. 
@@ -476,8 +477,29 @@ action_launch_child(svc_action_t *op)
     setpgid(0, 0);
 
     // Close all file descriptors except stdin/stdout/stderr
-    for (lpc = getdtablesize() - 1; lpc > STDERR_FILENO; lpc--) {
-        close(lpc);
+#if SUPPORT_PROCFS
+    dir = opendir("/proc/self/fd");
+#else
+    dir = opendir("/dev/fd");
+#endif
+    if (dir == NULL) { /* /proc or /dev/fd not available */
+	/* Iterate over all possible fds, might be slow */
+        for (lpc = getdtablesize() - 1; lpc > STDERR_FILENO; lpc--) {
+            close(lpc);
+        }
+    } else {
+        /* Iterate over fds obtained from /proc or /dev/fd */
+        struct dirent *entry;
+        int dir_fd = dirfd(dir);
+
+        while ((entry = readdir(dir)) != NULL) {
+            lpc = atoi(entry->d_name);
+            if (lpc > STDERR_FILENO && lpc != dir_fd) {
+                close(lpc);
+            }
+        }
+
+        closedir(dir);
     }
 
 #if SUPPORT_CIBSECRETS
-- 
1.8.3.1