Don't modify UID and GID when enter user namespace. The default is to drops supplementary groups and sets GID and UID to 0.
*-r*, *--root*[=_directory_]::
-Set the root directory. If no directory is specified, set the root directory to the root directory of the target process. If directory is specified, set the root directory to the specified directory.
+Set the root directory. If no directory is specified, set the root directory to the root directory of the target process. If directory is specified, set the root directory to the specified directory. The specified _directory_ is open before it switches to the requested namespaces.
*-w*, *--wd*[=_directory_]::
-Set the working directory. If no directory is specified, set the working directory to the working directory of the target process. If directory is specified, set the working directory to the specified directory.
+Set the working directory. If no directory is specified, set the working directory to the working directory of the target process. If directory is specified, set the working directory to the specified directory. The specified _directory_ is open before it switches to the requested namespaces, it means the specified directory works as "tunnel" to the current namespace. See also *--wdns*.
+
+*-W*, *--wdns*[=_directory_]::
+Set the working directory. The _directory_ is open after switch to the requested namespaces and after chroot call. The options *--wd* and *--wdns* are mutually exclusive.
*-F*, *--no-fork*::
Do not fork before exec'ing the specified program. By default, when entering a PID namespace, *nsenter* calls *fork* before calling *exec* so that any children will also be in the newly entered PID namespace.
#include "closestream.h"
#include "namespace.h"
#include "exec_shell.h"
+#include "optutils.h"
static struct namespace_file {
int nstype;
fputs(_(" --preserve-credentials do not touch uids or gids\n"), out);
fputs(_(" -r, --root[=<dir>] set the root directory\n"), out);
fputs(_(" -w, --wd[=<dir>] set the working directory\n"), out);
+ fputs(_(" -W. --wdns <dir> set the working directory in namespace\n"), out);
fputs(_(" -F, --no-fork do not fork before exec'ing <program>\n"), out);
#ifdef HAVE_LIBSELINUX
fputs(_(" -Z, --follow-context set SELinux context according to --target PID\n"), out);
{ "setgid", required_argument, NULL, 'G' },
{ "root", optional_argument, NULL, 'r' },
{ "wd", optional_argument, NULL, 'w' },
+ { "wdns", optional_argument, NULL, 'W' },
{ "no-fork", no_argument, NULL, 'F' },
{ "preserve-credentials", no_argument, NULL, OPT_PRESERVE_CRED },
#ifdef HAVE_LIBSELINUX
#endif
{ NULL, 0, NULL, 0 }
};
+ static const ul_excl_t excl[] = { /* rows and cols in ASCII order */
+ { 'W', 'w' },
+ { 0 }
+ };
+ int excl_st[ARRAY_SIZE(excl)] = UL_EXCL_STATUS_INIT;
struct namespace_file *nsfile;
int c, pass, namespaces = 0, setgroups_nerrs = 0, preserve_cred = 0;
bool do_rd = false, do_wd = false, force_uid = false, force_gid = false;
bool do_all = false;
int do_fork = -1; /* unknown yet */
+ char *wdns = NULL;
uid_t uid = 0;
gid_t gid = 0;
#ifdef HAVE_LIBSELINUX
close_stdout_atexit();
while ((c =
- getopt_long(argc, argv, "+ahVt:m::u::i::n::p::C::U::T::S:G:r::w::FZ",
+ getopt_long(argc, argv, "+ahVt:m::u::i::n::p::C::U::T::S:G:r::w::W:FZ",
longopts, NULL)) != -1) {
+
+ err_exclusive_options(c, longopts, excl, excl_st);
+
switch (c) {
case 'a':
do_all = true;
else
do_wd = true;
break;
+ case 'W':
+ wdns = optarg;
+ break;
case OPT_PRESERVE_CRED:
preserve_cred = 1;
break;
}
/* Remember the current working directory if I'm not changing it */
- if (root_fd >= 0 && wd_fd < 0) {
+ if (root_fd >= 0 && wd_fd < 0 && wdns == NULL) {
wd_fd = open(".", O_RDONLY);
if (wd_fd < 0)
err(EXIT_FAILURE,
root_fd = -1;
}
+ /* working directory specified as in-namespace path */
+ if (wdns) {
+ wd_fd = open(wdns, O_RDONLY);
+ if (wd_fd < 0)
+ err(EXIT_FAILURE,
+ _("cannot open current working directory"));
+ }
+
/* Change the working directory */
if (wd_fd >= 0) {
if (fchdir(wd_fd) < 0)