summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys-utils/nsenter.c46
1 files changed, 30 insertions, 16 deletions
diff --git a/sys-utils/nsenter.c b/sys-utils/nsenter.c
index d8690db36..8dbd22b2e 100644
--- a/sys-utils/nsenter.c
+++ b/sys-utils/nsenter.c
@@ -48,9 +48,11 @@ static struct namespace_file {
} namespace_files[] = {
/* Careful the order is significant in this array.
*
- * The user namespace comes first, so that it is entered
- * first. This gives an unprivileged user the potential to
- * enter the other namespaces.
+ * The user namespace comes either first or last: first if
+ * you're using it to increase your privilege and last if
+ * you're using it to decrease. We enter the namespaces in
+ * two passes starting initially from offset 1 and then offset
+ * 0 if that fails.
*/
{ .nstype = CLONE_NEWUSER, .name = "ns/user", .fd = -1 },
{ .nstype = CLONE_NEWCGROUP,.name = "ns/cgroup", .fd = -1 },
@@ -202,7 +204,7 @@ int main(int argc, char *argv[])
};
struct namespace_file *nsfile;
- int c, namespaces = 0, setgroups_nerrs = 0, preserve_cred = 0;
+ int c, pass, namespaces = 0, setgroups_nerrs = 0, preserve_cred = 0;
bool do_rd = false, do_wd = false, force_uid = false, force_gid = false;
int do_fork = -1; /* unknown yet */
uid_t uid = 0;
@@ -353,19 +355,31 @@ int main(int argc, char *argv[])
}
/*
- * Now that we know which namespaces we want to enter, enter them.
+ * Now that we know which namespaces we want to enter, enter
+ * them. Do this in two passes, not entering the user
+ * namespace on the first pass. So if we're deprivileging the
+ * container we'll enter the user namespace last and if we're
+ * privileging it then we enter the usernamespace first
+ * (because the initial setns will fail).
*/
- for (nsfile = namespace_files; nsfile->nstype; nsfile++) {
- if (nsfile->fd < 0)
- continue;
- if (nsfile->nstype == CLONE_NEWPID && do_fork == -1)
- do_fork = 1;
- if (setns(nsfile->fd, nsfile->nstype))
- err(EXIT_FAILURE,
- _("reassociate to namespace '%s' failed"),
- nsfile->name);
- close(nsfile->fd);
- nsfile->fd = -1;
+ for (pass = 0; pass < 2; pass ++) {
+ for (nsfile = namespace_files + 1 - pass; nsfile->nstype; nsfile++) {
+ if (nsfile->fd < 0)
+ continue;
+ if (nsfile->nstype == CLONE_NEWPID && do_fork == -1)
+ do_fork = 1;
+ if (setns(nsfile->fd, nsfile->nstype)) {
+ if (pass != 0)
+ err(EXIT_FAILURE,
+ _("reassociate to namespace '%s' failed"),
+ nsfile->name);
+ else
+ continue;
+ }
+
+ close(nsfile->fd);
+ nsfile->fd = -1;
+ }
}
/* Remember the current working directory if I'm not changing it */