aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bash-completion/nsenter1
-rw-r--r--sys-utils/nsenter.1.adoc8
-rw-r--r--sys-utils/nsenter.c50
3 files changed, 58 insertions, 1 deletions
diff --git a/bash-completion/nsenter b/bash-completion/nsenter
index 50763837ef..3ffd813714 100644
--- a/bash-completion/nsenter
+++ b/bash-completion/nsenter
@@ -42,6 +42,7 @@ _nsenter_module()
--pid=
--cgroup=
--user=
+ --user-parent
--time=
--setuid
--setgid
diff --git a/sys-utils/nsenter.1.adoc b/sys-utils/nsenter.1.adoc
index cf7e338301..b7e92d6b19 100644
--- a/sys-utils/nsenter.1.adoc
+++ b/sys-utils/nsenter.1.adoc
@@ -97,6 +97,10 @@ Enter the PID namespace. If no file is specified, enter the PID namespace of the
*-U*, *--user*[=_file_]::
Enter the user namespace. If no file is specified, enter the user namespace of the target process. If _file_ is specified, enter the user namespace specified by _file_. See also the *--setuid* and *--setgid* options.
+*--user-parent*::
+Enter the parent user namespace. Parent user namespace will be acquired from any other enabled namespace.
+If combined with *--user* option the parent user namespace will be fetched from the user namespace and replace it.
+
*-C*, *--cgroup*[=_file_]::
Enter the cgroup namespace. If no file is specified, enter the cgroup namespace of the target process. If _file_ is specified, enter the cgroup namespace specified by _file_.
@@ -139,6 +143,10 @@ Set the SELinux security context used for executing a new process according to a
include::man-common/help-version.adoc[]
+== NOTES
+
+The *--user-parent* option requires Linux 4.9 or higher, older kernels will raise inappropriate ioctl for device error.
+
== AUTHORS
mailto:biederm@xmission.com[Eric Biederman],
diff --git a/sys-utils/nsenter.c b/sys-utils/nsenter.c
index 7a4619d31a..74975313d5 100644
--- a/sys-utils/nsenter.c
+++ b/sys-utils/nsenter.c
@@ -31,6 +31,14 @@
#include <grp.h>
#include <sys/stat.h>
+#include <sys/ioctl.h>
+#ifdef HAVE_LINUX_NSFS_H
+# include <linux/nsfs.h>
+#endif
+#ifndef NS_GET_USERNS
+# define NS_GET_USERNS _IO(0xb7, 0x1)
+#endif
+
#ifdef HAVE_LIBSELINUX
# include <selinux/selinux.h>
#endif
@@ -92,6 +100,7 @@ static void __attribute__((__noreturn__)) usage(void)
fputs(_(" -p, --pid[=<file>] enter pid namespace\n"), out);
fputs(_(" -C, --cgroup[=<file>] enter cgroup namespace\n"), out);
fputs(_(" -U, --user[=<file>] enter user namespace\n"), out);
+ fputs(_(" --user-parent enter parent user namespace\n"), out);
fputs(_(" -T, --time[=<file>] enter time namespace\n"), out);
fputs(_(" -S, --setuid[=<uid>] set uid in entered namespace\n"), out);
fputs(_(" -G, --setgid[=<gid>] set gid in entered namespace\n"), out);
@@ -119,6 +128,33 @@ static int wd_fd = -1;
static int env_fd = -1;
static int uid_gid_fd = -1;
+static void set_parent_user_ns_fd(void)
+{
+ struct namespace_file *nsfile = NULL;
+ struct namespace_file *user_nsfile = NULL;
+ int parent_ns = -1;
+
+ for (nsfile = namespace_files; nsfile->nstype; nsfile++) {
+ if (nsfile->nstype == CLONE_NEWUSER)
+ user_nsfile = nsfile;
+
+ if (nsfile->fd == -1)
+ continue;
+
+ parent_ns = ioctl(nsfile->fd, NS_GET_USERNS);
+ if (parent_ns < 0)
+ err(EXIT_FAILURE, _("failed to open parent ns of %s"), nsfile->name);
+
+ break;
+ }
+
+ if (parent_ns < 0)
+ errx(EXIT_FAILURE, _("no namespaces to get parent of"));
+
+ user_nsfile->fd = parent_ns;
+}
+
+
static void open_target_fd(int *fd, const char *type, const char *path)
{
char pathbuf[PATH_MAX];
@@ -236,6 +272,7 @@ int main(int argc, char *argv[])
enum {
OPT_PRESERVE_CRED = CHAR_MAX + 1,
OPT_KEEPCAPS,
+ OPT_USER_PARENT,
};
static const struct option longopts[] = {
{ "all", no_argument, NULL, 'a' },
@@ -259,6 +296,7 @@ int main(int argc, char *argv[])
{ "no-fork", no_argument, NULL, 'F' },
{ "preserve-credentials", no_argument, NULL, OPT_PRESERVE_CRED },
{ "keep-caps", no_argument, NULL, OPT_KEEPCAPS },
+ { "user-parent", no_argument, NULL, OPT_USER_PARENT},
#ifdef HAVE_LIBSELINUX
{ "follow-context", no_argument, NULL, 'Z' },
#endif
@@ -273,7 +311,8 @@ int main(int argc, char *argv[])
struct namespace_file *nsfile;
int c, pass, namespaces = 0, setgroups_nerrs = 0, preserve_cred = 0;
bool do_rd = false, do_wd = false, do_uid = false, force_uid = false,
- do_gid = false, force_gid = false, do_env = false, do_all = false;
+ do_gid = false, force_gid = false, do_env = false, do_all = false,
+ do_user_parent = false;
int do_fork = -1; /* unknown yet */
char *wdns = NULL;
uid_t uid = 0;
@@ -392,6 +431,9 @@ int main(int argc, char *argv[])
case OPT_KEEPCAPS:
keepcaps = 1;
break;
+ case OPT_USER_PARENT:
+ do_user_parent = true;
+ break;
#ifdef HAVE_LIBSELINUX
case 'Z':
selinux = 1;
@@ -451,6 +493,12 @@ int main(int argc, char *argv[])
open_target_fd(&uid_gid_fd, "", NULL);
/*
+ * Get parent userns from any available ns.
+ */
+ if (do_user_parent)
+ set_parent_user_ns_fd();
+
+ /*
* Update namespaces variable to contain all requested namespaces
*/
for (nsfile = namespace_files; nsfile->nstype; nsfile++) {