|
|
|
#define _GNU_SOURCE
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <limits.h>
|
|
|
|
#include <sched.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
|
|
|
|
int enter_mount_namespace(void) {
|
|
|
|
if (geteuid() != 0) {
|
|
|
|
fprintf(stderr, "E Must run as root\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Do some minimal verification to check that oz-daemon is the parent
|
|
|
|
pid_t ppid = getppid();
|
|
|
|
if (checkProcessName(ppid, "oz-daemon") != 0) {
|
|
|
|
fprintf(stderr, "E unable to verify that oz-daemon is parent\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Parse namespace pid from environment
|
|
|
|
char *envv, *envvend;
|
|
|
|
long nspid;
|
|
|
|
envv = getenv("_OZ_NSPID");
|
|
|
|
if (envv == NULL) {
|
|
|
|
fprintf(stderr, "E unable to get namespace pid from environment\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
errno = 0;
|
|
|
|
nspid = strtol(envv, &envvend, 10);
|
|
|
|
if ((errno == ERANGE && (nspid == LONG_MAX || nspid == LONG_MIN))
|
|
|
|
|| (errno != 0 && nspid == 0)) {
|
|
|
|
fprintf(stderr, "E unable to parse namespace pid from environment\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (envvend == envv || nspid < 0) {
|
|
|
|
fprintf(stderr, "E unable to parse namespace pid from environment\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Verify that the target is an instance of oz-init
|
|
|
|
if (checkProcessName(nspid, "oz-init") != 0) {
|
|
|
|
fprintf(stderr, "E unable to verify that oz-init is the target\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
char nspath[PATH_MAX];
|
|
|
|
if (snprintf(nspath, PATH_MAX-1, "/proc/%ld/ns", nspid) < 0) {
|
|
|
|
fprintf(stderr, "E unable to parse namespace path `/proc/%ld/ns`\n", nspid);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
printf("D Opening: %s\n", nspath);
|
|
|
|
|
|
|
|
// Start opening the namespace
|
|
|
|
struct stat st;
|
|
|
|
int tfd, fd;
|
|
|
|
tfd = open(nspath, O_DIRECTORY | O_RDONLY);
|
|
|
|
if (tfd == -1) {
|
|
|
|
fprintf(stderr, "E failed to open child namespace\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
// Symlinks on all namespaces exist for dead processes, but they can't be opened
|
|
|
|
if (fstatat(tfd, "mnt", &st, AT_SYMLINK_NOFOLLOW) == -1) {
|
|
|
|
if (errno == ENOENT) {
|
|
|
|
fprintf(stderr, "E failed to open child namespace\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fd = openat(tfd, "mnt", O_RDONLY);
|
|
|
|
if (fd == -1) {
|
|
|
|
fprintf(stderr, "E failed to open child mount namespace: %s\n", nspath);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
// Set the namespace.
|
|
|
|
if (setns(fd, 0) == -1) {
|
|
|
|
fprintf(stderr, "E failed to setns for: %s\n", nspath);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
close(fd);
|
|
|
|
}
|
|
|
|
|
|
|
|
int checkProcessName(pid_t pid, char *pname) {
|
|
|
|
FILE *fp;
|
|
|
|
char *line = NULL;
|
|
|
|
char pproc[PATH_MAX];
|
|
|
|
char cline[PATH_MAX];
|
|
|
|
size_t len = 0;
|
|
|
|
ssize_t read;
|
|
|
|
|
|
|
|
if (snprintf(cline, PATH_MAX-1, "Name: %s\n", pname) < 0) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (snprintf(pproc, PATH_MAX-1, "/proc/%ld/status", pid) < 0) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
fp = fopen(pproc, "r");
|
|
|
|
if (fp == NULL) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int retval = -1;
|
|
|
|
while (retval == -1 && (read = getline(&line, &len, fp)) != -1) {
|
|
|
|
if (hasPrefix(line, "Name:") >= 0) {
|
|
|
|
retval = strcmp(cline, line);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fclose(fp);
|
|
|
|
if (line) {
|
|
|
|
free(line);
|
|
|
|
}
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
int hasPrefix(const char *str, const char *pre) {
|
|
|
|
size_t lenpre = strlen(pre),
|
|
|
|
lenstr = strlen(str);
|
|
|
|
return lenstr < lenpre ? -1 : strncmp(pre, str, lenpre);
|
|
|
|
}
|