nsenter: add --all option
Let's make it easy for users to enter target process namespaces. Addresses: https://github.com/karelzak/util-linux/issues/382 Signed-off-by: Karel Zak <kzak@redhat.com>
This commit is contained in:
parent
8623264511
commit
974cc006f1
2 changed files with 65 additions and 1 deletions
|
@ -103,6 +103,18 @@ This should be one of the
|
||||||
files described in
|
files described in
|
||||||
.BR namespaces (7).
|
.BR namespaces (7).
|
||||||
.TP
|
.TP
|
||||||
|
\fB\-a\fR, \fB\-\-all\fR
|
||||||
|
Enter all namespaces of the target process by the default
|
||||||
|
.IR /proc/[pid]/ns/*
|
||||||
|
namespace paths. The default paths to the target process namespaces may be
|
||||||
|
overwritten by namespace specific options (e.g. --all --mount=[path]).
|
||||||
|
|
||||||
|
The user namespace will be ignored if the same as the caller's current user
|
||||||
|
namespace. It prevents a caller that has dropped capabilities from regaining
|
||||||
|
those capabilities via a call to setns(). See
|
||||||
|
.BR setns (2)
|
||||||
|
for more details.
|
||||||
|
.TP
|
||||||
\fB\-t\fR, \fB\-\-target\fR \fIpid\fP
|
\fB\-t\fR, \fB\-\-target\fR \fIpid\fP
|
||||||
Specify a target process to get contexts from. The paths to the contexts
|
Specify a target process to get contexts from. The paths to the contexts
|
||||||
specified by
|
specified by
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#include <grp.h>
|
#include <grp.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
#ifdef HAVE_LIBSELINUX
|
#ifdef HAVE_LIBSELINUX
|
||||||
# include <selinux/selinux.h>
|
# include <selinux/selinux.h>
|
||||||
|
@ -76,6 +77,7 @@ static void usage(int status)
|
||||||
fputs(_("Run a program with namespaces of other processes.\n"), out);
|
fputs(_("Run a program with namespaces of other processes.\n"), out);
|
||||||
|
|
||||||
fputs(USAGE_OPTIONS, out);
|
fputs(USAGE_OPTIONS, out);
|
||||||
|
fputs(_(" -a, --all enter all namespaces\n"), out);
|
||||||
fputs(_(" -t, --target <pid> target process to get namespaces from\n"), out);
|
fputs(_(" -t, --target <pid> target process to get namespaces from\n"), out);
|
||||||
fputs(_(" -m, --mount[=<file>] enter mount namespace\n"), out);
|
fputs(_(" -m, --mount[=<file>] enter mount namespace\n"), out);
|
||||||
fputs(_(" -u, --uts[=<file>] enter UTS namespace (hostname etc)\n"), out);
|
fputs(_(" -u, --uts[=<file>] enter UTS namespace (hostname etc)\n"), out);
|
||||||
|
@ -143,6 +145,32 @@ static void open_namespace_fd(int nstype, const char *path)
|
||||||
assert(nsfile->nstype);
|
assert(nsfile->nstype);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int get_ns_ino(const char *path, ino_t *ino)
|
||||||
|
{
|
||||||
|
struct stat st;
|
||||||
|
|
||||||
|
if (stat(path, &st) != 0)
|
||||||
|
return -errno;
|
||||||
|
*ino = st.st_ino;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int is_same_namespace(pid_t a, pid_t b, const char *type)
|
||||||
|
{
|
||||||
|
char path[PATH_MAX];
|
||||||
|
ino_t a_ino, b_ino;
|
||||||
|
|
||||||
|
snprintf(path, sizeof(path), "/proc/%u/%s", a, type);
|
||||||
|
if (get_ns_ino(path, &a_ino) != 0)
|
||||||
|
err(EXIT_FAILURE, _("stat of %s failed"), path);
|
||||||
|
|
||||||
|
snprintf(path, sizeof(path), "/proc/%u/%s", b, type);
|
||||||
|
if (get_ns_ino(path, &b_ino) != 0)
|
||||||
|
err(EXIT_FAILURE, _("stat of %s failed"), path);
|
||||||
|
|
||||||
|
return a_ino == b_ino;
|
||||||
|
}
|
||||||
|
|
||||||
static void continue_as_child(void)
|
static void continue_as_child(void)
|
||||||
{
|
{
|
||||||
pid_t child = fork();
|
pid_t child = fork();
|
||||||
|
@ -181,6 +209,7 @@ int main(int argc, char *argv[])
|
||||||
OPT_PRESERVE_CRED = CHAR_MAX + 1
|
OPT_PRESERVE_CRED = CHAR_MAX + 1
|
||||||
};
|
};
|
||||||
static const struct option longopts[] = {
|
static const struct option longopts[] = {
|
||||||
|
{ "all", no_argument, NULL, 'a' },
|
||||||
{ "help", no_argument, NULL, 'h' },
|
{ "help", no_argument, NULL, 'h' },
|
||||||
{ "version", no_argument, NULL, 'V'},
|
{ "version", no_argument, NULL, 'V'},
|
||||||
{ "target", required_argument, NULL, 't' },
|
{ "target", required_argument, NULL, 't' },
|
||||||
|
@ -206,6 +235,7 @@ int main(int argc, char *argv[])
|
||||||
struct namespace_file *nsfile;
|
struct namespace_file *nsfile;
|
||||||
int c, pass, 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;
|
bool do_rd = false, do_wd = false, force_uid = false, force_gid = false;
|
||||||
|
bool do_all = false;
|
||||||
int do_fork = -1; /* unknown yet */
|
int do_fork = -1; /* unknown yet */
|
||||||
uid_t uid = 0;
|
uid_t uid = 0;
|
||||||
gid_t gid = 0;
|
gid_t gid = 0;
|
||||||
|
@ -219,7 +249,7 @@ int main(int argc, char *argv[])
|
||||||
atexit(close_stdout);
|
atexit(close_stdout);
|
||||||
|
|
||||||
while ((c =
|
while ((c =
|
||||||
getopt_long(argc, argv, "+hVt:m::u::i::n::p::C::U::S:G:r::w::FZ",
|
getopt_long(argc, argv, "+ahVt:m::u::i::n::p::C::U::S:G:r::w::FZ",
|
||||||
longopts, NULL)) != -1) {
|
longopts, NULL)) != -1) {
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case 'h':
|
case 'h':
|
||||||
|
@ -227,6 +257,9 @@ int main(int argc, char *argv[])
|
||||||
case 'V':
|
case 'V':
|
||||||
printf(UTIL_LINUX_VERSION);
|
printf(UTIL_LINUX_VERSION);
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
|
case 'a':
|
||||||
|
do_all = true;
|
||||||
|
break;
|
||||||
case 't':
|
case 't':
|
||||||
namespace_target_pid =
|
namespace_target_pid =
|
||||||
strtoul_or_err(optarg, _("failed to parse pid"));
|
strtoul_or_err(optarg, _("failed to parse pid"));
|
||||||
|
@ -323,6 +356,25 @@ int main(int argc, char *argv[])
|
||||||
freecon(scon);
|
freecon(scon);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (do_all) {
|
||||||
|
if (!namespace_target_pid)
|
||||||
|
errx(EXIT_FAILURE, _("no target PID specified for --all"));
|
||||||
|
for (nsfile = namespace_files; nsfile->nstype; nsfile++) {
|
||||||
|
if (nsfile->fd >= 0)
|
||||||
|
continue; /* namespace already specified */
|
||||||
|
|
||||||
|
/* It is not permitted to use setns(2) to reenter the caller's
|
||||||
|
* current user namespace; see setns(2) man page for more details.
|
||||||
|
*/
|
||||||
|
if (nsfile->nstype & CLONE_NEWUSER
|
||||||
|
&& is_same_namespace(getpid(), namespace_target_pid, nsfile->name))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
namespaces |= nsfile->nstype;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Open remaining namespace and directory descriptors.
|
* Open remaining namespace and directory descriptors.
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue