diff options
author | David Herrmann <dh.herrmann@gmail.com> | 2015-09-22 14:09:54 +0200 |
---|---|---|
committer | David Herrmann <dh.herrmann@gmail.com> | 2015-09-22 14:09:54 +0200 |
commit | d960371482d75711e61896f27ea0d3740ea69fe0 (patch) | |
tree | 6e7ffbd22d6dfb9ed71976e11999abcb93c31e9d | |
parent | 8e112c803cb9b1ab1d564d0e5a7f06af59a2a30a (diff) |
util: introduce {send,receive}_one_fd()
Introduce two new helpers that send/receive a single fd via a unix
transport. Also make nspawn use them instead of hard-coding it.
Based on a patch by Krzesimir Nowak.
-rw-r--r-- | src/basic/util.c | 69 | ||||
-rw-r--r-- | src/basic/util.h | 3 | ||||
-rw-r--r-- | src/nspawn/nspawn-expose-ports.c | 48 | ||||
-rw-r--r-- | src/nspawn/nspawn.c | 25 |
4 files changed, 83 insertions, 62 deletions
diff --git a/src/basic/util.c b/src/basic/util.c index e3b2af8e02..40d9e34f85 100644 --- a/src/basic/util.c +++ b/src/basic/util.c @@ -6775,3 +6775,72 @@ int fgetxattr_malloc(int fd, const char *name, char **value) { return -errno; } } + +int send_one_fd(int transport_fd, int fd) { + union { + struct cmsghdr cmsghdr; + uint8_t buf[CMSG_SPACE(sizeof(int))]; + } control = {}; + struct msghdr mh = { + .msg_control = &control, + .msg_controllen = sizeof(control), + }; + struct cmsghdr *cmsg; + ssize_t k; + + assert(transport_fd >= 0); + assert(fd >= 0); + + cmsg = CMSG_FIRSTHDR(&mh); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + cmsg->cmsg_len = CMSG_LEN(sizeof(int)); + memcpy(CMSG_DATA(cmsg), &fd, sizeof(int)); + + mh.msg_controllen = CMSG_SPACE(sizeof(int)); + k = sendmsg(transport_fd, &mh, MSG_NOSIGNAL); + if (k < 0) + return -errno; + + return 0; +} + +int receive_one_fd(int transport_fd) { + union { + struct cmsghdr cmsghdr; + uint8_t buf[CMSG_SPACE(sizeof(int))]; + } control = {}; + struct msghdr mh = { + .msg_control = &control, + .msg_controllen = sizeof(control), + }; + struct cmsghdr *cmsg; + ssize_t k; + + assert(transport_fd >= 0); + + /* + * Receive a single FD via @transport_fd. We don't care for the + * transport-type, but the caller must assure that no other CMSG types + * than SCM_RIGHTS is enabled. We also retrieve a single FD at most, so + * for packet-based transports, the caller must ensure to send only a + * single FD per packet. + * This is best used in combination with send_one_fd(). + */ + + k = recvmsg(transport_fd, &mh, MSG_NOSIGNAL | MSG_CMSG_CLOEXEC); + if (k < 0) + return -errno; + + cmsg = CMSG_FIRSTHDR(&mh); + if (!cmsg || CMSG_NXTHDR(&mh, cmsg) || + cmsg->cmsg_level != SOL_SOCKET || + cmsg->cmsg_type != SCM_RIGHTS || + cmsg->cmsg_len != CMSG_LEN(sizeof(int)) || + *(const int *)CMSG_DATA(cmsg) < 0) { + cmsg_close_all(&mh); + return -EIO; + } + + return *(const int *)CMSG_DATA(cmsg); +} diff --git a/src/basic/util.h b/src/basic/util.h index 8abaa740b2..905f375263 100644 --- a/src/basic/util.h +++ b/src/basic/util.h @@ -938,3 +938,6 @@ int reset_uid_gid(void); int getxattr_malloc(const char *path, const char *name, char **value, bool allow_symlink); int fgetxattr_malloc(int fd, const char *name, char **value); + +int send_one_fd(int transport_fd, int fd); +int receive_one_fd(int transport_fd); diff --git a/src/nspawn/nspawn-expose-ports.c b/src/nspawn/nspawn-expose-ports.c index 38250b6e02..9e63d88b69 100644 --- a/src/nspawn/nspawn-expose-ports.c +++ b/src/nspawn/nspawn-expose-ports.c @@ -183,17 +183,8 @@ int expose_port_execute(sd_netlink *rtnl, ExposePort *l, union in_addr_union *ex } int expose_port_send_rtnl(int send_fd) { - union { - struct cmsghdr cmsghdr; - uint8_t buf[CMSG_SPACE(sizeof(int))]; - } control = {}; - struct msghdr mh = { - .msg_control = &control, - .msg_controllen = sizeof(control), - }; - struct cmsghdr *cmsg; _cleanup_close_ int fd = -1; - ssize_t k; + int r; assert(send_fd >= 0); @@ -201,19 +192,11 @@ int expose_port_send_rtnl(int send_fd) { if (fd < 0) return log_error_errno(errno, "Failed to allocate container netlink: %m"); - cmsg = CMSG_FIRSTHDR(&mh); - cmsg->cmsg_level = SOL_SOCKET; - cmsg->cmsg_type = SCM_RIGHTS; - cmsg->cmsg_len = CMSG_LEN(sizeof(int)); - memcpy(CMSG_DATA(cmsg), &fd, sizeof(int)); - - mh.msg_controllen = cmsg->cmsg_len; - /* Store away the fd in the socket, so that it stays open as * long as we run the child */ - k = sendmsg(send_fd, &mh, MSG_NOSIGNAL); - if (k < 0) - return log_error_errno(errno, "Failed to send netlink fd: %m"); + r = send_one_fd(send_fd, fd); + if (r < 0) + return log_error_errno(r, "Failed to send netlink fd: %m"); return 0; } @@ -224,33 +207,16 @@ int expose_port_watch_rtnl( sd_netlink_message_handler_t handler, union in_addr_union *exposed, sd_netlink **ret) { - - union { - struct cmsghdr cmsghdr; - uint8_t buf[CMSG_SPACE(sizeof(int))]; - } control = {}; - struct msghdr mh = { - .msg_control = &control, - .msg_controllen = sizeof(control), - }; - struct cmsghdr *cmsg; _cleanup_netlink_unref_ sd_netlink *rtnl = NULL; int fd, r; - ssize_t k; assert(event); assert(recv_fd >= 0); assert(ret); - k = recvmsg(recv_fd, &mh, MSG_NOSIGNAL); - if (k < 0) - return log_error_errno(errno, "Failed to recv netlink fd: %m"); - - cmsg = CMSG_FIRSTHDR(&mh); - assert(cmsg->cmsg_level == SOL_SOCKET); - assert(cmsg->cmsg_type == SCM_RIGHTS); - assert(cmsg->cmsg_len == CMSG_LEN(sizeof(int))); - memcpy(&fd, CMSG_DATA(cmsg), sizeof(int)); + fd = receive_one_fd(recv_fd); + if (fd < 0) + return log_error_errno(fd, "Failed to recv netlink fd: %m"); r = sd_netlink_open_fd(&rtnl, fd); if (r < 0) { diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index 5702df8ab4..955490b752 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -1264,16 +1264,7 @@ static int setup_dev_console(const char *dest, const char *console) { static int setup_kmsg(const char *dest, int kmsg_socket) { const char *from, *to; _cleanup_umask_ mode_t u; - int fd, k; - union { - struct cmsghdr cmsghdr; - uint8_t buf[CMSG_SPACE(sizeof(int))]; - } control = {}; - struct msghdr mh = { - .msg_control = &control, - .msg_controllen = sizeof(control), - }; - struct cmsghdr *cmsg; + int fd, r; assert(kmsg_socket >= 0); @@ -1298,21 +1289,13 @@ static int setup_kmsg(const char *dest, int kmsg_socket) { if (fd < 0) return log_error_errno(errno, "Failed to open fifo: %m"); - cmsg = CMSG_FIRSTHDR(&mh); - cmsg->cmsg_level = SOL_SOCKET; - cmsg->cmsg_type = SCM_RIGHTS; - cmsg->cmsg_len = CMSG_LEN(sizeof(int)); - memcpy(CMSG_DATA(cmsg), &fd, sizeof(int)); - - mh.msg_controllen = cmsg->cmsg_len; - /* Store away the fd in the socket, so that it stays open as * long as we run the child */ - k = sendmsg(kmsg_socket, &mh, MSG_NOSIGNAL); + r = send_one_fd(kmsg_socket, fd); safe_close(fd); - if (k < 0) - return log_error_errno(errno, "Failed to send FIFO fd: %m"); + if (r < 0) + return log_error_errno(r, "Failed to send FIFO fd: %m"); /* And now make the FIFO unavailable as /run/kmsg... */ (void) unlink(from); |