summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>2020-04-24 07:45:07 +0200
committerGitHub <noreply@github.com>2020-04-24 07:45:07 +0200
commit11f93798663009d3a83b60ce899c778d9c1f5180 (patch)
tree0fd5e3d69f60033f54075e2ecd4d5a907f250abc
parent41ab8c67ebfbbdc78cda473d81d392da912c17bc (diff)
parent371d72e05b7e2c2b7850cb04d8d4c18be1e60421 (diff)
downloadsystemd-11f93798663009d3a83b60ce899c778d9c1f5180.tar.gz
Merge pull request #15570 from poettering/cmsg-find
CMSG_FIND_DATA() and cmsg_find() work
-rw-r--r--src/basic/socket-util.c13
-rw-r--r--src/basic/socket-util.h8
-rw-r--r--src/coredump/coredump.c12
-rw-r--r--src/import/importd.c10
-rw-r--r--src/journal/journald-stream.c26
-rw-r--r--src/libsystemd-network/sd-dhcp-client.c14
-rw-r--r--src/libsystemd/sd-netlink/netlink-socket.c22
-rw-r--r--src/nspawn/nspawn.c13
-rw-r--r--src/shared/ask-password-api.c7
-rw-r--r--src/udev/udevd.c10
10 files changed, 40 insertions, 95 deletions
diff --git a/src/basic/socket-util.c b/src/basic/socket-util.c
index b797a52180..b502a62a24 100644
--- a/src/basic/socket-util.c
+++ b/src/basic/socket-util.c
@@ -887,7 +887,7 @@ ssize_t receive_one_fd_iov(
.msg_iov = iov,
.msg_iovlen = iovlen,
};
- struct cmsghdr *cmsg, *found = NULL;
+ struct cmsghdr *found;
ssize_t k;
assert(transport_fd >= 0);
@@ -905,16 +905,7 @@ ssize_t receive_one_fd_iov(
if (k < 0)
return k;
- CMSG_FOREACH(cmsg, &mh) {
- if (cmsg->cmsg_level == SOL_SOCKET &&
- cmsg->cmsg_type == SCM_RIGHTS &&
- cmsg->cmsg_len == CMSG_LEN(sizeof(int))) {
- assert(!found);
- found = cmsg;
- break;
- }
- }
-
+ found = cmsg_find(&mh, SOL_SOCKET, SCM_RIGHTS, CMSG_LEN(sizeof(int)));
if (!found) {
cmsg_close_all(&mh);
diff --git a/src/basic/socket-util.h b/src/basic/socket-util.h
index 95643135df..fba4efef81 100644
--- a/src/basic/socket-util.h
+++ b/src/basic/socket-util.h
@@ -158,6 +158,14 @@ int flush_accept(int fd);
struct cmsghdr* cmsg_find(struct msghdr *mh, int level, int type, socklen_t length);
+/* Type-safe, dereferencing version of cmsg_find() */
+#define CMSG_FIND_DATA(mh, level, type, ctype) \
+ ({ \
+ struct cmsghdr *_found; \
+ _found = cmsg_find(mh, level, type, CMSG_LEN(sizeof(ctype))); \
+ (ctype*) (_found ? CMSG_DATA(_found) : NULL); \
+ })
+
/*
* Certain hardware address types (e.g Infiniband) do not fit into sll_addr
* (8 bytes) and run over the structure. This macro returns the correct size that
diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c
index e4266baa62..b88b284584 100644
--- a/src/coredump/coredump.c
+++ b/src/coredump/coredump.c
@@ -921,19 +921,11 @@ static int process_socket(int fd) {
/* The final zero-length datagram carries the file descriptor and tells us
* that we're done. */
if (n == 0) {
- struct cmsghdr *cmsg, *found = NULL;
+ struct cmsghdr *found;
free(iovec.iov_base);
- CMSG_FOREACH(cmsg, &mh) {
- if (cmsg->cmsg_level == SOL_SOCKET &&
- cmsg->cmsg_type == SCM_RIGHTS &&
- cmsg->cmsg_len == CMSG_LEN(sizeof(int))) {
- assert(!found);
- found = cmsg;
- }
- }
-
+ found = cmsg_find(&mh, SOL_SOCKET, SCM_RIGHTS, CMSG_LEN(sizeof(int)));
if (!found) {
cmsg_close_all(&mh);
r = log_error_errno(SYNTHETIC_ERRNO(EBADMSG),
diff --git a/src/import/importd.c b/src/import/importd.c
index 340b12ecd5..417e686bb9 100644
--- a/src/import/importd.c
+++ b/src/import/importd.c
@@ -557,9 +557,8 @@ 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 = NULL;
+ struct ucred *ucred;
Manager *m = userdata;
- struct cmsghdr *cmsg;
char *p, *e;
Transfer *t;
Iterator i;
@@ -574,17 +573,12 @@ static int manager_on_notify(sd_event_source *s, int fd, uint32_t revents, void
cmsg_close_all(&msghdr);
- CMSG_FOREACH(cmsg, &msghdr)
- if (cmsg->cmsg_level == SOL_SOCKET &&
- cmsg->cmsg_type == SCM_CREDENTIALS &&
- cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred)))
- ucred = (struct ucred*) CMSG_DATA(cmsg);
-
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);
if (!ucred || ucred->pid <= 0) {
log_warning("Got notification datagram lacking credential information, ignoring.");
return 0;
diff --git a/src/journal/journald-stream.c b/src/journal/journald-stream.c
index ec6dad62e8..202ac3cda2 100644
--- a/src/journal/journald-stream.c
+++ b/src/journal/journald-stream.c
@@ -491,8 +491,7 @@ static int stdout_stream_scan(StdoutStream *s, bool force_flush) {
static int stdout_stream_process(sd_event_source *es, int fd, uint32_t revents, void *userdata) {
uint8_t buf[CMSG_SPACE(sizeof(struct ucred))];
StdoutStream *s = userdata;
- struct ucred *ucred = NULL;
- struct cmsghdr *cmsg;
+ struct ucred *ucred;
struct iovec iovec;
size_t limit;
ssize_t l;
@@ -541,25 +540,14 @@ static int stdout_stream_process(sd_event_source *es, int fd, uint32_t revents,
goto terminate;
}
- CMSG_FOREACH(cmsg, &msghdr)
- 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;
- }
-
- /* Invalidate the context if the pid of the sender changed.
- * This happens when a forked process inherits stdout / stderr
- * from a parent. In this case getpeercred returns the ucred
- * of the parent, which can be invalid if the parent has exited
- * in the meantime.
+ /* Invalidate the context if the pid of the sender changed. This happens when a forked process
+ * inherits stdout / stderr from a parent. In this case getpeercred returns the ucred of the parent,
+ * which can be invalid if the parent has exited in the meantime.
*/
+ ucred = CMSG_FIND_DATA(&msghdr, SOL_SOCKET, SCM_CREDENTIALS, struct ucred);
if (ucred && ucred->pid != s->ucred.pid) {
- /* force out any previously half-written lines from a
- * different process, before we switch to the new ucred
- * structure for everything we just added */
+ /* force out any previously half-written lines from a different process, before we switch to
+ * the new ucred structure for everything we just added */
r = stdout_stream_scan(s, true);
if (r < 0)
goto terminate;
diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c
index 31416c9f43..0cff6c4f33 100644
--- a/src/libsystemd-network/sd-dhcp-client.c
+++ b/src/libsystemd-network/sd-dhcp-client.c
@@ -1937,15 +1937,11 @@ static int client_receive_message_raw(
if ((size_t) len < sizeof(DHCPPacket))
return 0;
- CMSG_FOREACH(cmsg, &msg)
- if (cmsg->cmsg_level == SOL_PACKET &&
- cmsg->cmsg_type == PACKET_AUXDATA &&
- cmsg->cmsg_len == CMSG_LEN(sizeof(struct tpacket_auxdata))) {
- struct tpacket_auxdata *aux = (struct tpacket_auxdata*)CMSG_DATA(cmsg);
-
- checksum = !(aux->tp_status & TP_STATUS_CSUMNOTREADY);
- break;
- }
+ cmsg = cmsg_find(&msg, SOL_PACKET, PACKET_AUXDATA, CMSG_LEN(sizeof(struct tpacket_auxdata)));
+ if (cmsg) {
+ struct tpacket_auxdata *aux = (struct tpacket_auxdata*) CMSG_DATA(cmsg);
+ checksum = !(aux->tp_status & TP_STATUS_CSUMNOTREADY);
+ }
r = dhcp_packet_verify_headers(packet, len, checksum, client->port);
if (r < 0)
diff --git a/src/libsystemd/sd-netlink/netlink-socket.c b/src/libsystemd/sd-netlink/netlink-socket.c
index 9401c43d05..aa3c6074cb 100644
--- a/src/libsystemd/sd-netlink/netlink-socket.c
+++ b/src/libsystemd/sd-netlink/netlink-socket.c
@@ -238,7 +238,7 @@ int socket_write_message(sd_netlink *nl, sd_netlink_message *m) {
return k;
}
-static int socket_recv_message(int fd, struct iovec *iov, uint32_t *_group, bool peek) {
+static int socket_recv_message(int fd, struct iovec *iov, uint32_t *ret_mcast_group, bool peek) {
union sockaddr_union sender;
uint8_t cmsg_buffer[CMSG_SPACE(sizeof(struct nl_pktinfo))];
struct msghdr msg = {
@@ -249,8 +249,6 @@ static int socket_recv_message(int fd, struct iovec *iov, uint32_t *_group, bool
.msg_control = cmsg_buffer,
.msg_controllen = sizeof(cmsg_buffer),
};
- struct cmsghdr *cmsg;
- uint32_t group = 0;
ssize_t n;
assert(fd >= 0);
@@ -281,20 +279,16 @@ static int socket_recv_message(int fd, struct iovec *iov, uint32_t *_group, bool
return 0;
}
- CMSG_FOREACH(cmsg, &msg) {
- if (cmsg->cmsg_level == SOL_NETLINK &&
- cmsg->cmsg_type == NETLINK_PKTINFO &&
- cmsg->cmsg_len == CMSG_LEN(sizeof(struct nl_pktinfo))) {
- struct nl_pktinfo *pktinfo = (void *)CMSG_DATA(cmsg);
+ if (ret_mcast_group) {
+ struct cmsghdr *cmsg;
- /* multi-cast group */
- group = pktinfo->group;
- }
+ cmsg = cmsg_find(&msg, SOL_NETLINK, NETLINK_PKTINFO, CMSG_LEN(sizeof(struct nl_pktinfo)));
+ if (ret_mcast_group)
+ *ret_mcast_group = ((struct nl_pktinfo*) CMSG_DATA(cmsg))->group;
+ else
+ *ret_mcast_group = 0;
}
- if (_group)
- *_group = group;
-
return (int) n;
}
diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c
index cc2f1521ff..c2148596b7 100644
--- a/src/nspawn/nspawn.c
+++ b/src/nspawn/nspawn.c
@@ -3698,8 +3698,7 @@ static int nspawn_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t r
.msg_control = &control,
.msg_controllen = sizeof(control),
};
- struct cmsghdr *cmsg;
- struct ucred *ucred = NULL;
+ struct ucred *ucred;
ssize_t n;
pid_t inner_child_pid;
_cleanup_strv_free_ char **tags = NULL;
@@ -3721,15 +3720,7 @@ static int nspawn_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t r
cmsg_close_all(&msghdr);
- CMSG_FOREACH(cmsg, &msghdr) {
- if (cmsg->cmsg_level == SOL_SOCKET &&
- cmsg->cmsg_type == SCM_CREDENTIALS &&
- cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))) {
-
- ucred = (struct ucred*) CMSG_DATA(cmsg);
- }
- }
-
+ ucred = CMSG_FIND_DATA(&msghdr, SOL_SOCKET, SCM_CREDENTIALS, struct ucred);
if (!ucred || ucred->pid != inner_child_pid) {
log_debug("Received notify message without valid credentials. Ignoring.");
return 0;
diff --git a/src/shared/ask-password-api.c b/src/shared/ask-password-api.c
index 4cec59087f..e690b0fa6e 100644
--- a/src/shared/ask-password-api.c
+++ b/src/shared/ask-password-api.c
@@ -940,15 +940,12 @@ int ask_password_agent(
continue;
}
- if (msghdr.msg_controllen < CMSG_LEN(sizeof(struct ucred)) ||
- control.cmsghdr.cmsg_level != SOL_SOCKET ||
- control.cmsghdr.cmsg_type != SCM_CREDENTIALS ||
- control.cmsghdr.cmsg_len != CMSG_LEN(sizeof(struct ucred))) {
+ ucred = CMSG_FIND_DATA(&msghdr, SOL_SOCKET, SCM_CREDENTIALS, struct ucred);
+ if (!ucred) {
log_debug("Received message without credentials. Ignoring.");
continue;
}
- ucred = (struct ucred*) CMSG_DATA(&control.cmsghdr);
if (ucred->uid != 0) {
log_debug("Got request from unprivileged user. Ignoring.");
continue;
diff --git a/src/udev/udevd.c b/src/udev/udevd.c
index 4b15159c5b..cfda47f849 100644
--- a/src/udev/udevd.c
+++ b/src/udev/udevd.c
@@ -916,9 +916,8 @@ static int on_worker(sd_event_source *s, int fd, uint32_t revents, void *userdat
.msg_control = &control,
.msg_controllen = sizeof(control),
};
- struct cmsghdr *cmsg;
ssize_t size;
- struct ucred *ucred = NULL;
+ struct ucred *ucred;
struct worker *worker;
size = recvmsg_safe(fd, &msghdr, MSG_DONTWAIT);
@@ -937,12 +936,7 @@ static int on_worker(sd_event_source *s, int fd, uint32_t revents, void *userdat
continue;
}
- CMSG_FOREACH(cmsg, &msghdr)
- if (cmsg->cmsg_level == SOL_SOCKET &&
- cmsg->cmsg_type == SCM_CREDENTIALS &&
- cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred)))
- ucred = (struct ucred*) CMSG_DATA(cmsg);
-
+ ucred = CMSG_FIND_DATA(&msghdr, SOL_SOCKET, SCM_CREDENTIALS, struct ucred);
if (!ucred || ucred->pid <= 0) {
log_warning("Ignoring worker message without valid PID");
continue;