From: Mike Yuan Date: Tue, 19 Nov 2024 23:14:12 +0000 (+0100) Subject: pidfd-util: introduce helper for obtaining ns fd using PIDFD_GET_*_NAMESPACE directly X-Git-Tag: v258-rc1~1704^2~13 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=72661e00915e54b5b690dcf23854bc401fd83aa9;p=thirdparty%2Fsystemd.git pidfd-util: introduce helper for obtaining ns fd using PIDFD_GET_*_NAMESPACE directly --- 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);