You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

129 lines
3.0 KiB

#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);
}