diff options
Diffstat (limited to 'src/libsystemd/sd-daemon/sd-daemon.c')
-rw-r--r-- | src/libsystemd/sd-daemon/sd-daemon.c | 75 |
1 files changed, 49 insertions, 26 deletions
diff --git a/src/libsystemd/sd-daemon/sd-daemon.c b/src/libsystemd/sd-daemon/sd-daemon.c index 6a60cde..4945d82 100644 --- a/src/libsystemd/sd-daemon/sd-daemon.c +++ b/src/libsystemd/sd-daemon/sd-daemon.c @@ -76,7 +76,7 @@ _public_ int sd_listen_fds(int unset_environment) { goto finish; } - for (int fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd ++) { + for (int fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd++) { r = fd_cloexec(fd, true); if (r < 0) goto finish; @@ -456,6 +456,7 @@ static int pid_notify_with_fds_internal( const char *state, const int *fds, unsigned n_fds) { + SocketAddress address; struct iovec iovec; struct msghdr msghdr = { @@ -464,19 +465,12 @@ static int pid_notify_with_fds_internal( .msg_name = &address.sockaddr, }; _cleanup_close_ int fd = -EBADF; - struct cmsghdr *cmsg = NULL; - const char *e; - bool send_ucred; - ssize_t n; int type, r; - if (!state) - return -EINVAL; - - if (n_fds > 0 && !fds) - return -EINVAL; + assert_return(state, -EINVAL); + assert_return(fds || n_fds == 0, -EINVAL); - e = getenv("NOTIFY_SOCKET"); + const char *e = getenv("NOTIFY_SOCKET"); if (!e) return 0; @@ -530,12 +524,14 @@ static int pid_notify_with_fds_internal( iovec = IOVEC_MAKE_STRING(state); - send_ucred = + bool send_ucred = (pid != 0 && pid != getpid_cached()) || getuid() != geteuid() || getgid() != getegid(); if (n_fds > 0 || send_ucred) { + struct cmsghdr *cmsg; + /* CMSG_SPACE(0) may return value different than zero, which results in miscalculated controllen. */ msghdr.msg_controllen = (n_fds > 0 ? CMSG_SPACE(sizeof(int) * n_fds) : 0) + @@ -569,6 +565,8 @@ static int pid_notify_with_fds_internal( } } + ssize_t n; + do { /* First try with fake ucred data, as requested */ n = sendmsg(fd, &msghdr, MSG_NOSIGNAL); @@ -594,6 +592,19 @@ static int pid_notify_with_fds_internal( } } while (!iovec_increment(msghdr.msg_iov, msghdr.msg_iovlen, n)); + if (address.sockaddr.sa.sa_family == AF_VSOCK && IN_SET(type, SOCK_STREAM, SOCK_SEQPACKET)) { + /* For AF_VSOCK, we need to close the socket to signal the end of the message. */ + if (shutdown(fd, SHUT_WR) < 0) + return log_debug_errno(errno, "Failed to shutdown notify socket: %m"); + + char c; + n = recv(fd, &c, sizeof(c), MSG_NOSIGNAL); + if (n < 0) + return log_debug_errno(errno, "Failed to wait for EOF on notify socket: %m"); + if (n > 0) + return log_debug_errno(SYNTHETIC_ERRNO(EPROTO), "Unexpectedly received data on notify socket."); + } + return 1; } @@ -650,7 +661,7 @@ _public_ int sd_notify(int unset_environment, const char *state) { _public_ int sd_pid_notifyf(pid_t pid, int unset_environment, const char *format, ...) { _cleanup_free_ char *p = NULL; - int r; + int r = 0, k; if (format) { va_list ap; @@ -659,16 +670,20 @@ _public_ int sd_pid_notifyf(pid_t pid, int unset_environment, const char *format r = vasprintf(&p, format, ap); va_end(ap); - if (r < 0 || !p) - return -ENOMEM; + if (r < 0 || !p) { + r = -ENOMEM; + p = mfree(p); /* If vasprintf failed, do not use the string, + * even if something was returned. */ + } } - return sd_pid_notify(pid, unset_environment, p); + k = sd_pid_notify(pid, unset_environment, p); + return r < 0 ? r : k; } _public_ int sd_notifyf(int unset_environment, const char *format, ...) { _cleanup_free_ char *p = NULL; - int r; + int r = 0, k; if (format) { va_list ap; @@ -677,11 +692,15 @@ _public_ int sd_notifyf(int unset_environment, const char *format, ...) { r = vasprintf(&p, format, ap); va_end(ap); - if (r < 0 || !p) - return -ENOMEM; + if (r < 0 || !p) { + r = -ENOMEM; + p = mfree(p); /* If vasprintf failed, do not use the string, + * even if something was returned. */ + } } - return sd_pid_notify(0, unset_environment, p); + k = sd_pid_notify(0, unset_environment, p); + return r < 0 ? r : k; } _public_ int sd_pid_notifyf_with_fds( @@ -691,27 +710,31 @@ _public_ int sd_pid_notifyf_with_fds( const char *format, ...) { _cleanup_free_ char *p = NULL; - int r; + int r = 0, k; /* Paranoia check: we traditionally used 'unsigned' as array size, but we nowadays more correctly use * 'size_t'. sd_pid_notifyf_with_fds() and sd_pid_notify_with_fds() are from different eras, hence * differ in this. Let's catch resulting incompatibilites early, even though they are pretty much * theoretic only */ if (n_fds > UINT_MAX) - return -E2BIG; + r = -E2BIG; - if (format) { + else if (format) { va_list ap; va_start(ap, format); r = vasprintf(&p, format, ap); va_end(ap); - if (r < 0 || !p) - return -ENOMEM; + if (r < 0 || !p) { + r = -ENOMEM; + p = mfree(p); /* If vasprintf failed, do not use the string, + * even if something was returned. */ + } } - return sd_pid_notify_with_fds(pid, unset_environment, p, fds, n_fds); + k = sd_pid_notify_with_fds(pid, unset_environment, p, fds, n_fds); + return r < 0 ? r : k; } _public_ int sd_booted(void) { |