diff --git a/src/basic/socket-util.c b/src/basic/socket-util.c index 2d0564e66f..b797a52180 100644 --- a/src/basic/socket-util.c +++ b/src/basic/socket-util.c @@ -901,9 +901,9 @@ ssize_t receive_one_fd_iov( * combination with send_one_fd(). */ - k = recvmsg(transport_fd, &mh, MSG_CMSG_CLOEXEC | flags); + k = recvmsg_safe(transport_fd, &mh, MSG_CMSG_CLOEXEC | flags); if (k < 0) - return (ssize_t) -errno; + return k; CMSG_FOREACH(cmsg, &mh) { if (cmsg->cmsg_level == SOL_SOCKET && @@ -915,12 +915,13 @@ ssize_t receive_one_fd_iov( } } - if (!found) + if (!found) { cmsg_close_all(&mh); - /* If didn't receive an FD or any data, return an error. */ - if (k == 0 && !found) - return -EIO; + /* If didn't receive an FD or any data, return an error. */ + if (k == 0) + return -EIO; + } if (found) *ret_fd = *(int*) CMSG_DATA(found); diff --git a/src/core/manager.c b/src/core/manager.c index 7536a9ca84..43b8a02e48 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -2360,20 +2360,20 @@ static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t return 0; } - n = recvmsg(m->notify_fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC|MSG_TRUNC); - if (n < 0) { - if (IN_SET(errno, EAGAIN, EINTR)) - return 0; /* Spurious wakeup, try again */ - - /* If this is any other, real error, then let's stop processing this socket. This of course means we - * won't take notification messages anymore, but that's still better than busy looping around this: - * being woken up over and over again but being unable to actually read the message off the socket. */ - return log_error_errno(errno, "Failed to receive notification message: %m"); - } + n = recvmsg_safe(m->notify_fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC|MSG_TRUNC); + if (IN_SET(n, -EAGAIN, -EINTR)) + return 0; /* Spurious wakeup, try again */ + if (n < 0) + /* If this is any other, real error, then let's stop processing this socket. This of course + * means we won't take notification messages anymore, but that's still better than busy + * looping around this: being woken up over and over again but being unable to actually read + * the message off the socket. */ + return log_error_errno(n, "Failed to receive notification message: %m"); CMSG_FOREACH(cmsg, &msghdr) { if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) { + assert(!fd_array); fd_array = (int*) CMSG_DATA(cmsg); n_fds = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int); @@ -2381,6 +2381,7 @@ static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t cmsg->cmsg_type == SCM_CREDENTIALS && cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))) { + assert(!ucred); ucred = (struct ucred*) CMSG_DATA(cmsg); } } diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c index ee4268b965..e4266baa62 100644 --- a/src/coredump/coredump.c +++ b/src/coredump/coredump.c @@ -911,10 +911,10 @@ static int process_socket(int fd) { mh.msg_iov = &iovec; - n = recvmsg(fd, &mh, MSG_CMSG_CLOEXEC); + n = recvmsg_safe(fd, &mh, MSG_CMSG_CLOEXEC); if (n < 0) { free(iovec.iov_base); - r = log_error_errno(errno, "Failed to receive datagram: %m"); + r = log_error_errno(n, "Failed to receive datagram: %m"); goto finish; } @@ -935,15 +935,17 @@ static int process_socket(int fd) { } if (!found) { - log_error("Coredump file descriptor missing."); - r = -EBADMSG; + cmsg_close_all(&mh); + r = log_error_errno(SYNTHETIC_ERRNO(EBADMSG), + "Coredump file descriptor missing."); goto finish; } assert(input_fd < 0); input_fd = *(int*) CMSG_DATA(found); break; - } + } else + cmsg_close_all(&mh); /* Add trailing NUL byte, in case these are strings */ ((char*) iovec.iov_base)[n] = 0; @@ -952,8 +954,6 @@ static int process_socket(int fd) { r = iovw_put(&iovw, iovec.iov_base, iovec.iov_len); if (r < 0) goto finish; - - cmsg_close_all(&mh); } /* Make sure we got all data we really need */ diff --git a/src/home/homed-manager.c b/src/home/homed-manager.c index ed2a54615c..5ce7be4fac 100644 --- a/src/home/homed-manager.c +++ b/src/home/homed-manager.c @@ -981,9 +981,9 @@ static ssize_t read_datagram(int fd, struct ucred *ret_sender, void **ret) { .msg_controllen = sizeof(control), }; - m = recvmsg(fd, &mh, MSG_DONTWAIT|MSG_CMSG_CLOEXEC); + m = recvmsg_safe(fd, &mh, MSG_DONTWAIT|MSG_CMSG_CLOEXEC); if (m < 0) - return -errno; + return m; cmsg_close_all(&mh); diff --git a/src/import/importd.c b/src/import/importd.c index 8977ebd835..340b12ecd5 100644 --- a/src/import/importd.c +++ b/src/import/importd.c @@ -566,13 +566,11 @@ static int manager_on_notify(sd_event_source *s, int fd, uint32_t revents, void ssize_t n; int r; - n = recvmsg(fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC); - if (n < 0) { - if (IN_SET(errno, EAGAIN, EINTR)) - return 0; - - return -errno; - } + n = recvmsg_safe(fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC); + if (IN_SET(n, -EAGAIN, -EINTR)) + return 0; + if (n < 0) + return (int) n; cmsg_close_all(&msghdr); diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c index 64cb3279f6..9616e161cc 100644 --- a/src/journal/journald-server.c +++ b/src/journal/journald-server.c @@ -1317,29 +1317,35 @@ int server_process_datagram( iovec = IOVEC_MAKE(s->buffer, s->buffer_size - 1); /* Leave room for trailing NUL we add later */ - n = recvmsg(fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC); - if (n < 0) { - if (IN_SET(errno, EINTR, EAGAIN)) - return 0; - - return log_error_errno(errno, "recvmsg() failed: %m"); + n = recvmsg_safe(fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC); + if (IN_SET(n, -EINTR, -EAGAIN)) + return 0; + if (n == -EXFULL) { + log_warning("Got message with truncated control data (too many fds sent?), ignoring."); + return 0; } + if (n < 0) + return log_error_errno(n, "recvmsg() failed: %m"); CMSG_FOREACH(cmsg, &msghdr) if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_CREDENTIALS && - cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))) + cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))) { + assert(!ucred); ucred = (struct ucred*) CMSG_DATA(cmsg); - else if (cmsg->cmsg_level == SOL_SOCKET && + } else if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_SECURITY) { + assert(!label); label = (char*) CMSG_DATA(cmsg); label_len = cmsg->cmsg_len - CMSG_LEN(0); } else if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SO_TIMESTAMP && - cmsg->cmsg_len == CMSG_LEN(sizeof(struct timeval))) + cmsg->cmsg_len == CMSG_LEN(sizeof(struct timeval))) { + assert(!tv); tv = (struct timeval*) CMSG_DATA(cmsg); - else if (cmsg->cmsg_level == SOL_SOCKET && + } else if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) { + assert(!fds); fds = (int*) CMSG_DATA(cmsg); n_fds = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int); } diff --git a/src/journal/journald-stream.c b/src/journal/journald-stream.c index 609af506a4..ec6dad62e8 100644 --- a/src/journal/journald-stream.c +++ b/src/journal/journald-stream.c @@ -545,6 +545,7 @@ static int stdout_stream_process(sd_event_source *es, int fd, uint32_t revents, if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_CREDENTIALS && cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))) { + assert(!ucred); ucred = (struct ucred *)CMSG_DATA(cmsg); break; } diff --git a/src/libsystemd/sd-bus/bus-socket.c b/src/libsystemd/sd-bus/bus-socket.c index 18d30d010a..f54a5d1976 100644 --- a/src/libsystemd/sd-bus/bus-socket.c +++ b/src/libsystemd/sd-bus/bus-socket.c @@ -557,17 +557,24 @@ static int bus_socket_read_auth(sd_bus *b) { mh.msg_control = &control; mh.msg_controllen = sizeof(control); - k = recvmsg(b->input_fd, &mh, MSG_DONTWAIT|MSG_CMSG_CLOEXEC); - if (k < 0 && errno == ENOTSOCK) { + k = recvmsg_safe(b->input_fd, &mh, MSG_DONTWAIT|MSG_CMSG_CLOEXEC); + if (k == -ENOTSOCK) { b->prefer_readv = true; k = readv(b->input_fd, &iov, 1); + if (k < 0) + k = -errno; } else handle_cmsg = true; } + if (k == -EAGAIN) + return 0; if (k < 0) - return errno == EAGAIN ? 0 : -errno; - if (k == 0) + return (int) k; + if (k == 0) { + if (handle_cmsg) + cmsg_close_all(&mh); /* paranoia, we shouldn't have gotten any fds on EOF */ return -ECONNRESET; + } b->rbuffer_size += k; @@ -1193,17 +1200,24 @@ int bus_socket_read_message(sd_bus *bus) { mh.msg_control = &control; mh.msg_controllen = sizeof(control); - k = recvmsg(bus->input_fd, &mh, MSG_DONTWAIT|MSG_CMSG_CLOEXEC); - if (k < 0 && errno == ENOTSOCK) { + k = recvmsg_safe(bus->input_fd, &mh, MSG_DONTWAIT|MSG_CMSG_CLOEXEC); + if (k == -ENOTSOCK) { bus->prefer_readv = true; k = readv(bus->input_fd, &iov, 1); + if (k < 0) + k = -errno; } else handle_cmsg = true; } + if (k == -EAGAIN) + return 0; if (k < 0) - return errno == EAGAIN ? 0 : -errno; - if (k == 0) + return (int) k; + if (k == 0) { + if (handle_cmsg) + cmsg_close_all(&mh); /* On EOF we shouldn't have gotten an fd, but let's make sure */ return -ECONNRESET; + } bus->rbuffer_size += k; diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index 9888c9e294..b0d2edac95 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -3716,13 +3716,12 @@ static int nspawn_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t r return 0; } - n = recvmsg(fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC); - if (n < 0) { - if (IN_SET(errno, EAGAIN, EINTR)) - return 0; + n = recvmsg_safe(fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC); + if (IN_SET(n, -EAGAIN, -EINTR)) + return 0; + if (n < 0) + return log_warning_errno(n, "Couldn't read notification socket: %m"); - return log_warning_errno(errno, "Couldn't read notification socket: %m"); - } cmsg_close_all(&msghdr); CMSG_FOREACH(cmsg, &msghdr) { diff --git a/src/portable/portable.c b/src/portable/portable.c index 58e4a6670d..49087179c8 100644 --- a/src/portable/portable.c +++ b/src/portable/portable.c @@ -190,9 +190,9 @@ static int recv_item( assert(ret_name); assert(ret_fd); - n = recvmsg(socket_fd, &mh, MSG_CMSG_CLOEXEC); + n = recvmsg_safe(socket_fd, &mh, MSG_CMSG_CLOEXEC); if (n < 0) - return -errno; + return (int) n; CMSG_FOREACH(cmsg, &mh) { if (cmsg->cmsg_level == SOL_SOCKET && diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c index 94590e3038..5055800b04 100644 --- a/src/resolve/resolved-manager.c +++ b/src/resolve/resolved-manager.c @@ -775,17 +775,14 @@ int manager_recv(Manager *m, int fd, DnsProtocol protocol, DnsPacket **ret) { iov = IOVEC_MAKE(DNS_PACKET_DATA(p), p->allocated); - l = recvmsg(fd, &mh, 0); - if (l < 0) { - if (IN_SET(errno, EAGAIN, EINTR)) - return 0; - - return -errno; - } + l = recvmsg_safe(fd, &mh, 0); + if (IN_SET(l, -EAGAIN, -EINTR)) + return 0; + if (l < 0) + return l; if (l == 0) return 0; - assert(!(mh.msg_flags & MSG_CTRUNC)); assert(!(mh.msg_flags & MSG_TRUNC)); p->size = (size_t) l; diff --git a/src/shared/ask-password-api.c b/src/shared/ask-password-api.c index 9b74d909b1..b7b7426058 100644 --- a/src/shared/ask-password-api.c +++ b/src/shared/ask-password-api.c @@ -925,12 +925,11 @@ int ask_password_agent( msghdr.msg_control = &control; msghdr.msg_controllen = sizeof(control); - n = recvmsg(socket_fd, &msghdr, 0); + n = recvmsg_safe(socket_fd, &msghdr, 0); + if (IN_SET(n, -EAGAIN, -EINTR)) + continue; if (n < 0) { - if (IN_SET(errno, EAGAIN, EINTR)) - continue; - - r = -errno; + r = (int) n; goto finish; } diff --git a/src/timesync/timesyncd-manager.c b/src/timesync/timesyncd-manager.c index e18e1e6c04..2980f79b16 100644 --- a/src/timesync/timesyncd-manager.c +++ b/src/timesync/timesyncd-manager.c @@ -438,12 +438,11 @@ static int manager_receive_response(sd_event_source *source, int fd, uint32_t re return manager_connect(m); } - len = recvmsg(fd, &msghdr, MSG_DONTWAIT); + len = recvmsg_safe(fd, &msghdr, MSG_DONTWAIT); + if (len == -EAGAIN) + return 0; if (len < 0) { - if (errno == EAGAIN) - return 0; - - log_warning("Error receiving message. Disconnecting."); + log_warning_errno(len, "Error receiving message, disconnecting: %m"); return manager_connect(m); } diff --git a/src/udev/udev-ctrl.c b/src/udev/udev-ctrl.c index b8c0d83a02..d067279f3e 100644 --- a/src/udev/udev-ctrl.c +++ b/src/udev/udev-ctrl.c @@ -212,13 +212,11 @@ static int udev_ctrl_connection_event_handler(sd_event_source *s, int fd, uint32 if (size == 0) return 0; /* Client disconnects? */ - size = recvmsg(fd, &smsg, 0); - if (size < 0) { - if (errno != EINTR) - return log_error_errno(errno, "Failed to receive ctrl message: %m"); - + size = recvmsg_safe(fd, &smsg, 0); + if (size == -EINTR) return 0; - } + if (size < 0) + return log_error_errno(size, "Failed to receive ctrl message: %m"); cmsg_close_all(&smsg); diff --git a/src/udev/udevd.c b/src/udev/udevd.c index 456bc8c479..4b15159c5b 100644 --- a/src/udev/udevd.c +++ b/src/udev/udevd.c @@ -921,16 +921,18 @@ static int on_worker(sd_event_source *s, int fd, uint32_t revents, void *userdat struct ucred *ucred = NULL; struct worker *worker; - size = recvmsg(fd, &msghdr, MSG_DONTWAIT); - if (size < 0) { - if (errno == EINTR) - continue; - else if (errno == EAGAIN) - /* nothing more to read */ - break; + size = recvmsg_safe(fd, &msghdr, MSG_DONTWAIT); + if (size == -EINTR) + continue; + if (size == -EAGAIN) + /* nothing more to read */ + break; + if (size < 0) + return log_error_errno(size, "Failed to receive message: %m"); - return log_error_errno(errno, "Failed to receive message: %m"); - } else if (size != sizeof(struct worker_message)) { + cmsg_close_all(&msghdr); + + if (size != sizeof(struct worker_message)) { log_warning("Ignoring worker message with invalid size %zi bytes", size); continue; }