aboutgitcodebugslistschat
path: root/isolation.c
diff options
context:
space:
mode:
Diffstat (limited to 'isolation.c')
-rw-r--r--isolation.c77
1 files changed, 60 insertions, 17 deletions
diff --git a/isolation.c b/isolation.c
index 41ca888..124dea4 100644
--- a/isolation.c
+++ b/isolation.c
@@ -20,6 +20,7 @@
#include <limits.h>
#include <pwd.h>
#include <sched.h>
+#include <stdbool.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
@@ -59,14 +60,19 @@ void drop_caps(void)
}
/**
- * drop_root() - Switch to given UID and GID
- * @uid: User ID to switch to
- * @gid: Group ID to switch to
+ * isolate_user() - Switch to final UID/GID and move into userns
+ * @uid: User ID to run as (in original userns)
+ * @gid: Group ID to run as (in original userns)
+ * @use_userns: Whether to join or create a userns
+ * @userns: userns path to enter, may be empty
*/
-void drop_root(uid_t uid, gid_t gid)
+void isolate_user(uid_t uid, gid_t gid, bool use_userns, const char *userns)
{
+ char nsmap[BUFSIZ];
+
+ /* First set our UID & GID in the original namespace */
if (setgroups(0, NULL)) {
- /* If we don't start with CAP_SETGID, this will EPERM */
+ /* If we don't have CAP_SETGID, this will EPERM */
if (errno != EPERM) {
err("Can't drop supplementary groups: %s",
strerror(errno));
@@ -74,11 +80,57 @@ void drop_root(uid_t uid, gid_t gid)
}
}
- if (!setgid(gid) && !setuid(uid))
+ if (setgid(gid) != 0) {
+ err("Can't set GID to %u: %s", gid, strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ if (setuid(uid) != 0) {
+ err("Can't set UID to %u: %s", uid, strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ /* If we're told not to use a userns, nothing more to do */
+ if (!use_userns)
+ return;
+
+ /* Otherwise, if given a userns, join it */
+ if (*userns) {
+ int ufd;
+
+ ufd = open(userns, O_RDONLY | O_CLOEXEC);
+ if (ufd < 0) {
+ err("Couldn't open user namespace %s: %s",
+ userns, strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ if (setns(ufd, CLONE_NEWUSER) != 0) {
+ err("Couldn't enter user namespace %s: %s",
+ userns, strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ close(ufd);
+
return;
+ }
- err("Can't change user/group, exiting");
- exit(EXIT_FAILURE);
+ /* Otherwise, create our own userns */
+ if (unshare(CLONE_NEWUSER) != 0) {
+ err("Couldn't create user namespace: %s", strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ /* Configure user and group mappings */
+ snprintf(nsmap, BUFSIZ, "0 %u 1", uid);
+ FWRITE("/proc/self/uid_map", nsmap, "Cannot set uid_map in namespace");
+
+ FWRITE("/proc/self/setgroups", "deny",
+ "Cannot write to setgroups in namespace");
+
+ snprintf(nsmap, BUFSIZ, "0 %u 1", gid);
+ FWRITE("/proc/self/gid_map", nsmap, "Cannot set gid_map in namespace");
}
/**
@@ -90,15 +142,6 @@ int sandbox(struct ctx *c)
{
int flags = CLONE_NEWIPC | CLONE_NEWNS | CLONE_NEWUTS;
- if (!c->netns_only) {
- if (c->pasta_userns_fd == -1)
- flags |= CLONE_NEWUSER;
- else
- setns(c->pasta_userns_fd, CLONE_NEWUSER);
- }
-
- c->pasta_userns_fd = -1;
-
/* If we run in foreground, we have no chance to actually move to a new
* PID namespace. For passt, use CLONE_NEWPID anyway, in case somebody
* ever gets around seccomp profiles -- there's no harm in passing it.