From: Christian Goeschel Ndjomouo Date: Mon, 12 Jan 2026 04:14:18 +0000 (-0500) Subject: nsenter: support 'PID:inode' process address format X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=986188d1da86fbde9d743089f4eb3f57e022707e;p=thirdparty%2Futil-linux.git nsenter: support 'PID:inode' process address format The 'PID:inode' can be used for the --target option to uniquely identify a process in a race-free manner. Signed-off-by: Christian Goeschel Ndjomouo --- diff --git a/sys-utils/nsenter.1.adoc b/sys-utils/nsenter.1.adoc index c480bdc9c..c21fdcc85 100644 --- a/sys-utils/nsenter.1.adoc +++ b/sys-utils/nsenter.1.adoc @@ -59,7 +59,7 @@ 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*(2). See the man page for more details. -*-t*, *--target* _PID_:: +*-t*, *--target* _PID[:inode]_:: Specify a target process to get contexts from. The paths to the contexts specified by _pid_ are: _/proc/pid/ns/mnt_;; @@ -83,6 +83,10 @@ the root directory _/proc/pid/cwd_;; the working directory respectively +Optionally, a process can be addressed with the format _PID:inode_. The _inode_ +identifies the unique process's file descriptor. To retrieve a process's inode +number you can use the *getino*(1) utility. + *-m*, *--mount*[**=**_file_]:: Enter the mount namespace. If no file is specified, enter the mount namespace of the target process. If _file_ is specified, enter the mount namespace specified by _file_. @@ -169,6 +173,7 @@ mailto:kzak@redhat.com[Karel Zak] *clone*(2), *setns*(2), *namespaces*(7) +*getino*(1) include::man-common/bugreports.adoc[] diff --git a/sys-utils/nsenter.c b/sys-utils/nsenter.c index a5976d9af..b45f626b1 100644 --- a/sys-utils/nsenter.c +++ b/sys-utils/nsenter.c @@ -52,6 +52,7 @@ #include "pathnames.h" #include "pidfd-utils.h" #include "linux_version.h" +#include "pidutils.h" static struct namespace_file { int nstype; @@ -90,34 +91,34 @@ static void __attribute__((__noreturn__)) usage(void) fputs(_("Run a program with namespaces of other processes.\n"), out); fputs(USAGE_OPTIONS, out); - fputs(_(" -a, --all enter all namespaces\n"), out); - fputs(_(" -t, --target target process to get namespaces from\n"), out); - fputs(_(" -m, --mount[=] enter mount namespace\n"), out); - fputs(_(" -u, --uts[=] enter UTS namespace (hostname etc)\n"), out); - fputs(_(" -i, --ipc[=] enter System V IPC namespace\n"), out); - fputs(_(" -n, --net[=] enter network namespace\n"), out); - fputs(_(" -N, --net-socket enter socket's network namespace (use with --target)\n"), out); - fputs(_(" -p, --pid[=] enter pid namespace\n"), out); - fputs(_(" -C, --cgroup[=] enter cgroup namespace\n"), out); - fputs(_(" -U, --user[=] enter user namespace\n"), out); - fputs(_(" --user-parent enter parent user namespace\n"), out); - fputs(_(" -T, --time[=] enter time namespace\n"), out); - fputs(_(" -S, --setuid[=] set uid in entered namespace\n"), out); - fputs(_(" -G, --setgid[=] set gid in entered namespace\n"), out); - fputs(_(" --preserve-credentials do not touch uids or gids\n"), out); - fputs(_(" --keep-caps retain capabilities granted in user namespaces\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(_(" -e, --env inherit environment variables from target process\n"), out); - fputs(_(" -F, --no-fork do not fork before exec'ing \n"), out); - fputs(_(" -c, --join-cgroup join the cgroup of the target process\n"), out); + fputs(_(" -a, --all enter all namespaces\n"), out); + fputs(_(" -t, --target target process to get namespaces from\n"), out); + fputs(_(" -m, --mount[=] enter mount namespace\n"), out); + fputs(_(" -u, --uts[=] enter UTS namespace (hostname etc)\n"), out); + fputs(_(" -i, --ipc[=] enter System V IPC namespace\n"), out); + fputs(_(" -n, --net[=] enter network namespace\n"), out); + fputs(_(" -N, --net-socket enter socket's network namespace (use with --target)\n"), out); + fputs(_(" -p, --pid[=] enter pid namespace\n"), out); + fputs(_(" -C, --cgroup[=] enter cgroup namespace\n"), out); + fputs(_(" -U, --user[=] enter user namespace\n"), out); + fputs(_(" --user-parent enter parent user namespace\n"), out); + fputs(_(" -T, --time[=] enter time namespace\n"), out); + fputs(_(" -S, --setuid[=] set uid in entered namespace\n"), out); + fputs(_(" -G, --setgid[=] set gid in entered namespace\n"), out); + fputs(_(" --preserve-credentials do not touch uids or gids\n"), out); + fputs(_(" --keep-caps retain capabilities granted in user namespaces\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(_(" -e, --env inherit environment variables from target process\n"), out); + fputs(_(" -F, --no-fork do not fork before exec'ing \n"), out); + fputs(_(" -c, --join-cgroup join the cgroup of the target process\n"), out); #ifdef HAVE_LIBSELINUX fputs(_(" -Z, --follow-context set SELinux context according to --target PID\n"), out); #endif fputs(USAGE_SEPARATOR, out); - fprintf(out, USAGE_HELP_OPTIONS(24)); + fprintf(out, USAGE_HELP_OPTIONS(30)); fprintf(out, USAGE_MAN_TAIL("nsenter(1)")); exit(EXIT_SUCCESS); @@ -490,6 +491,19 @@ static void continue_as_child(void) exit(EXIT_FAILURE); } +static int parse_pid_str(char *pidstr, pid_t *ns_target_pid) +{ + int rc, pfd; + uint64_t pidfd_ino = 0; + + rc = ul_parse_pid_str(pidstr, ns_target_pid, &pidfd_ino); + if (pidfd_ino) { + pfd = ul_get_valid_pidfd_or_err(*ns_target_pid, pidfd_ino); + close(pfd); + } + return rc; +} + int main(int argc, char *argv[]) { enum { @@ -533,7 +547,7 @@ int main(int argc, char *argv[]) }; int excl_st[ARRAY_SIZE(excl)] = UL_EXCL_STATUS_INIT; - int c, namespaces = 0, setgroups_nerrs = 0, preserve_cred = 0; + int c, rc, 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_join_cgroup = false, do_user_parent = false; @@ -548,6 +562,7 @@ int main(int argc, char *argv[]) bool selinux = 0; #endif + setlocale(LC_ALL, ""); bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); @@ -564,8 +579,9 @@ int main(int argc, char *argv[]) do_all = true; break; case 't': - namespace_target_pid = - strtoul_or_err(optarg, _("failed to parse pid")); + rc = parse_pid_str(optarg, &namespace_target_pid); + if (rc) + errx(EXIT_FAILURE, _("invalid PID argument")); break; case 'm': enable_namespace(CLONE_NEWNS, optarg);