libct/nsenter: refactor ipc funcs for reusability

Modify receive_fd() and send_fd() so they can be more readily reused in
cloned_binary.c. Change receive_fd() to have a single responsibility:
receiving and returning a single file descriptor over a UNIX domain
socket. Make send_fd() useable in precarious execution contexts such as
a clone(CLONE_VFORK|CLONE_VM) "thread" where allocating heap memory or
calling exit() would be dangerous.

Signed-off-by: Cory Snider <csnider@mirantis.com>
This commit is contained in:
Cory Snider
2022-09-15 15:46:24 -04:00
committed by Aleksa Sarai
parent 890dceeebf
commit 8f67178139
3 changed files with 23 additions and 30 deletions
+7 -26
View File
@@ -1,13 +1,12 @@
#define _GNU_SOURCE
#include <fcntl.h>
#include <alloca.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
#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);
}
+7 -2
View File
@@ -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 */
+9 -2
View File
@@ -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)