aboutgitcodebugslistschat
path: root/pasta.c
diff options
context:
space:
mode:
authorDavid Gibson <david@gibson.dropbear.id.au>2022-09-12 22:24:07 +1000
committerStefano Brivio <sbrivio@redhat.com>2022-09-13 05:31:51 +0200
commiteed17a47fe8291d449fd505d9a6b1f4a72be8d09 (patch)
treeb88d226da816c7059f704b00206fad0788898112 /pasta.c
parentd9f889a55a8bf4dc2e0caf61f35bc15dd6a68e06 (diff)
downloadpasst-eed17a47fe8291d449fd505d9a6b1f4a72be8d09.tar
passt-eed17a47fe8291d449fd505d9a6b1f4a72be8d09.tar.gz
passt-eed17a47fe8291d449fd505d9a6b1f4a72be8d09.tar.bz2
passt-eed17a47fe8291d449fd505d9a6b1f4a72be8d09.tar.lz
passt-eed17a47fe8291d449fd505d9a6b1f4a72be8d09.tar.xz
passt-eed17a47fe8291d449fd505d9a6b1f4a72be8d09.tar.zst
passt-eed17a47fe8291d449fd505d9a6b1f4a72be8d09.zip
Handle userns isolation and dropping root at the same time
passt/pasta can interact with user namespaces in a number of ways: 1) With --netns-only we'll remain in our original user namespace 2) With --userns or a PID option to pasta we'll join either the given user namespace or that of the PID 3) When pasta spawns a shell or command we'll start a new user namespace for the command and then join it 4) With passt we'll create a new user namespace when we sandbox() ourself However (3) and (4) turn out to have essentially the same effect. In both cases we create one new user namespace. The spawned command starts there, and passt/pasta itself will live there from sandbox() onwards. Because of this, we can simplify user namespace handling by moving the userns handling earlier, to the same point we drop root in the original namespace. Extend the drop_user() function to isolate_user() which does both. After switching UID and GID in the original userns, isolate_user() will either join or create the userns we require. When we spawn a command with pasta_start_ns()/pasta_setup_ns() we no longer need to create a userns, because we're already made one. sandbox() likewise no longer needs to create (or join) an userns because we're already in the one we need. We no longer need c->pasta_userns_fd, since the fd is only used locally in isolate_user(). Likewise we can replace c->netns_only with a local in conf(), since it's not used outside there. Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Diffstat (limited to 'pasta.c')
-rw-r--r--pasta.c56
1 files changed, 7 insertions, 49 deletions
diff --git a/pasta.c b/pasta.c
index 7eac8e9..e233762 100644
--- a/pasta.c
+++ b/pasta.c
@@ -23,6 +23,7 @@
#include <libgen.h>
#include <limits.h>
#include <stdlib.h>
+#include <stdbool.h>
#include <stdint.h>
#include <unistd.h>
#include <syslog.h>
@@ -83,16 +84,6 @@ static int pasta_wait_for_ns(void *arg)
int flags = O_RDONLY | O_CLOEXEC;
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, flags)) < 0);
- while (setns(c->pasta_userns_fd, CLONE_NEWUSER) &&
- !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, flags)) < 0);
@@ -112,25 +103,23 @@ static int ns_check(void *arg)
{
struct ctx *c = (struct ctx *)arg;
- if ((!c->netns_only && setns(c->pasta_userns_fd, CLONE_NEWUSER)) ||
- setns(c->pasta_netns_fd, CLONE_NEWNET))
- c->pasta_userns_fd = c->pasta_netns_fd = -1;
+ if (setns(c->pasta_netns_fd, CLONE_NEWNET))
+ c->pasta_netns_fd = -1;
return 0;
}
/**
- * pasta_open_ns() - Open network, user namespaces descriptors
+ * pasta_open_ns() - Open network namespace descriptors
* @c: Execution context
- * @userns: --userns argument, can be an empty string
* @netns: network namespace path
*
* Return: 0 on success, negative error code otherwise
*/
-void pasta_open_ns(struct ctx *c, const char *userns, const char *netns)
+void pasta_open_ns(struct ctx *c, const char *netns)
{
- int ufd = -1, nfd = -1;
+ int nfd = -1;
nfd = open(netns, O_RDONLY | O_CLOEXEC);
if (nfd < 0) {
@@ -138,17 +127,7 @@ void pasta_open_ns(struct ctx *c, const char *userns, const char *netns)
exit(EXIT_FAILURE);
}
- if (!c->netns_only && *userns) {
- ufd = open(userns, O_RDONLY | O_CLOEXEC);
- if (ufd < 0) {
- close(nfd);
- err("Couldn't open user namespace %s", userns);
- exit(EXIT_FAILURE);
- }
- }
-
c->pasta_netns_fd = nfd;
- c->pasta_userns_fd = ufd;
NS_CALL(ns_check, c);
@@ -169,12 +148,9 @@ void pasta_open_ns(struct ctx *c, const char *userns, const char *netns)
/**
* struct pasta_setup_ns_arg - Argument for pasta_setup_ns()
- * @c: Execution context
- * @euid: Effective UID of caller
+ * @argv: Command and arguments to run
*/
struct pasta_setup_ns_arg {
- struct ctx *c;
- int euid;
char **argv;
};
@@ -188,21 +164,6 @@ static int pasta_setup_ns(void *arg)
{
struct pasta_setup_ns_arg *a = (struct pasta_setup_ns_arg *)arg;
- if (!a->c->netns_only) {
- char buf[BUFSIZ];
-
- snprintf(buf, BUFSIZ, "%i %i %i", 0, a->euid, 1);
-
- FWRITE("/proc/self/uid_map", buf,
- "Cannot set uid_map in namespace");
-
- FWRITE("/proc/self/setgroups", "deny",
- "Cannot write to setgroups in namespace");
-
- FWRITE("/proc/self/gid_map", buf,
- "Cannot set gid_map in namespace");
- }
-
FWRITE("/proc/sys/net/ipv4/ping_group_range", "0 0",
"Cannot set ping_group_range, ICMP requests might fail");
@@ -221,8 +182,6 @@ static int pasta_setup_ns(void *arg)
void pasta_start_ns(struct ctx *c, int argc, char *argv[])
{
struct pasta_setup_ns_arg arg = {
- .c = c,
- .euid = geteuid(),
.argv = argv,
};
char *shell = getenv("SHELL") ? getenv("SHELL") : "/bin/sh";
@@ -244,7 +203,6 @@ void pasta_start_ns(struct ctx *c, int argc, char *argv[])
pasta_child_pid = clone(pasta_setup_ns,
ns_fn_stack + sizeof(ns_fn_stack) / 2,
- (c->netns_only ? 0 : CLONE_NEWUSER) |
CLONE_NEWIPC | CLONE_NEWPID | CLONE_NEWNET |
CLONE_NEWUTS,
(void *)&arg);