|
@@ -17,6 +17,11 @@
|
|
|
#include <sched.h>
|
|
|
#include <signal.h>
|
|
|
|
|
|
+#include <linux/netlink.h>
|
|
|
+#include <linux/types.h>
|
|
|
+#include <stdint.h>
|
|
|
+#include <sys/socket.h>
|
|
|
+
|
|
|
/* All arguments should be above stack, because it grows down */
|
|
|
struct clone_arg {
|
|
|
/*
|
|
@@ -63,24 +68,33 @@ static int clone_parent(jmp_buf * env)
|
|
|
return child;
|
|
|
}
|
|
|
|
|
|
+static uint32_t readint32(char *buf)
|
|
|
+{
|
|
|
+ return *(uint32_t *) buf;
|
|
|
+}
|
|
|
+
|
|
|
+// list of known message types we want to send to bootstrap program
|
|
|
+// These are defined in libcontainer/message_linux.go
|
|
|
+#define INIT_MSG 62000
|
|
|
+#define PID_ATTR 27281
|
|
|
+#define CONSOLE_PATH_ATTR 27282
|
|
|
+
|
|
|
void nsexec()
|
|
|
{
|
|
|
char *namespaces[] = { "ipc", "uts", "net", "pid", "mnt", "user" };
|
|
|
const int num = sizeof(namespaces) / sizeof(char *);
|
|
|
jmp_buf env;
|
|
|
char buf[PATH_MAX], *val;
|
|
|
- int i, tfd, self_tfd, child, len, pipenum, consolefd = -1;
|
|
|
- pid_t pid;
|
|
|
- char *console;
|
|
|
+ int i, tfd, self_tfd, child, n, len, pipenum, consolefd = -1;
|
|
|
+ pid_t pid = 0;
|
|
|
|
|
|
- val = getenv("_LIBCONTAINER_INITPID");
|
|
|
- if (val == NULL)
|
|
|
+ // if we dont have INITTYPE or this is the init process, skip the bootstrap process
|
|
|
+ val = getenv("_LIBCONTAINER_INITTYPE");
|
|
|
+ if (val == NULL || strcmp(val, "standard") == 0) {
|
|
|
return;
|
|
|
-
|
|
|
- pid = atoi(val);
|
|
|
- snprintf(buf, sizeof(buf), "%d", pid);
|
|
|
- if (strcmp(val, buf)) {
|
|
|
- pr_perror("Unable to parse _LIBCONTAINER_INITPID");
|
|
|
+ }
|
|
|
+ if (strcmp(val, "setns") != 0) {
|
|
|
+ pr_perror("Invalid inittype %s", val);
|
|
|
exit(1);
|
|
|
}
|
|
|
|
|
@@ -89,7 +103,6 @@ void nsexec()
|
|
|
pr_perror("Child pipe not found");
|
|
|
exit(1);
|
|
|
}
|
|
|
-
|
|
|
pipenum = atoi(val);
|
|
|
snprintf(buf, sizeof(buf), "%d", pipenum);
|
|
|
if (strcmp(val, buf)) {
|
|
@@ -97,13 +110,56 @@ void nsexec()
|
|
|
exit(1);
|
|
|
}
|
|
|
|
|
|
- console = getenv("_LIBCONTAINER_CONSOLE_PATH");
|
|
|
- if (console != NULL) {
|
|
|
- consolefd = open(console, O_RDWR);
|
|
|
- if (consolefd < 0) {
|
|
|
- pr_perror("Failed to open console %s", console);
|
|
|
- exit(1);
|
|
|
+ char nlbuf[NLMSG_HDRLEN];
|
|
|
+ struct nlmsghdr *nh;
|
|
|
+ if ((n = read(pipenum, nlbuf, NLMSG_HDRLEN)) != NLMSG_HDRLEN) {
|
|
|
+ pr_perror("Failed to read netlink header, got %d", n);
|
|
|
+ exit(1);
|
|
|
+ }
|
|
|
+
|
|
|
+ nh = (struct nlmsghdr *)nlbuf;
|
|
|
+ if (nh->nlmsg_type == NLMSG_ERROR) {
|
|
|
+ pr_perror("Invalid netlink header message");
|
|
|
+ exit(1);
|
|
|
+ }
|
|
|
+ if (nh->nlmsg_type != INIT_MSG) {
|
|
|
+ pr_perror("Unexpected netlink message type %d", nh->nlmsg_type);
|
|
|
+ exit(1);
|
|
|
+ }
|
|
|
+ // read the netlink payload
|
|
|
+ len = NLMSG_PAYLOAD(nh, 0);
|
|
|
+ char data[len];
|
|
|
+ if ((n = read(pipenum, data, len)) != len) {
|
|
|
+ pr_perror("Failed to read netlink payload, got %d", n);
|
|
|
+ exit(1);
|
|
|
+ }
|
|
|
+
|
|
|
+ int start = 0;
|
|
|
+ struct nlattr *attr;
|
|
|
+ while (start < len) {
|
|
|
+ int payload_len;
|
|
|
+ attr = (struct nlattr *)((void *)data + start);
|
|
|
+ start += NLA_HDRLEN;
|
|
|
+ payload_len = attr->nla_len - NLA_HDRLEN;
|
|
|
+ switch (attr->nla_type) {
|
|
|
+ case PID_ATTR:
|
|
|
+ pid = (pid_t) readint32(data + start);
|
|
|
+ break;
|
|
|
+ case CONSOLE_PATH_ATTR:
|
|
|
+ consolefd = open((char *)data + start, O_RDWR);
|
|
|
+ if (consolefd < 0) {
|
|
|
+ pr_perror("Failed to open console %s", (char *)data + start);
|
|
|
+ exit(1);
|
|
|
+ }
|
|
|
+ break;
|
|
|
}
|
|
|
+ start += NLA_ALIGN(payload_len);
|
|
|
+ }
|
|
|
+
|
|
|
+ // required pid to be passed
|
|
|
+ if (pid == 0) {
|
|
|
+ pr_perror("missing pid");
|
|
|
+ exit(1);
|
|
|
}
|
|
|
|
|
|
/* Check that the specified process exists */
|
|
@@ -133,15 +189,13 @@ void nsexec()
|
|
|
}
|
|
|
|
|
|
/* Skip namespaces we're already part of */
|
|
|
- if (fstatat(self_tfd, namespaces[i], &self_st, 0) != -1 &&
|
|
|
- st.st_ino == self_st.st_ino) {
|
|
|
+ if (fstatat(self_tfd, namespaces[i], &self_st, 0) != -1 && st.st_ino == self_st.st_ino) {
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
fd = openat(tfd, namespaces[i], O_RDONLY);
|
|
|
if (fd == -1) {
|
|
|
- pr_perror("Failed to open ns file %s for ns %s", buf,
|
|
|
- namespaces[i]);
|
|
|
+ pr_perror("Failed to open ns file %s for ns %s", buf, namespaces[i]);
|
|
|
exit(1);
|
|
|
}
|
|
|
// Set the namespace.
|