From f09a15d461f8d8e732d5fbb9651ddb7d574b5ebe Mon Sep 17 00:00:00 2001 From: Laurent Bercot Date: Tue, 18 Nov 2025 09:15:18 +0100 Subject: [PATCH] start-stop-daemon.c: fix failure case on --notify fd:4 When the created notified pipe (often on 4) is the same number as the notification fd target, dup2() does not clear the FD_CLOEXEC flag, so the fd gets closed right when exec'ing the daemon, reporting readiness failure. Fix this by explicitly testing for the case and clearing the flag when necessary. Note that this happens because of a call to close_range() right before the test. close_range() is the real problem, it should never be used and this bug is a perfect illustration of why; but getting rid of close_range() is a much more invasive change that I don't want to commit to right now, especially since navi's plan is to eventually deprecate start-stop-daemon. --- src/start-stop-daemon/start-stop-daemon.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/start-stop-daemon/start-stop-daemon.c b/src/start-stop-daemon/start-stop-daemon.c index 34ce08c4..fdcd9032 100644 --- a/src/start-stop-daemon/start-stop-daemon.c +++ b/src/start-stop-daemon/start-stop-daemon.c @@ -1130,13 +1130,25 @@ int main(int argc, char **argv) || rc_yesno(getenv("EINFO_QUIET"))) dup2(stderr_fd, STDERR_FILENO); - cloexec_fds_from(3); + cloexec_fds_from(3); /* FIXME: this is problematic, see right below */ if (notify.type == NOTIFY_FD) { if (close(notify.pipe[0]) == -1) eerrorx("%s: failed to close notify pipe[0]: %s", applet, strerror(errno)); if (dup2(notify.pipe[1], notify.fd) == -1) eerrorx("%s: failed to initialize notify fd: %s", applet, strerror(errno)); + + /* if notify.pipe[1] == notify.fd then the FD_CLOEXEC flag is not cleared by dup2, + leading to failure. The workaround here is to clear it manually, but the + real fix is that we should never close/cloexec fds in bulk like this */ + if (notify.pipe[1] == notify.fd) { + int flags = fcntl(notify.fd, F_GETFD, 0); + if (flags == -1) + eerrorx("%s: failed to get flags for notify fd: %s", applet, strerror(errno)); + if (fcntl(notify.fd, F_SETFD, flags & ~FD_CLOEXEC) == -1) + eerrorx("%s: failed to set flags for notify fd: %s", applet, strerror(errno)); + } + } if (scheduler != NULL) {