]> Git Repo - J-linux.git/commitdiff
Merge tag 'vfs-6.11.pidfs' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
authorLinus Torvalds <[email protected]>
Mon, 15 Jul 2024 19:34:01 +0000 (12:34 -0700)
committerLinus Torvalds <[email protected]>
Mon, 15 Jul 2024 19:34:01 +0000 (12:34 -0700)
Pull pidfs updates from Christian Brauner:
 "This contains work to make it possible to derive namespace file
  descriptors from pidfd file descriptors.

  Right now it is already possible to use a pidfd with setns() to
  atomically change multiple namespaces at the same time. In other
  words, it is possible to switch to the namespace context of a process
  using a pidfd. There is no need to first open namespace file
  descriptors via procfs.

  The work included here is an extension of these abilities by allowing
  to open namespace file descriptors using a pidfd. This means it is now
  possible to interact with namespaces without ever touching procfs.

  To this end a new set of ioctls() on pidfds is introduced covering all
  supported namespace types"

* tag 'vfs-6.11.pidfs' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs:
  pidfs: allow retrieval of namespace file descriptors
  nsfs: add open_namespace()
  nsproxy: add helper to go from arbitrary namespace to ns_common
  nsproxy: add a cleanup helper for nsproxy
  file: add take_fd() cleanup helper

1  2 
fs/internal.h
fs/nsfs.c

diff --combined fs/internal.h
index f26454c60a98422684258d31457990c39f55556e,24346cf765ddce9cbf182a5a489d81ca37342be6..cdd73209eecb4483323434bff314fc9b8569296f
@@@ -17,6 -17,7 +17,7 @@@ struct fs_context
  struct pipe_inode_info;
  struct iov_iter;
  struct mnt_idmap;
+ struct ns_common;
  
  /*
   * block/bdev.c
@@@ -239,6 -240,6 +240,7 @@@ extern void mnt_pin_kill(struct mount *
   * fs/nsfs.c
   */
  extern const struct dentry_operations ns_dentry_operations;
++int open_namespace(struct ns_common *ns);
  
  /*
   * fs/stat.c:
  int getname_statx_lookup_flags(int flags);
  int do_statx(int dfd, struct filename *filename, unsigned int flags,
             unsigned int mask, struct statx __user *buffer);
 +int do_statx_fd(int fd, unsigned int flags, unsigned int mask,
 +              struct statx __user *buffer);
  
  /*
   * fs/splice.c:
@@@ -323,15 -322,4 +325,15 @@@ struct stashed_operations 
  int path_from_stashed(struct dentry **stashed, struct vfsmount *mnt, void *data,
                      struct path *path);
  void stashed_dentry_prune(struct dentry *dentry);
 -int open_namespace(struct ns_common *ns);
 +/**
 + * path_mounted - check whether path is mounted
 + * @path: path to check
 + *
 + * Determine whether @path refers to the root of a mount.
 + *
 + * Return: true if @path is the root of a mount, false if not.
 + */
 +static inline bool path_mounted(const struct path *path)
 +{
 +      return path->mnt->mnt_root == path->dentry;
 +}
diff --combined fs/nsfs.c
index ad6bb91a3e23762154a2d08d790372f08c9614e0,4c4dbdce7601a619c6ab7dd71594a3613d25c152..a4a925dce33127fc6ccd107f500338cf141e1ab3
+++ b/fs/nsfs.c
@@@ -8,12 -8,10 +8,12 @@@
  #include <linux/magic.h>
  #include <linux/ktime.h>
  #include <linux/seq_file.h>
 +#include <linux/pid_namespace.h>
  #include <linux/user_namespace.h>
  #include <linux/nsfs.h>
  #include <linux/uaccess.h>
  
 +#include "mount.h"
  #include "internal.h"
  
  static struct vfsmount *nsfs_mnt;
@@@ -84,40 -82,47 +84,47 @@@ int ns_get_path(struct path *path, stru
        return ns_get_path_cb(path, ns_get_path_task, &args);
  }
  
- int open_related_ns(struct ns_common *ns,
-                  struct ns_common *(*get_ns)(struct ns_common *ns))
+ /**
+  * open_namespace - open a namespace
+  * @ns: the namespace to open
+  *
+  * This will consume a reference to @ns indendent of success or failure.
+  *
+  * Return: A file descriptor on success or a negative error code on failure.
+  */
+ int open_namespace(struct ns_common *ns)
  {
-       struct path path = {};
-       struct ns_common *relative;
+       struct path path __free(path_put) = {};
        struct file *f;
        int err;
-       int fd;
  
-       fd = get_unused_fd_flags(O_CLOEXEC);
+       /* call first to consume reference */
+       err = path_from_stashed(&ns->stashed, nsfs_mnt, ns, &path);
+       if (err < 0)
+               return err;
+       CLASS(get_unused_fd, fd)(O_CLOEXEC);
        if (fd < 0)
                return fd;
  
+       f = dentry_open(&path, O_RDONLY, current_cred());
+       if (IS_ERR(f))
+               return PTR_ERR(f);
+       fd_install(fd, f);
+       return take_fd(fd);
+ }
+ int open_related_ns(struct ns_common *ns,
+                  struct ns_common *(*get_ns)(struct ns_common *ns))
+ {
+       struct ns_common *relative;
        relative = get_ns(ns);
-       if (IS_ERR(relative)) {
-               put_unused_fd(fd);
+       if (IS_ERR(relative))
                return PTR_ERR(relative);
-       }
-       err = path_from_stashed(&relative->stashed, nsfs_mnt, relative, &path);
-       if (err < 0) {
-               put_unused_fd(fd);
-               return err;
-       }
  
-       f = dentry_open(&path, O_RDONLY, current_cred());
-       path_put(&path);
-       if (IS_ERR(f)) {
-               put_unused_fd(fd);
-               fd = PTR_ERR(f);
-       } else
-               fd_install(fd, f);
-       return fd;
+       return open_namespace(relative);
  }
  EXPORT_SYMBOL_GPL(open_related_ns);
  
@@@ -125,12 -130,9 +132,12 @@@ static long ns_ioctl(struct file *filp
                        unsigned long arg)
  {
        struct user_namespace *user_ns;
 +      struct pid_namespace *pid_ns;
 +      struct task_struct *tsk;
        struct ns_common *ns = get_proc_ns(file_inode(filp));
        uid_t __user *argp;
        uid_t uid;
 +      int ret;
  
        switch (ioctl) {
        case NS_GET_USERNS:
                argp = (uid_t __user *) arg;
                uid = from_kuid_munged(current_user_ns(), user_ns->owner);
                return put_user(uid, argp);
 +      case NS_GET_MNTNS_ID: {
 +              struct mnt_namespace *mnt_ns;
 +              __u64 __user *idp;
 +              __u64 id;
 +
 +              if (ns->ops->type != CLONE_NEWNS)
 +                      return -EINVAL;
 +
 +              mnt_ns = container_of(ns, struct mnt_namespace, ns);
 +              idp = (__u64 __user *)arg;
 +              id = mnt_ns->seq;
 +              return put_user(id, idp);
 +      }
 +      case NS_GET_PID_FROM_PIDNS:
 +              fallthrough;
 +      case NS_GET_TGID_FROM_PIDNS:
 +              fallthrough;
 +      case NS_GET_PID_IN_PIDNS:
 +              fallthrough;
 +      case NS_GET_TGID_IN_PIDNS:
 +              if (ns->ops->type != CLONE_NEWPID)
 +                      return -EINVAL;
 +
 +              ret = -ESRCH;
 +              pid_ns = container_of(ns, struct pid_namespace, ns);
 +
 +              rcu_read_lock();
 +
 +              if (ioctl == NS_GET_PID_IN_PIDNS ||
 +                  ioctl == NS_GET_TGID_IN_PIDNS)
 +                      tsk = find_task_by_vpid(arg);
 +              else
 +                      tsk = find_task_by_pid_ns(arg, pid_ns);
 +              if (!tsk)
 +                      break;
 +
 +              switch (ioctl) {
 +              case NS_GET_PID_FROM_PIDNS:
 +                      ret = task_pid_vnr(tsk);
 +                      break;
 +              case NS_GET_TGID_FROM_PIDNS:
 +                      ret = task_tgid_vnr(tsk);
 +                      break;
 +              case NS_GET_PID_IN_PIDNS:
 +                      ret = task_pid_nr_ns(tsk, pid_ns);
 +                      break;
 +              case NS_GET_TGID_IN_PIDNS:
 +                      ret = task_tgid_nr_ns(tsk, pid_ns);
 +                      break;
 +              default:
 +                      ret = 0;
 +                      break;
 +              }
 +              rcu_read_unlock();
 +
 +              if (!ret)
 +                      ret = -ESRCH;
 +              break;
        default:
 -              return -ENOTTY;
 +              ret = -ENOTTY;
        }
 +
 +      return ret;
  }
  
  int ns_get_name(char *buf, size_t size, struct task_struct *task,
This page took 0.0658300000000001 seconds and 4 git commands to generate.