From ae467c546bb15f16cad3a83b958c19136cdd7e91 Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Sun, 4 Jun 2017 07:04:27 +0200 Subject: [PATCH] af_unix: abstract lxc_abstract_unix_{send,recv}_fd - Enable lxc_abstract_unix_{send,recv}_fd() to send and receive multiple fds at once. - lxc_abstract_unix_{send,recv}_fd() -> lxc_abstract_unix_{send,recv}_fds() - Send tty fds from child to parent all at once. Signed-off-by: Christian Brauner --- src/lxc/af_unix.c | 74 ++++++++++++++++++++++++++++------------------ src/lxc/af_unix.h | 8 +++-- src/lxc/attach.c | 4 +-- src/lxc/commands.c | 4 +-- src/lxc/conf.c | 65 ++++++++++++++++++---------------------- src/lxc/start.c | 57 ++++++++++++++++++----------------- 6 files changed, 111 insertions(+), 101 deletions(-) diff --git a/src/lxc/af_unix.c b/src/lxc/af_unix.c index ac839943e..074fabb44 100644 --- a/src/lxc/af_unix.c +++ b/src/lxc/af_unix.c @@ -22,6 +22,8 @@ */ #include "config.h" +#include +#include #include #include #include @@ -133,49 +135,66 @@ int lxc_abstract_unix_connect(const char *path) return fd; } -int lxc_abstract_unix_send_fd(int fd, int sendfd, void *data, size_t size) +int lxc_abstract_unix_send_fds(int fd, int *sendfds, int num_sendfds, + void *data, size_t size) { - struct msghdr msg = { 0 }; + int ret; + struct msghdr msg; struct iovec iov; - struct cmsghdr *cmsg; - char cmsgbuf[CMSG_SPACE(sizeof(int))] = {0}; + struct cmsghdr *cmsg = NULL; char buf[1] = {0}; - int *val; + char *cmsgbuf; + size_t cmsgbufsize = CMSG_SPACE(num_sendfds * sizeof(int)); + + memset(&msg, 0, sizeof(msg)); + memset(&iov, 0, sizeof(iov)); + + cmsgbuf = malloc(cmsgbufsize); + if (!cmsgbuf) + return -1; msg.msg_control = cmsgbuf; - msg.msg_controllen = sizeof(cmsgbuf); + msg.msg_controllen = cmsgbufsize; cmsg = CMSG_FIRSTHDR(&msg); - cmsg->cmsg_len = CMSG_LEN(sizeof(int)); cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_RIGHTS; - val = (int *)(CMSG_DATA(cmsg)); - *val = sendfd; + cmsg->cmsg_len = CMSG_LEN(num_sendfds * sizeof(int)); - msg.msg_name = NULL; - msg.msg_namelen = 0; + msg.msg_controllen = cmsg->cmsg_len; + + memcpy(CMSG_DATA(cmsg), sendfds, num_sendfds * sizeof(int)); iov.iov_base = data ? data : buf; iov.iov_len = data ? size : sizeof(buf); msg.msg_iov = &iov; msg.msg_iovlen = 1; - return sendmsg(fd, &msg, MSG_NOSIGNAL); + ret = sendmsg(fd, &msg, MSG_NOSIGNAL); + free(cmsgbuf); + return ret; } -int lxc_abstract_unix_recv_fd(int fd, int *recvfd, void *data, size_t size) +int lxc_abstract_unix_recv_fds(int fd, int *recvfds, int num_recvfds, + void *data, size_t size) { - struct msghdr msg = { 0 }; + int ret; + struct msghdr msg; struct iovec iov; - struct cmsghdr *cmsg; - int ret, *val; - char cmsgbuf[CMSG_SPACE(sizeof(int))] = {0}; + struct cmsghdr *cmsg = NULL; char buf[1] = {0}; + char *cmsgbuf; + size_t cmsgbufsize = CMSG_SPACE(num_recvfds * sizeof(int)); + + memset(&msg, 0, sizeof(msg)); + memset(&iov, 0, sizeof(iov)); + + cmsgbuf = malloc(cmsgbufsize); + if (!cmsgbuf) + return -1; - msg.msg_name = NULL; - msg.msg_namelen = 0; msg.msg_control = cmsgbuf; - msg.msg_controllen = sizeof(cmsgbuf); + msg.msg_controllen = cmsgbufsize; iov.iov_base = data ? data : buf; iov.iov_len = data ? size : sizeof(buf); @@ -188,17 +207,14 @@ int lxc_abstract_unix_recv_fd(int fd, int *recvfd, void *data, size_t size) cmsg = CMSG_FIRSTHDR(&msg); - /* if the message is wrong the variable will not be - * filled and the peer will notified about a problem */ - *recvfd = -1; - - if (cmsg && cmsg->cmsg_len == CMSG_LEN(sizeof(int)) && - cmsg->cmsg_level == SOL_SOCKET && - cmsg->cmsg_type == SCM_RIGHTS) { - val = (int *) CMSG_DATA(cmsg); - *recvfd = *val; + memset(recvfds, -1, num_recvfds * sizeof(int)); + if (cmsg && cmsg->cmsg_len == CMSG_LEN(num_recvfds * sizeof(int)) && + cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) { + memcpy(recvfds, CMSG_DATA(cmsg), num_recvfds * sizeof(int)); } + out: + free(cmsgbuf); return ret; } diff --git a/src/lxc/af_unix.h b/src/lxc/af_unix.h index d25a2118a..fafa225b5 100644 --- a/src/lxc/af_unix.h +++ b/src/lxc/af_unix.h @@ -24,13 +24,17 @@ #ifndef __LXC_AF_UNIX_H #define __LXC_AF_UNIX_H +#include + /* does not enforce \0-termination */ extern int lxc_abstract_unix_open(const char *path, int type, int flags); extern int lxc_abstract_unix_close(int fd); /* does not enforce \0-termination */ extern int lxc_abstract_unix_connect(const char *path); -extern int lxc_abstract_unix_send_fd(int fd, int sendfd, void *data, size_t size); -extern int lxc_abstract_unix_recv_fd(int fd, int *recvfd, void *data, size_t size); +extern int lxc_abstract_unix_send_fds(int fd, int *sendfds, int num_sendfds, + void *data, size_t size); +extern int lxc_abstract_unix_recv_fds(int fd, int *recvfds, int num_recvfds, + void *data, size_t size); extern int lxc_abstract_unix_send_credential(int fd, void *data, size_t size); extern int lxc_abstract_unix_rcv_credential(int fd, void *data, size_t size); diff --git a/src/lxc/attach.c b/src/lxc/attach.c index 968301760..eae494067 100644 --- a/src/lxc/attach.c +++ b/src/lxc/attach.c @@ -986,7 +986,7 @@ int lxc_attach(const char* name, const char* lxcpath, lxc_attach_exec_t exec_fun goto on_error; /* Send child fd of the LSM security module to write to. */ - ret = lxc_abstract_unix_send_fd(ipc_sockets[0], labelfd, NULL, 0); + ret = lxc_abstract_unix_send_fds(ipc_sockets[0], &labelfd, 1, NULL, 0); saved_errno = errno; close(labelfd); if (ret <= 0) { @@ -1273,7 +1273,7 @@ static int attach_child_main(void* data) if ((options->namespaces & CLONE_NEWNS) && (options->attach_flags & LXC_ATTACH_LSM) && init_ctx->lsm_label) { int on_exec; /* Receive fd for LSM security module. */ - ret = lxc_abstract_unix_recv_fd(ipc_socket, &lsm_labelfd, NULL, 0); + ret = lxc_abstract_unix_recv_fds(ipc_socket, &lsm_labelfd, 1, NULL, 0); if (ret <= 0) { ERROR("Expected to receive file descriptor: %s.", strerror(errno)); shutdown(ipc_socket, SHUT_RDWR); diff --git a/src/lxc/commands.c b/src/lxc/commands.c index 85e7b0c9d..bb354a505 100644 --- a/src/lxc/commands.c +++ b/src/lxc/commands.c @@ -171,7 +171,7 @@ static int lxc_cmd_rsp_recv(int sock, struct lxc_cmd_rr *cmd) int ret,rspfd; struct lxc_cmd_rsp *rsp = &cmd->rsp; - ret = lxc_abstract_unix_recv_fd(sock, &rspfd, rsp, sizeof(*rsp)); + ret = lxc_abstract_unix_recv_fds(sock, &rspfd, 1, rsp, sizeof(*rsp)); if (ret < 0) { WARN("Command %s failed to receive response: %s.", lxc_cmd_str(cmd->req.cmd), strerror(errno)); @@ -756,7 +756,7 @@ static int lxc_cmd_console_callback(int fd, struct lxc_cmd_req *req, memset(&rsp, 0, sizeof(rsp)); rsp.data = INT_TO_PTR(ttynum); - if (lxc_abstract_unix_send_fd(fd, masterfd, &rsp, sizeof(rsp)) < 0) { + if (lxc_abstract_unix_send_fds(fd, &masterfd, 1, &rsp, sizeof(rsp)) < 0) { ERROR("Failed to send tty to client."); lxc_console_free(handler->conf, fd); goto out_close; diff --git a/src/lxc/conf.c b/src/lxc/conf.c index 2490e5cf6..44f15c482 100644 --- a/src/lxc/conf.c +++ b/src/lxc/conf.c @@ -4093,55 +4093,46 @@ static bool verify_start_hooks(struct lxc_conf *conf) return true; } -static int send_fd(int sock, int fd) +static int lxc_send_ttys_to_parent(struct lxc_handler *handler) { - int ret = lxc_abstract_unix_send_fd(sock, fd, NULL, 0); - - - if (ret < 0) { - SYSERROR("Error sending tty fd to parent"); - return -1; - } - - return 0; -} - -static int send_ttys_to_parent(struct lxc_handler *handler) -{ - int i, ret; + int i; + int *ttyfds; + struct lxc_pty_info *pty_info; struct lxc_conf *conf = handler->conf; const struct lxc_tty_info *tty_info = &conf->tty_info; int sock = handler->ttysock[0]; + int ret = -1; + size_t num_ttyfds = (2 * conf->tty); - for (i = 0; i < tty_info->nbtty; i++) { - struct lxc_pty_info *pty_info = &tty_info->pty_info[i]; - ret = send_fd(sock, pty_info->slave); - if (ret >= 0) - send_fd(sock, pty_info->master); - TRACE("sending pty \"%s\" with master fd %d and slave fd %d to " + ttyfds = malloc(num_ttyfds * sizeof(int)); + if (!ttyfds) + return -1; + + for (i = 0; i < num_ttyfds; i++) { + pty_info = &tty_info->pty_info[i / 2]; + ttyfds[i++] = pty_info->slave; + ttyfds[i] = pty_info->master; + TRACE("send pty \"%s\" with master fd %d and slave fd %d to " "parent", pty_info->name, pty_info->master, pty_info->slave); - close(pty_info->slave); - pty_info->slave = -1; - close(pty_info->master); - pty_info->master = -1; - if (ret < 0) { - ERROR("failed to send pty \"%s\" with master fd %d and " - "slave fd %d to parent : %s", - pty_info->name, pty_info->master, pty_info->slave, - strerror(errno)); - goto bad; - } } + ret = lxc_abstract_unix_send_fds(sock, ttyfds, num_ttyfds, NULL, 0); + if (ret < 0) + ERROR("failed to send %d ttys to parent: %s", conf->tty, + strerror(errno)); + else + TRACE("sent %d ttys to parent", conf->tty); + close(handler->ttysock[0]); close(handler->ttysock[1]); - return 0; + for (i = 0; i < num_ttyfds; i++) + close(ttyfds[i]); -bad: - ERROR("Error writing tty fd to parent"); - return -1; + free(ttyfds); + + return ret; } int lxc_setup(struct lxc_handler *handler) @@ -4260,7 +4251,7 @@ int lxc_setup(struct lxc_handler *handler) return -1; } - if (send_ttys_to_parent(handler) < 0) { + if (lxc_send_ttys_to_parent(handler) < 0) { ERROR("failure sending console info to parent"); return -1; } diff --git a/src/lxc/start.c b/src/lxc/start.c index 6d932038d..c0a7be5f0 100644 --- a/src/lxc/start.c +++ b/src/lxc/start.c @@ -1008,23 +1008,16 @@ static int save_phys_nics(struct lxc_conf *conf) return 0; } -static int recv_fd(int sock, int *fd) +static int lxc_recv_ttys_from_child(struct lxc_handler *handler) { - if (lxc_abstract_unix_recv_fd(sock, fd, NULL, 0) < 0) { - SYSERROR("Error receiving tty file descriptor from child process."); - return -1; - } - if (*fd == -1) - return -1; - return 0; -} - -static int recv_ttys_from_child(struct lxc_handler *handler) -{ - int i, ret; + int i; + int *ttyfds; + struct lxc_pty_info *pty_info; + int ret = -1; int sock = handler->ttysock[1]; struct lxc_conf *conf = handler->conf; struct lxc_tty_info *tty_info = &conf->tty_info; + size_t num_ttyfds = (2 * conf->tty); if (!conf->tty) return 0; @@ -1033,25 +1026,31 @@ static int recv_ttys_from_child(struct lxc_handler *handler) if (!tty_info->pty_info) return -1; - for (i = 0; i < conf->tty; i++) { - struct lxc_pty_info *pty_info = &tty_info->pty_info[i]; + ttyfds = malloc(num_ttyfds * sizeof(int)); + if (!ttyfds) + return -1; + + ret = lxc_abstract_unix_recv_fds(sock, ttyfds, num_ttyfds, NULL, 0); + for (i = 0; (ret >= 0 && *ttyfds != -1) && (i < num_ttyfds); i++) { + pty_info = &tty_info->pty_info[i / 2]; pty_info->busy = 0; - ret = recv_fd(sock, &pty_info->slave); - if (ret >= 0) - recv_fd(sock, &pty_info->master); - if (ret < 0) { - ERROR("failed to receive pty with master fd %d and " - "slave fd %d from child: %s", - pty_info->master, pty_info->slave, - strerror(errno)); - return -1; - } - TRACE("received pty with master fd %d and slave fd %d from child", - pty_info->master, pty_info->slave); + pty_info->slave = ttyfds[i++]; + pty_info->master = ttyfds[i]; + TRACE("received pty with master fd %d and slave fd %d from " + "parent", pty_info->master, pty_info->slave); } + tty_info->nbtty = conf->tty; - return 0; + free(ttyfds); + + if (ret < 0) + ERROR("failed to receive %d ttys from child: %s", conf->tty, + strerror(errno)); + else + TRACE("received %d ttys from child", conf->tty); + + return ret; } void resolve_clone_flags(struct lxc_handler *handler) @@ -1294,7 +1293,7 @@ static int lxc_spawn(struct lxc_handler *handler) cgroups_connected = false; /* Read tty fds allocated by child. */ - if (recv_ttys_from_child(handler) < 0) { + if (lxc_recv_ttys_from_child(handler) < 0) { ERROR("Failed to receive tty info from child process."); goto out_delete_net; } -- 2.47.3