0d8777
From 5a73027642b826793658774df8a0536975120b19 Mon Sep 17 00:00:00 2001
0d8777
From: John Eckersberg <jeckersb@redhat.com>
0d8777
Date: Fri, 11 Oct 2019 08:59:41 -0400
0d8777
Subject: [PATCH] Fix: libcrmservice: try not to spam close() file descriptors
0d8777
0d8777
With large file descriptor limits, action_launch_child can close
0d8777
millions of non-existent file descriptors.
0d8777
0d8777
Instead, try to read open file descriptors from /proc or /dev/fd and
0d8777
close only those which are open.
0d8777
0d8777
See rhbz#1762025
0d8777
---
0d8777
 lib/services/services_linux.c | 26 ++++++++++++++++++++++++--
0d8777
 1 file changed, 24 insertions(+), 2 deletions(-)
0d8777
0d8777
diff --git a/lib/services/services_linux.c b/lib/services/services_linux.c
0d8777
index 90c1f44..464fc5b 100644
0d8777
--- a/lib/services/services_linux.c
0d8777
+++ b/lib/services/services_linux.c
0d8777
@@ -445,6 +445,7 @@ static void
0d8777
 action_launch_child(svc_action_t *op)
0d8777
 {
0d8777
     int lpc;
0d8777
+    DIR *dir;
0d8777
 
0d8777
     /* SIGPIPE is ignored (which is different from signal blocking) by the gnutls library.
0d8777
      * Depending on the libqb version in use, libqb may set SIGPIPE to be ignored as well. 
0d8777
@@ -476,8 +477,29 @@ action_launch_child(svc_action_t *op)
0d8777
     setpgid(0, 0);
0d8777
 
0d8777
     // Close all file descriptors except stdin/stdout/stderr
0d8777
-    for (lpc = getdtablesize() - 1; lpc > STDERR_FILENO; lpc--) {
0d8777
-        close(lpc);
0d8777
+#if SUPPORT_PROCFS
0d8777
+    dir = opendir("/proc/self/fd");
0d8777
+#else
0d8777
+    dir = opendir("/dev/fd");
0d8777
+#endif
0d8777
+    if (dir == NULL) { /* /proc or /dev/fd not available */
0d8777
+	/* Iterate over all possible fds, might be slow */
0d8777
+        for (lpc = getdtablesize() - 1; lpc > STDERR_FILENO; lpc--) {
0d8777
+            close(lpc);
0d8777
+        }
0d8777
+    } else {
0d8777
+        /* Iterate over fds obtained from /proc or /dev/fd */
0d8777
+        struct dirent *entry;
0d8777
+        int dir_fd = dirfd(dir);
0d8777
+
0d8777
+        while ((entry = readdir(dir)) != NULL) {
0d8777
+            lpc = atoi(entry->d_name);
0d8777
+            if (lpc > STDERR_FILENO && lpc != dir_fd) {
0d8777
+                close(lpc);
0d8777
+            }
0d8777
+        }
0d8777
+
0d8777
+        closedir(dir);
0d8777
     }
0d8777
 
0d8777
 #if SUPPORT_CIBSECRETS
0d8777
-- 
0d8777
1.8.3.1
0d8777