From: Karel Zak Date: Mon, 22 Nov 2021 12:18:54 +0000 (+0100) Subject: nsenter: add --wdns to change working directory X-Git-Tag: v2.38-rc1~151 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=0cbb001a1e082c540011fced1eb1b0fef9e7a27e;p=thirdparty%2Futil-linux.git nsenter: add --wdns to change working directory The current --wd= changes CWD to the path which is opened *before* nsenter calls setns(). It may be useful if you want to use in namespace something from your current namespace. In this case, the option --wd works like a "tunnel" between namespaces. For some other use-cases, this is useless and you want to be sure that CWD always points to the target namespace. For this purpose this patch implements --wdns . Example: Setup the namespaces: # unshare --mount  # mount /dev/sdc /mnt/A # touch /mnt/A/fooooo  # echo $$ 2425872 Enter the namespace from another session: # nsenter --all --target 2425872 --wd=/mnt/A ls -a . .. # nsenter --all --target 2425872 --wdns=/mnt/A ls -a . .. fooooo lost+found Fixes: https://github.com/util-linux/util-linux/issues/1500 Signed-off-by: Karel Zak --- diff --git a/bash-completion/nsenter b/bash-completion/nsenter index 8ee74612e1..d3cb23f0b1 100644 --- a/bash-completion/nsenter +++ b/bash-completion/nsenter @@ -48,6 +48,7 @@ _nsenter_module() --preserve-credentials --root= --wd= + --wdns= --no-fork --help --version diff --git a/sys-utils/nsenter.1.adoc b/sys-utils/nsenter.1.adoc index e1d32dbc60..3df926810a 100644 --- a/sys-utils/nsenter.1.adoc +++ b/sys-utils/nsenter.1.adoc @@ -113,10 +113,13 @@ Set the user ID which will be used in the entered namespace. *nsenter* always se 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. diff --git a/sys-utils/nsenter.c b/sys-utils/nsenter.c index 7805703cbb..440bf3b9f8 100644 --- a/sys-utils/nsenter.c +++ b/sys-utils/nsenter.c @@ -41,6 +41,7 @@ #include "closestream.h" #include "namespace.h" #include "exec_shell.h" +#include "optutils.h" static struct namespace_file { int nstype; @@ -93,6 +94,7 @@ static void __attribute__((__noreturn__)) usage(void) fputs(_(" --preserve-credentials do not touch uids or gids\n"), out); fputs(_(" -r, --root[=] set the root directory\n"), out); fputs(_(" -w, --wd[=] set the working directory\n"), out); + fputs(_(" -W. --wdns set the working directory in namespace\n"), out); fputs(_(" -F, --no-fork do not fork before exec'ing \n"), out); #ifdef HAVE_LIBSELINUX fputs(_(" -Z, --follow-context set SELinux context according to --target PID\n"), out); @@ -243,6 +245,7 @@ int main(int argc, char *argv[]) { "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 @@ -250,12 +253,18 @@ int main(int argc, char *argv[]) #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 @@ -268,8 +277,11 @@ int main(int argc, char *argv[]) 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; @@ -349,6 +361,9 @@ int main(int argc, char *argv[]) else do_wd = true; break; + case 'W': + wdns = optarg; + break; case OPT_PRESERVE_CRED: preserve_cred = 1; break; @@ -455,7 +470,7 @@ int main(int argc, char *argv[]) } /* 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, @@ -477,6 +492,14 @@ int main(int argc, char *argv[]) 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)