]> git.ipfire.org Git - thirdparty/lxc.git/commitdiff
af_unix: abstract lxc_abstract_unix_{send,recv}_fd
authorChristian Brauner <christian.brauner@ubuntu.com>
Sun, 4 Jun 2017 05:04:27 +0000 (07:04 +0200)
committerChristian Brauner <christian.brauner@ubuntu.com>
Sun, 4 Jun 2017 06:08:41 +0000 (08:08 +0200)
- 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 <christian.brauner@ubuntu.com>
src/lxc/af_unix.c
src/lxc/af_unix.h
src/lxc/attach.c
src/lxc/commands.c
src/lxc/conf.c
src/lxc/start.c

index ac839943e966d3ce6d6ae0776b0d8afeba97820a..074fabb4405bba1ffdf901fb66e4987a7e77cd9d 100644 (file)
@@ -22,6 +22,8 @@
  */
 #include "config.h"
 
+#include <stdio.h>
+#include <stdlib.h>
 #include <stddef.h>
 #include <string.h>
 #include <unistd.h>
@@ -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;
 }
 
index d25a2118a2f5c6534bf0566cc30cadfd3ffbe1b8..fafa225b5a678a634c1f5e7743bf27fcd28df2fc 100644 (file)
 #ifndef __LXC_AF_UNIX_H
 #define __LXC_AF_UNIX_H
 
+#include <stdio.h>
+
 /* 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);
 
index 9683017603ed9acc4df9223aa556f0cabf39a5f8..eae494067217b942711b6fb6a8713b67dbe938c2 100644 (file)
@@ -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);
index 85e7b0c9d7ec442faed78112dffcffae144d3fda..bb354a50544140e62b78c83b45b8ede7bff09ad1 100644 (file)
@@ -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;
index 2490e5cf6a68ec60a834d50282020dc8d1a8944f..44f15c48295ad5460a15322ddfe7ca2490c4b44d 100644 (file)
@@ -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;
        }
index 6d932038d4454bc70d6771b133d20c24388d2f68..c0a7be5f06ccd4c9702ccd7559b5f768fa921138 100644 (file)
@@ -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;
        }