Exemplo n.º 1
0
static void start_child(int pipenum, jmp_buf *env, int syncpipe[2],
		 struct nsenter_config *config)
{
	int     len;
	int     childpid;
	char    buf[PATH_MAX];
	uint8_t syncbyte = 1;

	// We must fork to actually enter the PID namespace, use CLONE_PARENT
	// so the child can have the right parent, and we don't need to forward
	// the child's exit code or resend its death signal.
	childpid = clone_parent(env, config->cloneflags);
	if (childpid < 0) {
		pr_perror("Unable to fork");
		exit(1);
	}

	// update uid_map and gid_map for the child process if they
	// were provided
	update_process_uidmap(childpid, config->uidmap, config->uidmap_len);
	update_process_gidmap(childpid, config->is_setgroup, config->gidmap, config->gidmap_len);

	// Send the sync signal to the child
	close(syncpipe[0]);
	syncbyte = 1;
	if (write(syncpipe[1], &syncbyte, 1) != 1) {
		pr_perror("failed to write sync byte to child");
		exit(1);
	}

	// Send the child pid back to our parent
	len = snprintf(buf, sizeof(buf), "{ \"pid\" : %d }\n", childpid);
	if ((len < 0) || (write(pipenum, buf, len) != len)) {
		pr_perror("Unable to send a child pid");
		kill(childpid, SIGKILL);
		exit(1);
	}

	exit(0);
}
Exemplo n.º 2
0
void nsexec()
{
	char *namespaces[] = { "ipc", "uts", "net", "pid", "mnt" };
	const int num = sizeof(namespaces) / sizeof(char *);
	jmp_buf env;
	char buf[PATH_MAX], *val;
	int i, tfd, child, len, consolefd = -1;
	pid_t pid;
	char *console;

	val = getenv("_LIBCONTAINER_INITPID");
	if (val == NULL)
		return;

	pid = atoi(val);
	snprintf(buf, sizeof(buf), "%d", pid);
	if (strcmp(val, buf)) {
		pr_perror("Unable to parse _LIBCONTAINER_INITPID");
		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);
		}
	}

	/* Check that the specified process exists */
	snprintf(buf, PATH_MAX - 1, "/proc/%d/ns", pid);
	tfd = open(buf, O_DIRECTORY | O_RDONLY);
	if (tfd == -1) {
		pr_perror("Failed to open \"%s\"", buf);
		exit(1);
	}

	for (i = 0; i < num; i++) {
		struct stat st;
		int fd;

		/* Symlinks on all namespaces exist for dead processes, but they can't be opened */
		if (fstatat(tfd, namespaces[i], &st, AT_SYMLINK_NOFOLLOW) == -1) {
			// Ignore nonexistent namespaces.
			if (errno == ENOENT)
				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]);
			exit(1);
		}
		// Set the namespace.
		if (setns(fd, 0) == -1) {
			pr_perror("Failed to setns for %s", namespaces[i]);
			exit(1);
		}
		close(fd);
	}

	if (setjmp(env) == 1) {
		if (setsid() == -1) {
			pr_perror("setsid failed");
			exit(1);
		}
		if (consolefd != -1) {
			if (ioctl(consolefd, TIOCSCTTY, 0) == -1) {
				pr_perror("ioctl TIOCSCTTY failed");
				exit(1);
			}
			if (dup2(consolefd, STDIN_FILENO) != STDIN_FILENO) {
				pr_perror("Failed to dup 0");
				exit(1);
			}
			if (dup2(consolefd, STDOUT_FILENO) != STDOUT_FILENO) {
				pr_perror("Failed to dup 1");
				exit(1);
			}
			if (dup2(consolefd, STDERR_FILENO) != STDERR_FILENO) {
				pr_perror("Failed to dup 2");
				exit(1);
			}
		}
		// Finish executing, let the Go runtime take over.
		return;
	}

	child = clone_parent(&env);
	if (child < 0) {
		pr_perror("Unable to fork");
		exit(1);
	}

	len = snprintf(buf, sizeof(buf), "{ \"pid\" : %d }\n", child);

	if (write(3, buf, len) != len) {
		pr_perror("Unable to send a child pid");
		kill(child, SIGKILL);
		exit(1);
	}

	exit(0);
}