diff --git a/libcontainer/nsenter/ipc.c b/libcontainer/nsenter/ipc.c index ac1b7e0db..8e99bb657 100644 --- a/libcontainer/nsenter/ipc.c +++ b/libcontainer/nsenter/ipc.c @@ -1,13 +1,12 @@ #define _GNU_SOURCE -#include +#include #include #include #include -#include #include "ipc.h" #include "log.h" -void receive_fd(int sockfd, int new_fd) +int receive_fd(int sockfd) { int bytes_read; struct msghdr msg = { }; @@ -16,7 +15,6 @@ void receive_fd(int sockfd, int new_fd) char null_byte = '\0'; int ret; int fd_count; - int *fd_payload; iov.iov_base = &null_byte; iov.iov_len = 1; @@ -52,21 +50,13 @@ void receive_fd(int sockfd, int new_fd) if (fd_count != 1) bail("received control message from unix socket %d with too many fds: %d", sockfd, fd_count); - fd_payload = (int *)CMSG_DATA(cmsg); - ret = dup3(*fd_payload, new_fd, O_CLOEXEC); - if (ret < 0) - bail("cannot dup3 fd %d to %d", *fd_payload, new_fd); - + ret = *(int *)CMSG_DATA(cmsg); free(msg.msg_control); - - ret = close(*fd_payload); - if (ret < 0) - bail("cannot close fd %d", *fd_payload); + return ret; } -void send_fd(int sockfd, int fd) +int send_fd(int sockfd, int fd) { - int bytes_written; struct msghdr msg = { }; struct cmsghdr *cmsg; struct iovec iov[1] = { }; @@ -81,11 +71,7 @@ void send_fd(int sockfd, int fd) /* We send only one fd as specified by cmsg->cmsg_len below, even * though msg.msg_controllen might have more space due to alignment. */ msg.msg_controllen = CMSG_SPACE(sizeof(int)); - msg.msg_control = malloc(msg.msg_controllen); - if (msg.msg_control == NULL) { - bail("Can't allocate memory to send fd."); - } - + msg.msg_control = alloca(msg.msg_controllen); memset(msg.msg_control, 0, msg.msg_controllen); cmsg = CMSG_FIRSTHDR(&msg); @@ -94,10 +80,5 @@ void send_fd(int sockfd, int fd) cmsg->cmsg_len = CMSG_LEN(sizeof(int)); memcpy(CMSG_DATA(cmsg), &fd, sizeof(int)); - bytes_written = sendmsg(sockfd, &msg, 0); - - free(msg.msg_control); - - if (bytes_written != 1) - bail("failed to send fd %d via unix socket %d", fd, sockfd); + return sendmsg(sockfd, &msg, 0); } diff --git a/libcontainer/nsenter/ipc.h b/libcontainer/nsenter/ipc.h index 18441d74c..6e5972697 100644 --- a/libcontainer/nsenter/ipc.h +++ b/libcontainer/nsenter/ipc.h @@ -1,7 +1,12 @@ #ifndef NSENTER_IPC_H #define NSENTER_IPC_H -void receive_fd(int sockfd, int new_fd); -void send_fd(int sockfd, int fd); +int receive_fd(int sockfd); + +/* + * send_fd passes the open file descriptor fd to another process via the UNIX + * domain socket sockfd. The return value of the sendmsg(2) call is returned. + */ +int send_fd(int sockfd, int fd); #endif /* NSENTER_IPC_H */ diff --git a/libcontainer/nsenter/nsexec.c b/libcontainer/nsenter/nsexec.c index 844d25117..748791d6b 100644 --- a/libcontainer/nsenter/nsexec.c +++ b/libcontainer/nsenter/nsexec.c @@ -552,7 +552,13 @@ void receive_mountsources(int sockfd) bail("malformed _LIBCONTAINER_MOUNT_FDS env var: fds out of range"); } - receive_fd(sockfd, new_fd); + int recv_fd = receive_fd(sockfd); + if (dup3(recv_fd, new_fd, O_CLOEXEC) < 0) { + bail("cannot dup3 fd %d to %ld", recv_fd, new_fd); + } + if (close(recv_fd) < 0) { + bail("cannot close fd %d", recv_fd); + } } } @@ -595,7 +601,8 @@ void send_mountsources(int sockfd, pid_t child, char *mountsources, size_t mount bail("failed to open mount source %s", mountsources); write_log(DEBUG, "~> sending fd for: %s", mountsources); - send_fd(sockfd, fd); + if (send_fd(sockfd, fd) < 0) + bail("failed to send fd %d via unix socket %d", fd, sockfd); ret = close(fd); if (ret != 0)