1
0
Fork 0
mirror of https://passt.top/passt synced 2025-06-07 16:35:33 +02:00

pasta: Allow specifying paths and names of namespaces

Based on a patch from Giuseppe Scrivano, this adds the ability to:

- specify paths and names of target namespaces to join, instead of
  a PID, also for user namespaces, with --userns

- request to join or create a network namespace only, without
  entering or creating a user namespace, with --netns-only

- specify the base directory for netns mountpoints, with --nsrun-dir

Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com>
[sbrivio: reworked logic to actually join the given namespaces when
 they're not created, implemented --netns-only and --nsrun-dir,
 updated pasta demo script and man page]
Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
This commit is contained in:
Giuseppe Scrivano 2021-09-29 16:11:06 +02:00 committed by Stefano Brivio
parent ab32838022
commit 9a175cc2ce
12 changed files with 240 additions and 79 deletions

59
passt.c
View file

@ -242,18 +242,34 @@ static void pasta_child_handler(int signal)
/**
* pasta_wait_for_ns() - Busy loop until we can enter the target namespace
* @target_pid: PID of process associated with target namespace
* @arg: Execution context
*
* Return: 0
*/
static int pasta_wait_for_ns(void *target_pid)
static int pasta_wait_for_ns(void *arg)
{
while (ns_enter(*(int *)target_pid));
struct ctx *c = (struct ctx *)arg;
char ns[PATH_MAX];
if (c->netns_only)
goto netns;
snprintf(ns, PATH_MAX, "/proc/%i/ns/user", pasta_child_pid);
do
while ((c->pasta_userns_fd = open(ns, O_RDONLY)) < 0);
while (setns(c->pasta_userns_fd, 0) && !close(c->pasta_userns_fd));
netns:
snprintf(ns, PATH_MAX, "/proc/%i/ns/net", pasta_child_pid);
do
while ((c->pasta_netns_fd = open(ns, O_RDONLY)) < 0);
while (setns(c->pasta_netns_fd, 0) && !close(c->pasta_netns_fd));
return 0;
}
/**
* pasta_start_ns() - Fork shell in new namespace if target PID is not given
* pasta_start_ns() - Fork shell in new namespace if target ns is not given
* @c: Execution context
*/
static void pasta_start_ns(struct ctx *c)
@ -266,34 +282,36 @@ static void pasta_start_ns(struct ctx *c)
if (!c->debug)
c->quiet = 1;
if ((c->pasta_pid = fork()) == -1) {
if ((pasta_child_pid = fork()) == -1) {
perror("fork");
exit(EXIT_FAILURE);
}
if ((pasta_child_pid = c->pasta_pid)) {
NS_CALL(pasta_wait_for_ns, &pasta_child_pid);
if (pasta_child_pid) {
NS_CALL(pasta_wait_for_ns, c);
return;
}
if (unshare(CLONE_NEWNET | CLONE_NEWUSER)) {
if (unshare(CLONE_NEWNET | (c->netns_only ? 0 : CLONE_NEWUSER))) {
perror("unshare");
exit(EXIT_FAILURE);
}
snprintf(buf, BUFSIZ, "%u %u %u", 0, euid, 1);
if (!c->netns_only) {
snprintf(buf, BUFSIZ, "%u %u %u", 0, euid, 1);
fd = open("/proc/self/uid_map", O_WRONLY);
write(fd, buf, strlen(buf));
close(fd);
fd = open("/proc/self/uid_map", O_WRONLY);
write(fd, buf, strlen(buf));
close(fd);
fd = open("/proc/self/setgroups", O_WRONLY);
write(fd, "deny", sizeof("deny"));
close(fd);
fd = open("/proc/self/setgroups", O_WRONLY);
write(fd, "deny", sizeof("deny"));
close(fd);
fd = open("/proc/self/gid_map", O_WRONLY);
write(fd, buf, strlen(buf));
close(fd);
fd = open("/proc/self/gid_map", O_WRONLY);
write(fd, buf, strlen(buf));
close(fd);
}
fd = open("/proc/sys/net/ipv4/ping_group_range", O_WRONLY);
write(fd, "0 0", strlen("0 0"));
@ -352,11 +370,12 @@ int main(int argc, char **argv)
if (!c.debug && (c.stderr || isatty(fileno(stdout))))
openlog(log_name, LOG_PERROR, LOG_DAEMON);
if (c.mode == MODE_PASTA && !c.pasta_pid) {
if (c.mode == MODE_PASTA && !c.pasta_netns_fd) {
char proc_path[PATH_MAX];
pasta_start_ns(&c);
snprintf(proc_path, PATH_MAX, "/proc/%i/ns/net", c.pasta_pid);
snprintf(proc_path, PATH_MAX, "/proc/%i/ns/net",
pasta_child_pid);
readlink(proc_path, pasta_child_ns, PATH_MAX);
}