From 72661e00915e54b5b690dcf23854bc401fd83aa9 Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Wed, 20 Nov 2024 00:14:12 +0100 Subject: [PATCH] pidfd-util: introduce helper for obtaining ns fd using PIDFD_GET_*_NAMESPACE directly --- src/basic/pidfd-util.c | 35 +++++++++++++++++++++++++++++++++++ src/basic/pidfd-util.h | 2 ++ 2 files changed, 37 insertions(+) diff --git a/src/basic/pidfd-util.c b/src/basic/pidfd-util.c index 53f2a688a74..c29173471b4 100644 --- a/src/basic/pidfd-util.c +++ b/src/basic/pidfd-util.c @@ -1,5 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ +#include #include #include "errno-util.h" @@ -33,6 +34,40 @@ static int pidfd_check_pidfs(void) { return (have_pidfs = fd_is_fs_type(fd, PID_FS_MAGIC)); } +int pidfd_get_namespace(int fd, unsigned long ns_type_cmd) { + static bool cached_supported = true; + + /* Obtain the namespace fd from pidfd directly through ioctl(PIDFD_GET_*_NAMESPACE). + * + * Returns -EOPNOTSUPP if ioctl on pidfds are not supported, -ENOPKG if the requested namespace + * is disabled in kernel. (The errno used are different from what kernel returns via ioctl(), + * see below) */ + + assert(fd >= 0); + + /* If we know ahead of time that pidfs is unavailable, shortcut things. But otherwise we don't + * call pidfd_check_pidfs() here, which is kinda extraneous and our own cache is required + * anyways (pidfs is introduced in kernel 6.9 while ioctl support there is added in 6.11). */ + if (have_pidfs == 0 || !cached_supported) + return -EOPNOTSUPP; + + int nsfd = ioctl(fd, ns_type_cmd); + if (nsfd < 0) { + /* Kernel returns EOPNOTSUPP if the ns type in question is disabled. Hence we need to look + * at precise errno instead of generic ERRNO_IS_(IOCTL_)NOT_SUPPORTED. */ + if (IN_SET(errno, ENOTTY, EINVAL)) { + cached_supported = false; + return -EOPNOTSUPP; + } + if (errno == EOPNOTSUPP) /* Translate to something more recognizable */ + return -ENOPKG; + + return -errno; + } + + return nsfd; +} + int pidfd_get_pid(int fd, pid_t *ret) { char path[STRLEN("/proc/self/fdinfo/") + DECIMAL_STR_MAX(int)]; _cleanup_free_ char *fdinfo = NULL; diff --git a/src/basic/pidfd-util.h b/src/basic/pidfd-util.h index 4db9368e407..2ffece0c4fe 100644 --- a/src/basic/pidfd-util.h +++ b/src/basic/pidfd-util.h @@ -7,6 +7,8 @@ #include "missing_pidfd.h" #include "missing_syscall.h" +int pidfd_get_namespace(int fd, unsigned long ns_type_cmd); + int pidfd_get_pid(int fd, pid_t *ret); int pidfd_verify_pid(int pidfd, pid_t pid); -- 2.47.3