summaryrefslogtreecommitdiff
path: root/conmon/cmsg.c
diff options
context:
space:
mode:
authorMatthew Heon <matthew.heon@gmail.com>2017-11-01 11:24:59 -0400
committerMatthew Heon <matthew.heon@gmail.com>2017-11-01 11:24:59 -0400
commita031b83a09a8628435317a03f199cdc18b78262f (patch)
treebc017a96769ce6de33745b8b0b1304ccf38e9df0 /conmon/cmsg.c
parent2b74391cd5281f6fdf391ff8ad50fd1490f6bf89 (diff)
downloadpodman-a031b83a09a8628435317a03f199cdc18b78262f.tar.gz
podman-a031b83a09a8628435317a03f199cdc18b78262f.tar.bz2
podman-a031b83a09a8628435317a03f199cdc18b78262f.zip
Initial checkin from CRI-O repo
Signed-off-by: Matthew Heon <matthew.heon@gmail.com>
Diffstat (limited to 'conmon/cmsg.c')
-rw-r--r--conmon/cmsg.c149
1 files changed, 149 insertions, 0 deletions
diff --git a/conmon/cmsg.c b/conmon/cmsg.c
new file mode 100644
index 000000000..c44db2ef1
--- /dev/null
+++ b/conmon/cmsg.c
@@ -0,0 +1,149 @@
+/*
+ * Copyright 2016 SUSE LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* NOTE: This code comes directly from runc/libcontainer/utils/cmsg.c. */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "cmsg.h"
+
+#define error(fmt, ...) \
+ ({ \
+ fprintf(stderr, "nsenter: " fmt ": %m\n", ##__VA_ARGS__); \
+ errno = ECOMM; \
+ goto err; /* return value */ \
+ })
+
+/*
+ * Sends a file descriptor along the sockfd provided. Returns the return
+ * value of sendmsg(2). Any synchronisation and preparation of state
+ * should be done external to this (we expect the other side to be in
+ * recvfd() in the code).
+ */
+ssize_t sendfd(int sockfd, struct file_t file)
+{
+ struct msghdr msg = {0};
+ struct iovec iov[1] = {0};
+ struct cmsghdr *cmsg;
+ int *fdptr;
+
+ union {
+ char buf[CMSG_SPACE(sizeof(file.fd))];
+ struct cmsghdr align;
+ } u;
+
+ /*
+ * We need to send some other data along with the ancillary data,
+ * otherwise the other side won't recieve any data. This is very
+ * well-hidden in the documentation (and only applies to
+ * SOCK_STREAM). See the bottom part of unix(7).
+ */
+ iov[0].iov_base = file.name;
+ iov[0].iov_len = strlen(file.name) + 1;
+
+ msg.msg_name = NULL;
+ msg.msg_namelen = 0;
+ msg.msg_iov = iov;
+ msg.msg_iovlen = 1;
+ msg.msg_control = u.buf;
+ msg.msg_controllen = sizeof(u.buf);
+
+ cmsg = CMSG_FIRSTHDR(&msg);
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(int));
+
+ fdptr = (int *) CMSG_DATA(cmsg);
+ memcpy(fdptr, &file.fd, sizeof(int));
+
+ return sendmsg(sockfd, &msg, 0);
+}
+
+/*
+ * Receives a file descriptor from the sockfd provided. Returns the file
+ * descriptor as sent from sendfd(). It will return the file descriptor
+ * or die (literally) trying. Any synchronisation and preparation of
+ * state should be done external to this (we expect the other side to be
+ * in sendfd() in the code).
+ */
+struct file_t recvfd(int sockfd)
+{
+ struct msghdr msg = {0};
+ struct iovec iov[1] = {0};
+ struct cmsghdr *cmsg;
+ struct file_t file = {0};
+ int *fdptr;
+ int olderrno;
+
+ union {
+ char buf[CMSG_SPACE(sizeof(file.fd))];
+ struct cmsghdr align;
+ } u;
+
+ /* Allocate a buffer. */
+ /* TODO: Make this dynamic with MSG_PEEK. */
+ file.name = malloc(TAG_BUFFER);
+ if (!file.name)
+ error("recvfd: failed to allocate file.tag buffer\n");
+
+ /*
+ * We need to "recieve" the non-ancillary data even though we don't
+ * plan to use it at all. Otherwise, things won't work as expected.
+ * See unix(7) and other well-hidden documentation.
+ */
+ iov[0].iov_base = file.name;
+ iov[0].iov_len = TAG_BUFFER;
+
+ msg.msg_name = NULL;
+ msg.msg_namelen = 0;
+ msg.msg_iov = iov;
+ msg.msg_iovlen = 1;
+ msg.msg_control = u.buf;
+ msg.msg_controllen = sizeof(u.buf);
+
+ ssize_t ret = recvmsg(sockfd, &msg, 0);
+ if (ret < 0)
+ goto err;
+
+ cmsg = CMSG_FIRSTHDR(&msg);
+ if (!cmsg)
+ error("recvfd: got NULL from CMSG_FIRSTHDR");
+ if (cmsg->cmsg_level != SOL_SOCKET)
+ error("recvfd: expected SOL_SOCKET in cmsg: %d", cmsg->cmsg_level);
+ if (cmsg->cmsg_type != SCM_RIGHTS)
+ error("recvfd: expected SCM_RIGHTS in cmsg: %d", cmsg->cmsg_type);
+ if (cmsg->cmsg_len != CMSG_LEN(sizeof(int)))
+ error("recvfd: expected correct CMSG_LEN in cmsg: %lu", cmsg->cmsg_len);
+
+ fdptr = (int *) CMSG_DATA(cmsg);
+ if (!fdptr || *fdptr < 0)
+ error("recvfd: recieved invalid pointer");
+
+ file.fd = *fdptr;
+ return file;
+
+err:
+ olderrno = errno;
+ free(file.name);
+ errno = olderrno;
+ return (struct file_t){0};
+}