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: 's avatarChristian Brauner <christian.brauner@ubuntu.com>
parent beda39eb
...@@ -22,6 +22,8 @@ ...@@ -22,6 +22,8 @@
*/ */
#include "config.h" #include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h> #include <stddef.h>
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
...@@ -133,49 +135,66 @@ int lxc_abstract_unix_connect(const char *path) ...@@ -133,49 +135,66 @@ int lxc_abstract_unix_connect(const char *path)
return fd; 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 iovec iov;
struct cmsghdr *cmsg; struct cmsghdr *cmsg = NULL;
char cmsgbuf[CMSG_SPACE(sizeof(int))] = {0};
char buf[1] = {0}; 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_control = cmsgbuf;
msg.msg_controllen = sizeof(cmsgbuf); msg.msg_controllen = cmsgbufsize;
cmsg = CMSG_FIRSTHDR(&msg); cmsg = CMSG_FIRSTHDR(&msg);
cmsg->cmsg_len = CMSG_LEN(sizeof(int));
cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS; cmsg->cmsg_type = SCM_RIGHTS;
val = (int *)(CMSG_DATA(cmsg)); cmsg->cmsg_len = CMSG_LEN(num_sendfds * sizeof(int));
*val = sendfd;
msg.msg_name = NULL; msg.msg_controllen = cmsg->cmsg_len;
msg.msg_namelen = 0;
memcpy(CMSG_DATA(cmsg), sendfds, num_sendfds * sizeof(int));
iov.iov_base = data ? data : buf; iov.iov_base = data ? data : buf;
iov.iov_len = data ? size : sizeof(buf); iov.iov_len = data ? size : sizeof(buf);
msg.msg_iov = &iov; msg.msg_iov = &iov;
msg.msg_iovlen = 1; 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 iovec iov;
struct cmsghdr *cmsg; struct cmsghdr *cmsg = NULL;
int ret, *val;
char cmsgbuf[CMSG_SPACE(sizeof(int))] = {0};
char buf[1] = {0}; 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_control = cmsgbuf;
msg.msg_controllen = sizeof(cmsgbuf); msg.msg_controllen = cmsgbufsize;
iov.iov_base = data ? data : buf; iov.iov_base = data ? data : buf;
iov.iov_len = data ? size : sizeof(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) ...@@ -188,17 +207,14 @@ int lxc_abstract_unix_recv_fd(int fd, int *recvfd, void *data, size_t size)
cmsg = CMSG_FIRSTHDR(&msg); cmsg = CMSG_FIRSTHDR(&msg);
/* if the message is wrong the variable will not be memset(recvfds, -1, num_recvfds * sizeof(int));
* filled and the peer will notified about a problem */ if (cmsg && cmsg->cmsg_len == CMSG_LEN(num_recvfds * sizeof(int)) &&
*recvfd = -1; cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
memcpy(recvfds, CMSG_DATA(cmsg), num_recvfds * sizeof(int));
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;
} }
out: out:
free(cmsgbuf);
return ret; return ret;
} }
......
...@@ -24,13 +24,17 @@ ...@@ -24,13 +24,17 @@
#ifndef __LXC_AF_UNIX_H #ifndef __LXC_AF_UNIX_H
#define __LXC_AF_UNIX_H #define __LXC_AF_UNIX_H
#include <stdio.h>
/* does not enforce \0-termination */ /* does not enforce \0-termination */
extern int lxc_abstract_unix_open(const char *path, int type, int flags); extern int lxc_abstract_unix_open(const char *path, int type, int flags);
extern int lxc_abstract_unix_close(int fd); extern int lxc_abstract_unix_close(int fd);
/* does not enforce \0-termination */ /* does not enforce \0-termination */
extern int lxc_abstract_unix_connect(const char *path); 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_send_fds(int fd, int *sendfds, int num_sendfds,
extern int lxc_abstract_unix_recv_fd(int fd, int *recvfd, void *data, size_t size); 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_send_credential(int fd, void *data, size_t size);
extern int lxc_abstract_unix_rcv_credential(int fd, void *data, size_t size); extern int lxc_abstract_unix_rcv_credential(int fd, void *data, size_t size);
......
...@@ -986,7 +986,7 @@ int lxc_attach(const char* name, const char* lxcpath, lxc_attach_exec_t exec_fun ...@@ -986,7 +986,7 @@ int lxc_attach(const char* name, const char* lxcpath, lxc_attach_exec_t exec_fun
goto on_error; goto on_error;
/* Send child fd of the LSM security module to write to. */ /* 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; saved_errno = errno;
close(labelfd); close(labelfd);
if (ret <= 0) { if (ret <= 0) {
...@@ -1273,7 +1273,7 @@ static int attach_child_main(void* data) ...@@ -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) { if ((options->namespaces & CLONE_NEWNS) && (options->attach_flags & LXC_ATTACH_LSM) && init_ctx->lsm_label) {
int on_exec; int on_exec;
/* Receive fd for LSM security module. */ /* 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) { if (ret <= 0) {
ERROR("Expected to receive file descriptor: %s.", strerror(errno)); ERROR("Expected to receive file descriptor: %s.", strerror(errno));
shutdown(ipc_socket, SHUT_RDWR); shutdown(ipc_socket, SHUT_RDWR);
......
...@@ -171,7 +171,7 @@ static int lxc_cmd_rsp_recv(int sock, struct lxc_cmd_rr *cmd) ...@@ -171,7 +171,7 @@ static int lxc_cmd_rsp_recv(int sock, struct lxc_cmd_rr *cmd)
int ret,rspfd; int ret,rspfd;
struct lxc_cmd_rsp *rsp = &cmd->rsp; 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) { if (ret < 0) {
WARN("Command %s failed to receive response: %s.", WARN("Command %s failed to receive response: %s.",
lxc_cmd_str(cmd->req.cmd), strerror(errno)); 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, ...@@ -756,7 +756,7 @@ static int lxc_cmd_console_callback(int fd, struct lxc_cmd_req *req,
memset(&rsp, 0, sizeof(rsp)); memset(&rsp, 0, sizeof(rsp));
rsp.data = INT_TO_PTR(ttynum); 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."); ERROR("Failed to send tty to client.");
lxc_console_free(handler->conf, fd); lxc_console_free(handler->conf, fd);
goto out_close; goto out_close;
......
...@@ -4093,55 +4093,46 @@ static bool verify_start_hooks(struct lxc_conf *conf) ...@@ -4093,55 +4093,46 @@ static bool verify_start_hooks(struct lxc_conf *conf)
return true; 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); int i;
int *ttyfds;
struct lxc_pty_info *pty_info;
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;
struct lxc_conf *conf = handler->conf; struct lxc_conf *conf = handler->conf;
const struct lxc_tty_info *tty_info = &conf->tty_info; const struct lxc_tty_info *tty_info = &conf->tty_info;
int sock = handler->ttysock[0]; int sock = handler->ttysock[0];
int ret = -1;
size_t num_ttyfds = (2 * conf->tty);
for (i = 0; i < tty_info->nbtty; i++) { ttyfds = malloc(num_ttyfds * sizeof(int));
struct lxc_pty_info *pty_info = &tty_info->pty_info[i]; if (!ttyfds)
ret = send_fd(sock, pty_info->slave); return -1;
if (ret >= 0)
send_fd(sock, pty_info->master); for (i = 0; i < num_ttyfds; i++) {
TRACE("sending pty \"%s\" with master fd %d and slave fd %d to " 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", "parent",
pty_info->name, pty_info->master, pty_info->slave); 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[0]);
close(handler->ttysock[1]); close(handler->ttysock[1]);
return 0; for (i = 0; i < num_ttyfds; i++)
close(ttyfds[i]);
bad: free(ttyfds);
ERROR("Error writing tty fd to parent");
return -1; return ret;
} }
int lxc_setup(struct lxc_handler *handler) int lxc_setup(struct lxc_handler *handler)
...@@ -4260,7 +4251,7 @@ int lxc_setup(struct lxc_handler *handler) ...@@ -4260,7 +4251,7 @@ int lxc_setup(struct lxc_handler *handler)
return -1; return -1;
} }
if (send_ttys_to_parent(handler) < 0) { if (lxc_send_ttys_to_parent(handler) < 0) {
ERROR("failure sending console info to parent"); ERROR("failure sending console info to parent");
return -1; return -1;
} }
......
...@@ -1008,23 +1008,16 @@ static int save_phys_nics(struct lxc_conf *conf) ...@@ -1008,23 +1008,16 @@ static int save_phys_nics(struct lxc_conf *conf)
return 0; 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) { int i;
SYSERROR("Error receiving tty file descriptor from child process."); int *ttyfds;
return -1; struct lxc_pty_info *pty_info;
} int ret = -1;
if (*fd == -1)
return -1;
return 0;
}
static int recv_ttys_from_child(struct lxc_handler *handler)
{
int i, ret;
int sock = handler->ttysock[1]; int sock = handler->ttysock[1];
struct lxc_conf *conf = handler->conf; struct lxc_conf *conf = handler->conf;
struct lxc_tty_info *tty_info = &conf->tty_info; struct lxc_tty_info *tty_info = &conf->tty_info;
size_t num_ttyfds = (2 * conf->tty);
if (!conf->tty) if (!conf->tty)
return 0; return 0;
...@@ -1033,25 +1026,31 @@ static int recv_ttys_from_child(struct lxc_handler *handler) ...@@ -1033,25 +1026,31 @@ static int recv_ttys_from_child(struct lxc_handler *handler)
if (!tty_info->pty_info) if (!tty_info->pty_info)
return -1; return -1;
for (i = 0; i < conf->tty; i++) { ttyfds = malloc(num_ttyfds * sizeof(int));
struct lxc_pty_info *pty_info = &tty_info->pty_info[i]; 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; pty_info->busy = 0;
ret = recv_fd(sock, &pty_info->slave); pty_info->slave = ttyfds[i++];
if (ret >= 0) pty_info->master = ttyfds[i];
recv_fd(sock, &pty_info->master); TRACE("received pty with master fd %d and slave fd %d from "
if (ret < 0) { "parent", pty_info->master, pty_info->slave);
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);
} }
tty_info->nbtty = conf->tty; 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) void resolve_clone_flags(struct lxc_handler *handler)
...@@ -1294,7 +1293,7 @@ static int lxc_spawn(struct lxc_handler *handler) ...@@ -1294,7 +1293,7 @@ static int lxc_spawn(struct lxc_handler *handler)
cgroups_connected = false; cgroups_connected = false;
/* Read tty fds allocated by child. */ /* 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."); ERROR("Failed to receive tty info from child process.");
goto out_delete_net; goto out_delete_net;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment