daemonize: fix file descriptor leaks on error paths
authorZdenek Kabelac <zkabelac@redhat.com>
Mon, 17 Nov 2025 09:32:50 +0000 (10:32 +0100)
committerZdenek Kabelac <zkabelac@redhat.com>
Mon, 17 Nov 2025 12:52:34 +0000 (13:52 +0100)
Fix resource leaks in daemonization code across multiple daemons by
properly closing /dev/null file descriptor on all error paths.

Changes across all daemonizing code:
- Skip dup2() when fd already equals target (no-op optimization)
- Close fd on error paths before exit (prevents leak)
- Add Coverity annotations on both error and success paths
- Use consistent == -1 pattern for dup2() error checks
- Remove explicit close(0/1/2) in cmirrord (dup2 handles atomically)

This eliminates resource leak warnings from static analyzers while
maintaining correct daemonization behavior.

daemons/cmirrord/clogd.c
daemons/dmeventd/dmeventd.c
libdaemon/server/daemon-server.c
libdm/dm-tools/dmfilemapd.c

index 9ba86335678fbdcda5590647bc1ebe3807b143ce..142ee136afb0a8a02c722573250ff6de49f462ec 100644 (file)
@@ -228,16 +228,15 @@ static void daemonize(void)
 
        umask(0);
 
-       if (close(0) || close(1) || close(2)) {
-               LOG_ERROR("Failed to close terminal FDs");
+       if (((devnull != STDIN_FILENO) && (dup2(devnull, STDIN_FILENO) == -1)) ||
+           ((devnull != STDOUT_FILENO) && (dup2(devnull, STDOUT_FILENO) == -1)) ||
+           ((devnull != STDERR_FILENO) && (dup2(devnull, STDERR_FILENO) == -1))) {
+               if (devnull > STDERR_FILENO)
+                       (void) close(devnull);
+               /* coverity[leaked_handle] devnull is stdin/stdout/stderr */
                exit(EXIT_FAILURE);
        }
 
-       if ((dup2(devnull, 0) < 0) || /* reopen stdin */
-           (dup2(devnull, 1) < 0) || /* reopen stdout */
-           (dup2(devnull, 2) < 0))   /* reopen stderr */
-               exit(EXIT_FAILURE);
-
        if ((devnull > STDERR_FILENO) && close(devnull)) {
                LOG_ERROR("Failed to close descriptor %d: %s",
                          devnull, strerror(errno));
@@ -245,7 +244,7 @@ static void daemonize(void)
        }
 
        LOG_OPEN("cmirrord", LOG_PID, LOG_DAEMON);
-       /* coverity[leaked_handle] devnull cannot leak here */
+       /* coverity[leaked_handle] devnull is stdin/stdout/stderr */
 }
 
 /*
index e4610c9e4b1dffcf2e9e57acd4a655cdf9c728e4..305e1d18eb8916ce758a9886b503310835e9b9d5 100644 (file)
@@ -2478,17 +2478,21 @@ static void _daemonize(void)
        if ((null_fd = open("/dev/null", O_RDWR)) < 0)
                exit(EXIT_DESC_OPEN_FAILURE);
 
-       if ((dup2(null_fd, STDIN_FILENO) == -1) ||
-           (dup2(null_fd, STDOUT_FILENO) == -1) ||
-           (dup2(null_fd, STDERR_FILENO) == -1))
+       if (((null_fd != STDIN_FILENO) && (dup2(null_fd, STDIN_FILENO) == -1)) ||
+           ((null_fd != STDOUT_FILENO) && (dup2(null_fd, STDOUT_FILENO) == -1)) ||
+           ((null_fd != STDERR_FILENO) && (dup2(null_fd, STDERR_FILENO) == -1))) {
+               if (null_fd > STDERR_FILENO)
+                       (void) close(null_fd);
+               /* coverity[leaked_handle] null_fd is stdin/stdout/stderr */
                exit(EXIT_DESC_OPEN_FAILURE);
+       }
 
        if ((null_fd > STDERR_FILENO) && close(null_fd))
                exit(EXIT_DESC_CLOSE_FAILURE);
 
        setsid();
 
-       /* coverity[leaked_handle] 'null_fd' handle is not leaking */
+       /* coverity[leaked_handle] 'null_fd' is stdin/stdout/stderr */
 }
 
 static int _reinstate_registrations(struct dm_event_fifos *fifos)
index 9f6c92ea56d1594561157a2d5d8813e629639be4..a4e24074bdb23e9ddc5ad355dfe8234df5c16952 100644 (file)
@@ -343,6 +343,7 @@ static void _daemonize(daemon_state s)
        sigemptyset(&my_sigset);
        if (sigprocmask(SIG_SETMASK, &my_sigset, NULL) < 0) {
                fprintf(stderr, "Unable to restore signals.\n");
+               (void) close(fd);
                exit(EXIT_FAILURE);
        }
        signal(SIGTERM, &_exit_handler);
@@ -350,6 +351,7 @@ static void _daemonize(daemon_state s)
        switch (pid = fork()) {
        case -1:
                perror("fork failed:");
+               (void) close(fd);
                exit(EXIT_FAILURE);
 
        case 0:         /* Child */
@@ -380,13 +382,17 @@ static void _daemonize(daemon_state s)
 
        if (chdir("/")) {
                perror("Cannot chdir to /");
+               (void) close(fd);
                exit(1);
        }
 
-       if ((dup2(fd, STDIN_FILENO) == -1) ||
-           (dup2(fd, STDOUT_FILENO) == -1) ||
-           (dup2(fd, STDERR_FILENO) == -1)) {
+       if (((fd != STDIN_FILENO) && (dup2(fd, STDIN_FILENO) == -1)) ||
+           ((fd != STDOUT_FILENO) && (dup2(fd, STDOUT_FILENO) == -1)) ||
+           ((fd != STDERR_FILENO) && (dup2(fd, STDERR_FILENO) == -1))) {
                perror("Error setting terminal FDs to /dev/null");
+               if (fd > STDERR_FILENO)
+                       (void) close(fd);
+               /* coverity[leaked_handle] fd is stdin/stdout/stderr */
                exit(2);
        }
 
@@ -399,7 +405,7 @@ static void _daemonize(daemon_state s)
 
        setsid();
 
-       /* coverity[leaked_handle] 'fd' handle is not leaking */
+       /* coverity[leaked_handle] 'fd' is stdin/stdout/stderr */
 }
 
 response daemon_reply_simple(const char *id, ...)
index 37fbc4e0ec7ed02f5cb32e82887de99002650dec..47d9e1fbe401db9fdf319ba56c41455087c1f92a 100644 (file)
@@ -658,13 +658,13 @@ static int _daemonize(struct filemap_monitor *fm)
                        return 0;
                }
 
-               if ((dup2(fd, STDIN_FILENO) == -1) ||
-                   (dup2(fd, STDOUT_FILENO) == -1) ||
-                   (dup2(fd, STDERR_FILENO) == -1)) {
+               if (((fd != STDIN_FILENO) && (dup2(fd, STDIN_FILENO) == -1)) ||
+                   ((fd != STDOUT_FILENO) && (dup2(fd, STDOUT_FILENO) == -1)) ||
+                   ((fd != STDERR_FILENO) && (dup2(fd, STDERR_FILENO) == -1))) {
                        if (fd > STDERR_FILENO)
                                (void) close(fd);
                        _early_log("Error redirecting stdin/out/err to null.");
-                       /* coverity[leaked_handle] no leak */
+                       /* coverity[leaked_handle] fd is stdin/stdout/stderr */
                        return 0;
                }
                if (fd > STDERR_FILENO)
@@ -675,7 +675,7 @@ static int _daemonize(struct filemap_monitor *fm)
                if (ffd != fm->fd)
                        (void) close(ffd);
 
-       /* coverity[leaked_handle] no leak */
+       /* coverity[leaked_handle] fd is stdin/stdout/stderr */
        return 1;
 }
 
This page took 0.086399 seconds and 5 git commands to generate.