1
0
mirror of https://github.com/systemd/systemd.git synced 2025-02-15 09:57:39 +03:00

Merge pull request #15504 from poettering/cmsg-find-pure

just the recvmsg_safe() stuff from #15457
This commit is contained in:
Lennart Poettering 2020-04-23 17:28:19 +02:00 committed by GitHub
commit 0f4a141744
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 129 additions and 91 deletions

View File

@ -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);
@ -1171,3 +1172,24 @@ int socket_bind_to_ifindex(int fd, int ifindex) {
return socket_bind_to_ifname(fd, ifname);
}
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.
*
* Note that unlike our usual coding style this might modify *msg on failure. */
n = recvmsg(sockfd, msg, flags);
if (n < 0)
return -errno;
if (FLAGS_SET(msg->msg_flags, MSG_CTRUNC)) {
cmsg_close_all(msg);
return -EXFULL; /* a recognizable error code */
}
return n;
}

View File

@ -199,3 +199,5 @@ static inline int setsockopt_int(int fd, int level, int optname, int value) {
int socket_bind_to_ifname(int fd, const char *ifname);
int socket_bind_to_ifindex(int fd, int ifindex);
ssize_t recvmsg_safe(int sockfd, struct msghdr *msg, int flags);

View File

@ -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);
}
}

View File

@ -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 */

View File

@ -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);

View File

@ -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);

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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;

View File

@ -3713,13 +3713,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) {

View File

@ -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 &&

View File

@ -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;

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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);

View File

@ -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;
}