Merge tag 'vfs-6.11.nsfs' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
authorLinus Torvalds <torvalds@linux-foundation.org>
Mon, 15 Jul 2024 19:27:39 +0000 (12:27 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 15 Jul 2024 19:27:39 +0000 (12:27 -0700)
Pull namespace-fs updates from Christian Brauner:
 "This adds ioctls allowing to translate PIDs between PID namespaces.

  The motivating use-case comes from LXCFS which is a tiny fuse
  filesystem used to virtualize various aspects of procfs. LXCFS is run
  on the host. The files and directories it creates can be bind-mounted
  by e.g. a container at startup and mounted over the various procfs
  files the container wishes to have virtualized.

  When e.g. a read request for uptime is received, LXCFS will receive
  the pid of the reader. In order to virtualize the corresponding read,
  LXCFS needs to know the pid of the init process of the reader's pid
  namespace.

  In order to do this, LXCFS first needs to fork() two helper processes.
  The first helper process setns() to the readers pid namespace. The
  second helper process is needed to create a process that is a proper
  member of the pid namespace.

  The second helper process then creates a ucred message with ucred.pid
  set to 1 and sends it back to LXCFS. The kernel will translate the
  ucred.pid field to the corresponding pid number in LXCFS's pid
  namespace. This way LXCFS can learn the init pid number of the
  reader's pid namespace and can go on to virtualize.

  Since these two forks() are costly LXCFS maintains an init pid cache
  that caches a given pid for a fixed amount of time. The cache is
  pruned during new read requests. However, even with the cache the hit
  of the two forks() is singificant when a very large number of
  containers are running.

  So this adds a simple set of ioctls that let's a caller translate PIDs
  from and into a given PID namespace. This significantly improves
  performance with a very simple change.

  To protect against races pidfds can be used to check whether the
  process is still valid"

* tag 'vfs-6.11.nsfs' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs:
  nsfs: add pid translation ioctls

1  2 
fs/nsfs.c
include/uapi/linux/nsfs.h

diff --cc fs/nsfs.c
index af352dadffe160b5383f18944455defc255d8ea1,a23c827a0299605814c86a3c61ac26cf340db2ce..ad6bb91a3e23762154a2d08d790372f08c9614e0
+++ b/fs/nsfs.c
@@@ -144,22 -147,56 +148,69 @@@ static long ns_ioctl(struct file *filp
                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,
index 56e8b1639b98fe579f65a75a3ad94943a2c5bb80,faeb9195da08c49845d5d9097d1736f99efa1eb7..b133211331f6a60e57e46f7c6bff650dc7d3c637
  #define NS_GET_NSTYPE         _IO(NSIO, 0x3)
  /* Get owner UID (in the caller's user namespace) for a user namespace */
  #define NS_GET_OWNER_UID      _IO(NSIO, 0x4)
 -#define NS_GET_PID_FROM_PIDNS _IOR(NSIO, 0x5, int)
 +/* Get the id for a mount namespace */
 +#define NS_GET_MNTNS_ID               _IO(NSIO, 0x5)
+ /* Translate pid from target pid namespace into the caller's pid namespace. */
 -#define NS_GET_PID_IN_PIDNS   _IOR(NSIO, 0x6, int)
++#define NS_GET_PID_FROM_PIDNS _IOR(NSIO, 0x6, int)
+ /* Return thread-group leader id of pid in the callers pid namespace. */
+ #define NS_GET_TGID_FROM_PIDNS        _IOR(NSIO, 0x7, int)
+ /* Translate pid from caller's pid namespace into a target pid namespace. */
 -#define NS_GET_TGID_IN_PIDNS  _IOR(NSIO, 0x8, int)
++#define NS_GET_PID_IN_PIDNS   _IOR(NSIO, 0x8, int)
+ /* Return thread-group leader id of pid in the target pid namespace. */
++#define NS_GET_TGID_IN_PIDNS  _IOR(NSIO, 0x9, int)
  
  #endif /* __LINUX_NSFS_H */