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:
commit
0f4a141744
@ -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;
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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 &&
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user