diff --git a/src/basic/audit-util.c b/src/basic/audit-util.c index bf96e080d2..7f86f84fa3 100644 --- a/src/basic/audit-util.c +++ b/src/basic/audit-util.c @@ -99,7 +99,7 @@ static int try_audit_request(int fd) { n = recvmsg_safe(fd, &mh, 0); if (n < 0) - return -errno; + return n; if (n != NLMSG_LENGTH(sizeof(struct nlmsgerr))) return -EIO; diff --git a/src/basic/fd-util.c b/src/basic/fd-util.c index 5d7fc258b2..88b76c51d0 100644 --- a/src/basic/fd-util.c +++ b/src/basic/fd-util.c @@ -568,14 +568,21 @@ int same_fd(int a, int b) { } void cmsg_close_all(struct msghdr *mh) { - struct cmsghdr *cmsg; - assert(mh); - CMSG_FOREACH(cmsg, mh) - if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) + struct cmsghdr *cmsg; + CMSG_FOREACH(cmsg, mh) { + if (cmsg->cmsg_level != SOL_SOCKET) + continue; + + if (cmsg->cmsg_type == SCM_RIGHTS) close_many(CMSG_TYPED_DATA(cmsg, int), (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int)); + else if (cmsg->cmsg_type == SCM_PIDFD) { + assert(cmsg->cmsg_len == CMSG_LEN(sizeof(int))); + safe_close(*CMSG_TYPED_DATA(cmsg, int)); + } + } } bool fdname_is_valid(const char *s) { diff --git a/src/basic/socket-util.c b/src/basic/socket-util.c index c59c6a16a1..e4fb5a280c 100644 --- a/src/basic/socket-util.c +++ b/src/basic/socket-util.c @@ -1447,18 +1447,22 @@ int socket_bind_to_ifindex(int fd, int ifindex) { ssize_t recvmsg_safe(int sockfd, struct msghdr *msg, int flags) { ssize_t n; - /* A wrapper around recvmsg() that checks for MSG_CTRUNC, and turns it into an error, in a reasonably - * safe way, closing any SCM_RIGHTS fds in the error path. + /* A wrapper around recvmsg() that checks for MSG_CTRUNC and MSG_TRUNC, and turns them into an error, + * in a reasonably safe way, closing any received fds in the error path. * * Note that unlike our usual coding style this might modify *msg on failure. */ + assert(sockfd >= 0); + assert(msg); + n = recvmsg(sockfd, msg, flags); if (n < 0) return -errno; - if (FLAGS_SET(msg->msg_flags, MSG_CTRUNC)) { + if (FLAGS_SET(msg->msg_flags, MSG_CTRUNC) || + (!FLAGS_SET(flags, MSG_PEEK) && FLAGS_SET(msg->msg_flags, MSG_TRUNC))) { cmsg_close_all(msg); - return -EXFULL; /* a recognizable error code */ + return FLAGS_SET(msg->msg_flags, MSG_CTRUNC) ? -ECHRNG : -EXFULL; } return n; diff --git a/src/basic/socket-util.h b/src/basic/socket-util.h index 18699a5349..64eb6d7cda 100644 --- a/src/basic/socket-util.h +++ b/src/basic/socket-util.h @@ -329,7 +329,7 @@ struct timespec_large { /* glibc duplicates timespec/timeval on certain 32-bit arches, once in 32-bit and once in 64-bit. * See __convert_scm_timestamps() in glibc source code. Hence, we need additional buffer space for them - * to prevent from recvmsg_safe() returning -EXFULL. */ + * to prevent truncating control msg (recvmsg() MSG_CTRUNC). */ #define CMSG_SPACE_TIMEVAL \ ((sizeof(struct timeval) == sizeof(struct timeval_large)) ? \ CMSG_SPACE(sizeof(struct timeval)) : \ diff --git a/src/core/manager.c b/src/core/manager.c index 2241708297..85ab09be2a 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -2750,13 +2750,17 @@ static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t return 0; } - n = recvmsg_safe(m->notify_fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC|MSG_TRUNC); + n = recvmsg_safe(m->notify_fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC); if (ERRNO_IS_NEG_TRANSIENT(n)) return 0; /* Spurious wakeup, try again */ - if (n == -EXFULL) { + if (n == -ECHRNG) { log_warning_errno(n, "Got message with truncated control data (too many fds sent?), ignoring."); return 0; } + if (n == -EXFULL) { + log_warning_errno(n, "Got message with truncated payload data, ignoring."); + return 0; + } if (n < 0) /* If this is any other, real error, then stop processing this socket. This of course means * we won't take notification messages anymore, but that's still better than busy looping: @@ -2829,11 +2833,6 @@ static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t return 0; } - if ((size_t) n >= sizeof(buf) || (msghdr.msg_flags & MSG_TRUNC)) { - log_warning("Received notify message exceeded maximum size. Ignoring."); - return 0; - } - /* As extra safety check, let's make sure the string we get doesn't contain embedded NUL bytes. * We permit one trailing NUL byte in the message, but don't expect it. */ if (n > 1 && memchr(buf, 0, n-1)) { @@ -4932,20 +4931,22 @@ static int manager_dispatch_handoff_timestamp_fd(sd_event_source *source, int fd assert(source); - n = recvmsg_safe(m->handoff_timestamp_fds[0], &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC|MSG_TRUNC); + n = recvmsg_safe(m->handoff_timestamp_fds[0], &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC); if (ERRNO_IS_NEG_TRANSIENT(n)) return 0; /* Spurious wakeup, try again */ + if (n == -ECHRNG) { + log_warning_errno(n, "Got message with truncated control data (unexpected fds sent?), ignoring."); + return 0; + } if (n == -EXFULL) { - log_warning("Got message with truncated control, ignoring."); + log_warning_errno(n, "Got message with truncated payload data, ignoring."); return 0; } if (n < 0) return log_error_errno(n, "Failed to receive handoff timestamp message: %m"); - if (msghdr.msg_flags & MSG_TRUNC) { - log_warning("Got truncated handoff timestamp message, ignoring."); - return 0; - } + cmsg_close_all(&msghdr); + if (n != sizeof(ts)) { log_warning("Got handoff timestamp message of unexpected size %zi (expected %zu), ignoring.", n, sizeof(ts)); return 0; diff --git a/src/import/importd.c b/src/import/importd.c index 79c2e45276..a0c40cc3d0 100644 --- a/src/import/importd.c +++ b/src/import/importd.c @@ -633,7 +633,7 @@ static Manager *manager_unref(Manager *m) { DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_unref); static int manager_on_notify(sd_event_source *s, int fd, uint32_t revents, void *userdata) { - + Manager *m = ASSERT_PTR(userdata); char buf[NOTIFY_BUFFER_MAX+1]; struct iovec iovec = { .iov_base = buf, @@ -647,33 +647,32 @@ static int manager_on_notify(sd_event_source *s, int fd, uint32_t revents, void .msg_control = &control, .msg_controllen = sizeof(control), }; - struct ucred *ucred; - Manager *m = userdata; - Transfer *t; ssize_t n; - char *p; int r; n = recvmsg_safe(fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC); - if (n < 0) { - if (ERRNO_IS_TRANSIENT(n)) - return 0; - return (int) n; + if (ERRNO_IS_NEG_TRANSIENT(n)) + return 0; + if (n == -ECHRNG) { + log_warning_errno(n, "Got message with truncated control data (unexpected fds sent?), ignoring."); + return 0; } + if (n == -EXFULL) { + log_warning_errno(n, "Got message with truncated payload data, ignoring."); + return 0; + } + if (n < 0) + return (int) n; cmsg_close_all(&msghdr); - if (msghdr.msg_flags & MSG_TRUNC) { - log_warning("Got overly long notification datagram, ignoring."); - return 0; - } - - ucred = CMSG_FIND_DATA(&msghdr, SOL_SOCKET, SCM_CREDENTIALS, struct ucred); + struct ucred *ucred = CMSG_FIND_DATA(&msghdr, SOL_SOCKET, SCM_CREDENTIALS, struct ucred); if (!ucred || ucred->pid <= 0) { log_warning("Got notification datagram lacking credential information, ignoring."); return 0; } + Transfer *t; HASHMAP_FOREACH(t, m->transfers) if (ucred->pid == t->pidref.pid) break; @@ -685,7 +684,7 @@ static int manager_on_notify(sd_event_source *s, int fd, uint32_t revents, void buf[n] = 0; - p = find_line_startswith(buf, "X_IMPORT_PROGRESS="); + char *p = find_line_startswith(buf, "X_IMPORT_PROGRESS="); if (!p) return 0; diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c index 66f09e4945..6198454bd5 100644 --- a/src/journal/journald-server.c +++ b/src/journal/journald-server.c @@ -1549,39 +1549,42 @@ int server_process_datagram( iovec = IOVEC_MAKE(s->buffer, MALLOC_ELEMENTSOF(s->buffer) - 1); /* Leave room for trailing NUL we add later */ n = recvmsg_safe(fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC); - if (n < 0) { - if (ERRNO_IS_TRANSIENT(n)) - return 0; - if (n == -EXFULL) { - log_ratelimit_warning(JOURNAL_LOG_RATELIMIT, - "Got message with truncated control data (too many fds sent?), ignoring."); - return 0; - } - return log_ratelimit_error_errno(n, JOURNAL_LOG_RATELIMIT, "recvmsg() failed: %m"); + if (ERRNO_IS_NEG_TRANSIENT(n)) + return 0; + if (n == -ECHRNG) { + log_ratelimit_warning_errno(n, JOURNAL_LOG_RATELIMIT, + "Got message with truncated control data (too many fds sent?), ignoring."); + return 0; } + if (n == -EXFULL) { + log_ratelimit_warning_errno(n, JOURNAL_LOG_RATELIMIT, "Got message with truncated payload data, ignoring."); + return 0; + } + if (n < 0) + return log_ratelimit_error_errno(n, JOURNAL_LOG_RATELIMIT, "Failed to receive message: %m"); - CMSG_FOREACH(cmsg, &msghdr) - if (cmsg->cmsg_level == SOL_SOCKET && - cmsg->cmsg_type == SCM_CREDENTIALS && + CMSG_FOREACH(cmsg, &msghdr) { + if (cmsg->cmsg_level != SOL_SOCKET) + continue; + + if (cmsg->cmsg_type == SCM_CREDENTIALS && cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))) { assert(!ucred); ucred = CMSG_TYPED_DATA(cmsg, struct ucred); - } else if (cmsg->cmsg_level == SOL_SOCKET && - cmsg->cmsg_type == SCM_SECURITY) { + } else if (cmsg->cmsg_type == SCM_SECURITY) { assert(!label); label = CMSG_TYPED_DATA(cmsg, char); label_len = cmsg->cmsg_len - CMSG_LEN(0); - } else if (cmsg->cmsg_level == SOL_SOCKET && - cmsg->cmsg_type == SCM_TIMESTAMP && + } else if (cmsg->cmsg_type == SCM_TIMESTAMP && cmsg->cmsg_len == CMSG_LEN(sizeof(struct timeval))) { assert(!tv); tv = memcpy(&tv_buf, CMSG_DATA(cmsg), sizeof(struct timeval)); - } else if (cmsg->cmsg_level == SOL_SOCKET && - cmsg->cmsg_type == SCM_RIGHTS) { + } else if (cmsg->cmsg_type == SCM_RIGHTS) { assert(!fds); fds = CMSG_TYPED_DATA(cmsg, int); n_fds = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int); } + } /* And a trailing NUL, just in case */ s->buffer[n] = 0; diff --git a/src/libsystemd/sd-device/device-monitor.c b/src/libsystemd/sd-device/device-monitor.c index 287fb8d9f2..d2892c4d3c 100644 --- a/src/libsystemd/sd-device/device-monitor.c +++ b/src/libsystemd/sd-device/device-monitor.c @@ -600,16 +600,15 @@ _public_ int sd_device_monitor_receive(sd_device_monitor *m, sd_device **ret) { iov = IOVEC_MAKE(message.buf, n); - n = recvmsg(m->sock, &smsg, 0); + n = recvmsg_safe(m->sock, &smsg, 0); if (n < 0) { - if (!ERRNO_IS_TRANSIENT(errno)) - log_monitor_errno(m, errno, "Failed to receive message: %m"); - return -errno; + if (!ERRNO_IS_NEG_TRANSIENT(n)) + log_monitor_errno(m, n, "Failed to receive message: %s", + n == -ECHRNG ? "got truncated control data" : + n == -EXFULL ? "got truncated payload data" : + STRERROR((int) n)); + return n; } - - if (smsg.msg_flags & MSG_TRUNC) - return log_monitor_errno(m, SYNTHETIC_ERRNO(EINVAL), "Received truncated message, ignoring message."); - if (n < 32) return log_monitor_errno(m, SYNTHETIC_ERRNO(EINVAL), "Invalid message length (%zi), ignoring message.", n); diff --git a/src/libsystemd/sd-netlink/netlink-socket.c b/src/libsystemd/sd-netlink/netlink-socket.c index 79729decbc..55a80e0f4c 100644 --- a/src/libsystemd/sd-netlink/netlink-socket.c +++ b/src/libsystemd/sd-netlink/netlink-socket.c @@ -176,14 +176,19 @@ static int socket_recv_message(int fd, void *buf, size_t buf_size, uint32_t *ret assert(fd >= 0); assert(peek || (buf && buf_size > 0)); - n = recvmsg_safe(fd, &msg, MSG_TRUNC | (peek ? MSG_PEEK : 0)); - if (n == -ENOBUFS) - return log_debug_errno(n, "sd-netlink: kernel receive buffer overrun"); - else if (ERRNO_IS_NEG_TRANSIENT(n)) { + n = recvmsg_safe(fd, &msg, peek ? (MSG_PEEK|MSG_TRUNC) : 0); + if (ERRNO_IS_NEG_TRANSIENT(n)) { if (ret_mcast_group) *ret_mcast_group = 0; return 0; - } else if (n < 0) + } + if (n == -ENOBUFS) + return log_debug_errno(n, "sd-netlink: kernel receive buffer overrun"); + if (n == -ECHRNG) + return log_debug_errno(n, "sd-netlink: got truncated control message"); + if (n == -EXFULL) + return log_debug_errno(n, "sd-netlink: got truncated payload message"); + if (n < 0) return (int) n; if (sender.nl.nl_pid != 0) { @@ -202,9 +207,6 @@ static int socket_recv_message(int fd, void *buf, size_t buf_size, uint32_t *ret return 0; } - if (!peek && (size_t) n > buf_size) /* message did not fit in read buffer */ - return -EIO; - if (ret_mcast_group) { struct nl_pktinfo *pi; diff --git a/src/libsystemd/sd-varlink/sd-varlink.c b/src/libsystemd/sd-varlink/sd-varlink.c index 447d5c333c..4665913b1c 100644 --- a/src/libsystemd/sd-varlink/sd-varlink.c +++ b/src/libsystemd/sd-varlink/sd-varlink.c @@ -870,23 +870,25 @@ static int varlink_read(sd_varlink *v) { bool prefer_read = v->prefer_read; if (!prefer_read) { n = recv(v->input_fd, p, rs, MSG_DONTWAIT); - if (n < 0 && errno == ENOTSOCK) + if (n < 0) + n = -errno; + if (n == -ENOTSOCK) prefer_read = v->prefer_read = true; } - if (prefer_read) + if (prefer_read) { n = read(v->input_fd, p, rs); - } - if (n < 0) { - if (errno == EAGAIN) - return 0; - - if (ERRNO_IS_DISCONNECT(errno)) { - v->read_disconnected = true; - return 1; + if (n < 0) + n = -errno; } - - return -errno; } + if (ERRNO_IS_NEG_TRANSIENT(n)) + return 0; + if (ERRNO_IS_NEG_DISCONNECT(n)) { + v->read_disconnected = true; + return 1; + } + if (n < 0) + return n; if (n == 0) { /* EOF */ if (v->allow_fd_passing_input) @@ -897,7 +899,7 @@ static int varlink_read(sd_varlink *v) { } if (v->allow_fd_passing_input) { - struct cmsghdr* cmsg; + struct cmsghdr *cmsg; cmsg = cmsg_find(&mh, SOL_SOCKET, SCM_RIGHTS, (socklen_t) -1); if (cmsg) { diff --git a/src/machine/machine-dbus.c b/src/machine/machine-dbus.c index 366be8fbde..783463896f 100644 --- a/src/machine/machine-dbus.c +++ b/src/machine/machine-dbus.c @@ -215,21 +215,13 @@ int bus_machine_method_get_addresses(sd_bus_message *message, void *userdata, sd case MACHINE_CONTAINER: { _cleanup_close_pair_ int pair[2] = EBADF_PAIR; - _cleanup_free_ char *us = NULL, *them = NULL; _cleanup_close_ int netns_fd = -EBADF; - const char *p; pid_t child; - r = readlink_malloc("/proc/self/ns/net", &us); + r = in_same_namespace(0, m->leader.pid, NAMESPACE_NET); if (r < 0) return r; - - p = procfs_file_alloca(m->leader.pid, "ns/net"); - r = readlink_malloc(p, &them); - if (r < 0) - return r; - - if (streq(us, them)) + if (r > 0) return sd_bus_error_setf(error, BUS_ERROR_NO_PRIVATE_NETWORKING, "Machine %s does not use private networking", m->name); r = pidref_namespace_open(&m->leader, @@ -290,9 +282,9 @@ int bus_machine_method_get_addresses(sd_bus_message *message, void *userdata, sd iov[0] = IOVEC_MAKE(&family, sizeof(family)); iov[1] = IOVEC_MAKE(&in_addr, sizeof(in_addr)); - n = recvmsg(pair[0], &mh, 0); + n = recvmsg_safe(pair[0], &mh, 0); if (n < 0) - return -errno; + return n; if ((size_t) n < sizeof(family)) break; diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index 9cd52e06c0..2694b11f14 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -4485,10 +4485,15 @@ static int nspawn_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t r n = recvmsg_safe(fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC); if (ERRNO_IS_NEG_TRANSIENT(n)) return 0; - else if (n == -EXFULL) { - log_warning("Got message with truncated control data (too many fds sent?), ignoring."); + if (n == -ECHRNG) { + log_warning_errno(n, "Got message with truncated control data (too many fds sent?), ignoring."); return 0; - } else if (n < 0) + } + if (n == -EXFULL) { + log_warning_errno(n, "Got message with truncated payload data, ignoring."); + return 0; + } + if (n < 0) return log_warning_errno(n, "Couldn't read notification socket: %m"); cmsg_close_all(&msghdr); @@ -4499,11 +4504,6 @@ static int nspawn_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t r return 0; } - if ((size_t) n >= sizeof(buf)) { - log_warning("Received notify message exceeded maximum size. Ignoring."); - return 0; - } - buf[n] = 0; tags = strv_split(buf, "\n\r"); if (!tags) diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c index 046f8dd1ce..210a71c9d5 100644 --- a/src/resolve/resolved-manager.c +++ b/src/resolve/resolved-manager.c @@ -867,8 +867,6 @@ int manager_recv(Manager *m, int fd, DnsProtocol protocol, DnsPacket **ret) { if (l <= 0) return l; - assert(!(mh.msg_flags & MSG_TRUNC)); - p->size = (size_t) l; p->family = sa.sa.sa_family; diff --git a/src/resolve/test-resolved-dummy-server.c b/src/resolve/test-resolved-dummy-server.c index 58257d7832..a47fafa2a6 100644 --- a/src/resolve/test-resolved-dummy-server.c +++ b/src/resolve/test-resolved-dummy-server.c @@ -53,8 +53,6 @@ static int server_recv(int fd, DnsPacket **ret) { if (l <= 0) return l; - assert(!(mh.msg_flags & MSG_TRUNC)); - p->size = (size_t) l; p->family = sa.sa.sa_family; diff --git a/src/shared/ask-password-api.c b/src/shared/ask-password-api.c index 7706c3c271..135f19706e 100644 --- a/src/shared/ask-password-api.c +++ b/src/shared/ask-password-api.c @@ -873,10 +873,15 @@ int ask_password_agent( n = recvmsg_safe(socket_fd, &msghdr, 0); if (ERRNO_IS_NEG_TRANSIENT(n)) continue; - else if (n == -EXFULL) { - log_debug("Got message with truncated control data, ignoring."); + if (n == -ECHRNG) { + log_debug_errno(n, "Got message with truncated control data (unexpected fds sent?), ignoring."); continue; - } else if (n < 0) { + } + if (n == -EXFULL) { + log_debug_errno(n, "Got message with truncated payload data, ignoring."); + continue; + } + if (n < 0) { r = (int) n; goto finish; } diff --git a/src/sysupdate/sysupdate-transfer.c b/src/sysupdate/sysupdate-transfer.c index 7ea168961e..cbf3f77f5b 100644 --- a/src/sysupdate/sysupdate-transfer.c +++ b/src/sysupdate/sysupdate-transfer.c @@ -938,18 +938,20 @@ static int helper_on_notify(sd_event_source *s, int fd, uint32_t revents, void * int r; n = recvmsg_safe(fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC); - if (n < 0) { - if (ERRNO_IS_TRANSIENT(n)) - return 0; - return (int) n; - } - - cmsg_close_all(&msghdr); - - if (msghdr.msg_flags & MSG_TRUNC) { - log_warning("Got overly long notification datagram, ignoring."); + if (ERRNO_IS_NEG_TRANSIENT(n)) + return 0; + if (n == -ECHRNG) { + log_warning_errno(n, "Got message with truncated control data (unexpected fds sent?), ignoring."); return 0; } + if (n == -EXFULL) { + log_warning_errno(n, "Got message with truncated payload data, ignoring."); + return 0; + } + if (n < 0) + return (int) n; + + cmsg_close_all(&msghdr); ucred = CMSG_FIND_DATA(&msghdr, SOL_SOCKET, SCM_CREDENTIALS, struct ucred); if (!ucred || ucred->pid <= 0) { diff --git a/src/sysupdate/sysupdated.c b/src/sysupdate/sysupdated.c index 6f15177c94..546f52a96c 100644 --- a/src/sysupdate/sysupdated.c +++ b/src/sysupdate/sysupdated.c @@ -419,7 +419,7 @@ static int job_start(Job *j) { if (IN_SET(j->type, JOB_UPDATE, JOB_VACUUM) && j->target->busy) return log_notice_errno(SYNTHETIC_ERRNO(EBUSY), "Target %s busy, ignoring job.", j->target->name); - + stdout_fd = memfd_new("sysupdate-stdout"); if (stdout_fd < 0) return log_error_errno(stdout_fd, "Failed to create memfd: %m"); @@ -1460,18 +1460,20 @@ static int manager_on_notify(sd_event_source *s, int fd, uint32_t revents, void char *version, *progress, *errno_str, *ready; n = recvmsg_safe(fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC); - if (n < 0) { - if (ERRNO_IS_TRANSIENT(n)) - return 0; - return (int) n; - } - - cmsg_close_all(&msghdr); - - if (msghdr.msg_flags & MSG_TRUNC) { - log_warning("Got overly long notification datagram, ignoring."); + if (ERRNO_IS_NEG_TRANSIENT(n)) + return 0; + if (n == -ECHRNG) { + log_warning_errno(n, "Got message with truncated control data (unexpected fds sent?), ignoring."); return 0; } + if (n == -EXFULL) { + log_warning_errno(n, "Got message with truncated payload data, ignoring."); + return 0; + } + if (n < 0) + return (int) n; + + cmsg_close_all(&msghdr); ucred = CMSG_FIND_DATA(&msghdr, SOL_SOCKET, SCM_CREDENTIALS, struct ucred); if (!ucred || ucred->pid <= 0) { diff --git a/src/timesync/timesyncd-manager.c b/src/timesync/timesyncd-manager.c index faf894fb47..5f16ed2b94 100644 --- a/src/timesync/timesyncd-manager.c +++ b/src/timesync/timesyncd-manager.c @@ -423,15 +423,18 @@ static int manager_receive_response(sd_event_source *source, int fd, uint32_t re } len = recvmsg_safe(fd, &msghdr, MSG_DONTWAIT); - if (len == -EAGAIN) + if (ERRNO_IS_NEG_TRANSIENT(len)) return 0; if (len < 0) { - log_warning_errno(len, "Error receiving message, disconnecting: %m"); + log_warning_errno(len, "Error receiving message, disconnecting: %s", + len == -ECHRNG ? "got truncated control data" : + len == -EXFULL ? "got truncated payload data" : + STRERROR((int) len)); return manager_connect(m); } - /* Too short or too long packet? */ - if (iov.iov_len < sizeof(struct ntp_msg) || (msghdr.msg_flags & MSG_TRUNC)) { + /* Too short packet? */ + if (iov.iov_len < sizeof(struct ntp_msg)) { log_warning("Invalid response from server. Disconnecting."); return manager_connect(m); } diff --git a/src/udev/udev-ctrl.c b/src/udev/udev-ctrl.c index 28716347e7..56da1fb353 100644 --- a/src/udev/udev-ctrl.c +++ b/src/udev/udev-ctrl.c @@ -169,33 +169,40 @@ static int udev_ctrl_connection_event_handler(sd_event_source *s, int fd, uint32 * To avoid the object freed, let's increment the refcount. */ uctrl = udev_ctrl_ref(userdata); - size = next_datagram_size_fd(fd); - if (size < 0) - return log_error_errno(size, "Failed to get size of message: %m"); - if (size == 0) - return 0; /* Client disconnects? */ - size = recvmsg_safe(fd, &smsg, 0); - if (size == -EINTR) + if (ERRNO_IS_NEG_TRANSIENT(size)) return 0; + if (size == -ECHRNG) { + log_warning_errno(size, "Got message with truncated control data (unexpected fds sent?), ignoring."); + return 0; + } + if (size == -EXFULL) { + log_warning_errno(size, "Got message with truncated payload data, ignoring."); + return 0; + } if (size < 0) return log_error_errno(size, "Failed to receive ctrl message: %m"); cmsg_close_all(&smsg); + if (size != sizeof(msg_wire)) { + log_warning("Received message with invalid length, ignoring"); + return 0; + } + cred = CMSG_FIND_DATA(&smsg, SOL_SOCKET, SCM_CREDENTIALS, struct ucred); if (!cred) { - log_error("No sender credentials received, ignoring message"); + log_warning("No sender credentials received, ignoring message"); return 0; } if (cred->uid != 0) { - log_error("Invalid sender uid "UID_FMT", ignoring message", cred->uid); + log_warning("Invalid sender uid "UID_FMT", ignoring message", cred->uid); return 0; } if (msg_wire.magic != UDEV_CTRL_MAGIC) { - log_error("Message magic 0x%08x doesn't match, ignoring message", msg_wire.magic); + log_warning("Message magic 0x%08x doesn't match, ignoring message", msg_wire.magic); return 0; }