b24413180f560 (Greg Kroah-Hartman 2017-11-01 15:07:57 +0100 1) // SPDX-License-Identifier: GPL-2.0
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 2) #include <linux/mount.h>
059b20d9da69d (David Howells 2019-03-25 16:38:23 +0000 3) #include <linux/pseudo_fs.h>
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 4) #include <linux/file.h>
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 5) #include <linux/fs.h>
7bebd69ecf107 (Eric Biggers 2020-01-04 12:59:52 -0800 6) #include <linux/proc_fs.h>
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 7) #include <linux/proc_ns.h>
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 8) #include <linux/magic.h>
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 9) #include <linux/ktime.h>
75509fd88fbd5 (Eric W. Biederman 2015-05-24 12:49:04 -0500 10) #include <linux/seq_file.h>
6786741dbf99e (Andrey Vagin 2016-09-06 00:47:14 -0700 11) #include <linux/user_namespace.h>
6786741dbf99e (Andrey Vagin 2016-09-06 00:47:14 -0700 12) #include <linux/nsfs.h>
d95fa3c76a66b (Michael Kerrisk (man-pages) 2017-01-25 14:04:15 +1300 13) #include <linux/uaccess.h>
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 14)
7bebd69ecf107 (Eric Biggers 2020-01-04 12:59:52 -0800 15) #include "internal.h"
7bebd69ecf107 (Eric Biggers 2020-01-04 12:59:52 -0800 16)
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 17) static struct vfsmount *nsfs_mnt;
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 18)
6786741dbf99e (Andrey Vagin 2016-09-06 00:47:14 -0700 19) static long ns_ioctl(struct file *filp, unsigned int ioctl,
6786741dbf99e (Andrey Vagin 2016-09-06 00:47:14 -0700 20) unsigned long arg);
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 21) static const struct file_operations ns_file_operations = {
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 22) .llseek = no_llseek,
6786741dbf99e (Andrey Vagin 2016-09-06 00:47:14 -0700 23) .unlocked_ioctl = ns_ioctl,
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 24) };
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 25)
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 26) static char *ns_dname(struct dentry *dentry, char *buffer, int buflen)
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 27) {
75c3cfa855dce (David Howells 2015-03-17 22:26:12 +0000 28) struct inode *inode = d_inode(dentry);
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 29) const struct proc_ns_operations *ns_ops = dentry->d_fsdata;
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 30)
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 31) return dynamic_dname(dentry, buffer, buflen, "%s:[%lu]",
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 32) ns_ops->name, inode->i_ino);
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 33) }
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 34)
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 35) static void ns_prune_dentry(struct dentry *dentry)
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 36) {
75c3cfa855dce (David Howells 2015-03-17 22:26:12 +0000 37) struct inode *inode = d_inode(dentry);
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 38) if (inode) {
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 39) struct ns_common *ns = inode->i_private;
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 40) atomic_long_set(&ns->stashed, 0);
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 41) }
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 42) }
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 43)
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 44) const struct dentry_operations ns_dentry_operations =
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 45) {
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 46) .d_prune = ns_prune_dentry,
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 47) .d_delete = always_delete_dentry,
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 48) .d_dname = ns_dname,
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 49) };
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 50)
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 51) static void nsfs_evict(struct inode *inode)
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 52) {
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 53) struct ns_common *ns = inode->i_private;
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 54) clear_inode(inode);
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 55) ns->ops->put(ns);
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 56) }
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 57)
ce623f89872df (Aleksa Sarai 2019-12-07 01:13:27 +1100 58) static int __ns_get_path(struct path *path, struct ns_common *ns)
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 59) {
213b067ce314f (Eric W. Biederman 2016-09-22 19:39:20 -0500 60) struct vfsmount *mnt = nsfs_mnt;
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 61) struct dentry *dentry;
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 62) struct inode *inode;
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 63) unsigned long d;
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 64)
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 65) rcu_read_lock();
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 66) d = atomic_long_read(&ns->stashed);
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 67) if (!d)
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 68) goto slow;
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 69) dentry = (struct dentry *)d;
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 70) if (!lockref_get_not_dead(&dentry->d_lockref))
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 71) goto slow;
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 72) rcu_read_unlock();
6786741dbf99e (Andrey Vagin 2016-09-06 00:47:14 -0700 73) ns->ops->put(ns);
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 74) got_it:
213b067ce314f (Eric W. Biederman 2016-09-22 19:39:20 -0500 75) path->mnt = mntget(mnt);
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 76) path->dentry = dentry;
ce623f89872df (Aleksa Sarai 2019-12-07 01:13:27 +1100 77) return 0;
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 78) slow:
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 79) rcu_read_unlock();
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 80) inode = new_inode_pseudo(mnt->mnt_sb);
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 81) if (!inode) {
6786741dbf99e (Andrey Vagin 2016-09-06 00:47:14 -0700 82) ns->ops->put(ns);
ce623f89872df (Aleksa Sarai 2019-12-07 01:13:27 +1100 83) return -ENOMEM;
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 84) }
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 85) inode->i_ino = ns->inum;
078cd8279e659 (Deepa Dinamani 2016-09-14 07:48:04 -0700 86) inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode);
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 87) inode->i_flags |= S_IMMUTABLE;
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 88) inode->i_mode = S_IFREG | S_IRUGO;
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 89) inode->i_fop = &ns_file_operations;
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 90) inode->i_private = ns;
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 91)
5467a68cbf688 (Al Viro 2019-03-15 22:23:19 -0400 92) dentry = d_alloc_anon(mnt->mnt_sb);
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 93) if (!dentry) {
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 94) iput(inode);
ce623f89872df (Aleksa Sarai 2019-12-07 01:13:27 +1100 95) return -ENOMEM;
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 96) }
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 97) d_instantiate(dentry, inode);
6786741dbf99e (Andrey Vagin 2016-09-06 00:47:14 -0700 98) dentry->d_fsdata = (void *)ns->ops;
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 99) d = atomic_long_cmpxchg(&ns->stashed, 0, (unsigned long)dentry);
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 100) if (d) {
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 101) d_delete(dentry); /* make sure ->d_prune() does nothing */
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 102) dput(dentry);
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 103) cpu_relax();
ce623f89872df (Aleksa Sarai 2019-12-07 01:13:27 +1100 104) return -EAGAIN;
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 105) }
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 106) goto got_it;
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 107) }
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 108)
ce623f89872df (Aleksa Sarai 2019-12-07 01:13:27 +1100 109) int ns_get_path_cb(struct path *path, ns_get_path_helper_t *ns_get_cb,
cdab6ba8668d6 (Jakub Kicinski 2017-12-27 18:39:08 -0800 110) void *private_data)
6786741dbf99e (Andrey Vagin 2016-09-06 00:47:14 -0700 111) {
ce623f89872df (Aleksa Sarai 2019-12-07 01:13:27 +1100 112) int ret;
6786741dbf99e (Andrey Vagin 2016-09-06 00:47:14 -0700 113)
357ab5b5d240a (Al Viro 2019-03-22 23:26:22 -0400 114) do {
357ab5b5d240a (Al Viro 2019-03-22 23:26:22 -0400 115) struct ns_common *ns = ns_get_cb(private_data);
357ab5b5d240a (Al Viro 2019-03-22 23:26:22 -0400 116) if (!ns)
ce623f89872df (Aleksa Sarai 2019-12-07 01:13:27 +1100 117) return -ENOENT;
357ab5b5d240a (Al Viro 2019-03-22 23:26:22 -0400 118) ret = __ns_get_path(path, ns);
ce623f89872df (Aleksa Sarai 2019-12-07 01:13:27 +1100 119) } while (ret == -EAGAIN);
6786741dbf99e (Andrey Vagin 2016-09-06 00:47:14 -0700 120)
6786741dbf99e (Andrey Vagin 2016-09-06 00:47:14 -0700 121) return ret;
6786741dbf99e (Andrey Vagin 2016-09-06 00:47:14 -0700 122) }
6786741dbf99e (Andrey Vagin 2016-09-06 00:47:14 -0700 123)
cdab6ba8668d6 (Jakub Kicinski 2017-12-27 18:39:08 -0800 124) struct ns_get_path_task_args {
cdab6ba8668d6 (Jakub Kicinski 2017-12-27 18:39:08 -0800 125) const struct proc_ns_operations *ns_ops;
cdab6ba8668d6 (Jakub Kicinski 2017-12-27 18:39:08 -0800 126) struct task_struct *task;
cdab6ba8668d6 (Jakub Kicinski 2017-12-27 18:39:08 -0800 127) };
cdab6ba8668d6 (Jakub Kicinski 2017-12-27 18:39:08 -0800 128)
cdab6ba8668d6 (Jakub Kicinski 2017-12-27 18:39:08 -0800 129) static struct ns_common *ns_get_path_task(void *private_data)
cdab6ba8668d6 (Jakub Kicinski 2017-12-27 18:39:08 -0800 130) {
cdab6ba8668d6 (Jakub Kicinski 2017-12-27 18:39:08 -0800 131) struct ns_get_path_task_args *args = private_data;
cdab6ba8668d6 (Jakub Kicinski 2017-12-27 18:39:08 -0800 132)
cdab6ba8668d6 (Jakub Kicinski 2017-12-27 18:39:08 -0800 133) return args->ns_ops->get(args->task);
cdab6ba8668d6 (Jakub Kicinski 2017-12-27 18:39:08 -0800 134) }
cdab6ba8668d6 (Jakub Kicinski 2017-12-27 18:39:08 -0800 135)
ce623f89872df (Aleksa Sarai 2019-12-07 01:13:27 +1100 136) int ns_get_path(struct path *path, struct task_struct *task,
cdab6ba8668d6 (Jakub Kicinski 2017-12-27 18:39:08 -0800 137) const struct proc_ns_operations *ns_ops)
cdab6ba8668d6 (Jakub Kicinski 2017-12-27 18:39:08 -0800 138) {
cdab6ba8668d6 (Jakub Kicinski 2017-12-27 18:39:08 -0800 139) struct ns_get_path_task_args args = {
cdab6ba8668d6 (Jakub Kicinski 2017-12-27 18:39:08 -0800 140) .ns_ops = ns_ops,
cdab6ba8668d6 (Jakub Kicinski 2017-12-27 18:39:08 -0800 141) .task = task,
cdab6ba8668d6 (Jakub Kicinski 2017-12-27 18:39:08 -0800 142) };
cdab6ba8668d6 (Jakub Kicinski 2017-12-27 18:39:08 -0800 143)
cdab6ba8668d6 (Jakub Kicinski 2017-12-27 18:39:08 -0800 144) return ns_get_path_cb(path, ns_get_path_task, &args);
cdab6ba8668d6 (Jakub Kicinski 2017-12-27 18:39:08 -0800 145) }
cdab6ba8668d6 (Jakub Kicinski 2017-12-27 18:39:08 -0800 146)
c62cce2caee55 (Andrey Vagin 2016-10-24 18:29:13 -0700 147) int open_related_ns(struct ns_common *ns,
6786741dbf99e (Andrey Vagin 2016-09-06 00:47:14 -0700 148) struct ns_common *(*get_ns)(struct ns_common *ns))
6786741dbf99e (Andrey Vagin 2016-09-06 00:47:14 -0700 149) {
6786741dbf99e (Andrey Vagin 2016-09-06 00:47:14 -0700 150) struct path path = {};
6786741dbf99e (Andrey Vagin 2016-09-06 00:47:14 -0700 151) struct file *f;
ce623f89872df (Aleksa Sarai 2019-12-07 01:13:27 +1100 152) int err;
6786741dbf99e (Andrey Vagin 2016-09-06 00:47:14 -0700 153) int fd;
6786741dbf99e (Andrey Vagin 2016-09-06 00:47:14 -0700 154)
6786741dbf99e (Andrey Vagin 2016-09-06 00:47:14 -0700 155) fd = get_unused_fd_flags(O_CLOEXEC);
6786741dbf99e (Andrey Vagin 2016-09-06 00:47:14 -0700 156) if (fd < 0)
6786741dbf99e (Andrey Vagin 2016-09-06 00:47:14 -0700 157) return fd;
6786741dbf99e (Andrey Vagin 2016-09-06 00:47:14 -0700 158)
357ab5b5d240a (Al Viro 2019-03-22 23:26:22 -0400 159) do {
6786741dbf99e (Andrey Vagin 2016-09-06 00:47:14 -0700 160) struct ns_common *relative;
6786741dbf99e (Andrey Vagin 2016-09-06 00:47:14 -0700 161)
6786741dbf99e (Andrey Vagin 2016-09-06 00:47:14 -0700 162) relative = get_ns(ns);
6786741dbf99e (Andrey Vagin 2016-09-06 00:47:14 -0700 163) if (IS_ERR(relative)) {
6786741dbf99e (Andrey Vagin 2016-09-06 00:47:14 -0700 164) put_unused_fd(fd);
6786741dbf99e (Andrey Vagin 2016-09-06 00:47:14 -0700 165) return PTR_ERR(relative);
6786741dbf99e (Andrey Vagin 2016-09-06 00:47:14 -0700 166) }
6786741dbf99e (Andrey Vagin 2016-09-06 00:47:14 -0700 167)
6786741dbf99e (Andrey Vagin 2016-09-06 00:47:14 -0700 168) err = __ns_get_path(&path, relative);
ce623f89872df (Aleksa Sarai 2019-12-07 01:13:27 +1100 169) } while (err == -EAGAIN);
357ab5b5d240a (Al Viro 2019-03-22 23:26:22 -0400 170)
ce623f89872df (Aleksa Sarai 2019-12-07 01:13:27 +1100 171) if (err) {
6786741dbf99e (Andrey Vagin 2016-09-06 00:47:14 -0700 172) put_unused_fd(fd);
ce623f89872df (Aleksa Sarai 2019-12-07 01:13:27 +1100 173) return err;
6786741dbf99e (Andrey Vagin 2016-09-06 00:47:14 -0700 174) }
6786741dbf99e (Andrey Vagin 2016-09-06 00:47:14 -0700 175)
6786741dbf99e (Andrey Vagin 2016-09-06 00:47:14 -0700 176) f = dentry_open(&path, O_RDONLY, current_cred());
6786741dbf99e (Andrey Vagin 2016-09-06 00:47:14 -0700 177) path_put(&path);
6786741dbf99e (Andrey Vagin 2016-09-06 00:47:14 -0700 178) if (IS_ERR(f)) {
6786741dbf99e (Andrey Vagin 2016-09-06 00:47:14 -0700 179) put_unused_fd(fd);
6786741dbf99e (Andrey Vagin 2016-09-06 00:47:14 -0700 180) fd = PTR_ERR(f);
6786741dbf99e (Andrey Vagin 2016-09-06 00:47:14 -0700 181) } else
6786741dbf99e (Andrey Vagin 2016-09-06 00:47:14 -0700 182) fd_install(fd, f);
6786741dbf99e (Andrey Vagin 2016-09-06 00:47:14 -0700 183)
6786741dbf99e (Andrey Vagin 2016-09-06 00:47:14 -0700 184) return fd;
6786741dbf99e (Andrey Vagin 2016-09-06 00:47:14 -0700 185) }
24dce0800baaa (Kirill Tkhai 2018-02-14 16:40:05 +0300 186) EXPORT_SYMBOL_GPL(open_related_ns);
6786741dbf99e (Andrey Vagin 2016-09-06 00:47:14 -0700 187)
6786741dbf99e (Andrey Vagin 2016-09-06 00:47:14 -0700 188) static long ns_ioctl(struct file *filp, unsigned int ioctl,
6786741dbf99e (Andrey Vagin 2016-09-06 00:47:14 -0700 189) unsigned long arg)
6786741dbf99e (Andrey Vagin 2016-09-06 00:47:14 -0700 190) {
d95fa3c76a66b (Michael Kerrisk (man-pages) 2017-01-25 14:04:15 +1300 191) struct user_namespace *user_ns;
6786741dbf99e (Andrey Vagin 2016-09-06 00:47:14 -0700 192) struct ns_common *ns = get_proc_ns(file_inode(filp));
d95fa3c76a66b (Michael Kerrisk (man-pages) 2017-01-25 14:04:15 +1300 193) uid_t __user *argp;
d95fa3c76a66b (Michael Kerrisk (man-pages) 2017-01-25 14:04:15 +1300 194) uid_t uid;
6786741dbf99e (Andrey Vagin 2016-09-06 00:47:14 -0700 195)
6786741dbf99e (Andrey Vagin 2016-09-06 00:47:14 -0700 196) switch (ioctl) {
6786741dbf99e (Andrey Vagin 2016-09-06 00:47:14 -0700 197) case NS_GET_USERNS:
6786741dbf99e (Andrey Vagin 2016-09-06 00:47:14 -0700 198) return open_related_ns(ns, ns_get_owner);
a7306ed8d94af (Andrey Vagin 2016-09-06 00:47:15 -0700 199) case NS_GET_PARENT:
a7306ed8d94af (Andrey Vagin 2016-09-06 00:47:15 -0700 200) if (!ns->ops->get_parent)
a7306ed8d94af (Andrey Vagin 2016-09-06 00:47:15 -0700 201) return -EINVAL;
a7306ed8d94af (Andrey Vagin 2016-09-06 00:47:15 -0700 202) return open_related_ns(ns, ns->ops->get_parent);
e5ff5ce6e20ee (Michael Kerrisk (man-pages) 2017-01-25 14:03:36 +1300 203) case NS_GET_NSTYPE:
e5ff5ce6e20ee (Michael Kerrisk (man-pages) 2017-01-25 14:03:36 +1300 204) return ns->ops->type;
d95fa3c76a66b (Michael Kerrisk (man-pages) 2017-01-25 14:04:15 +1300 205) case NS_GET_OWNER_UID:
d95fa3c76a66b (Michael Kerrisk (man-pages) 2017-01-25 14:04:15 +1300 206) if (ns->ops->type != CLONE_NEWUSER)
d95fa3c76a66b (Michael Kerrisk (man-pages) 2017-01-25 14:04:15 +1300 207) return -EINVAL;
d95fa3c76a66b (Michael Kerrisk (man-pages) 2017-01-25 14:04:15 +1300 208) user_ns = container_of(ns, struct user_namespace, ns);
d95fa3c76a66b (Michael Kerrisk (man-pages) 2017-01-25 14:04:15 +1300 209) argp = (uid_t __user *) arg;
d95fa3c76a66b (Michael Kerrisk (man-pages) 2017-01-25 14:04:15 +1300 210) uid = from_kuid_munged(current_user_ns(), user_ns->owner);
d95fa3c76a66b (Michael Kerrisk (man-pages) 2017-01-25 14:04:15 +1300 211) return put_user(uid, argp);
6786741dbf99e (Andrey Vagin 2016-09-06 00:47:14 -0700 212) default:
6786741dbf99e (Andrey Vagin 2016-09-06 00:47:14 -0700 213) return -ENOTTY;
6786741dbf99e (Andrey Vagin 2016-09-06 00:47:14 -0700 214) }
6786741dbf99e (Andrey Vagin 2016-09-06 00:47:14 -0700 215) }
6786741dbf99e (Andrey Vagin 2016-09-06 00:47:14 -0700 216)
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 217) int ns_get_name(char *buf, size_t size, struct task_struct *task,
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 218) const struct proc_ns_operations *ns_ops)
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 219) {
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 220) struct ns_common *ns;
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 221) int res = -ENOENT;
25b14e92af1a5 (Kirill Tkhai 2017-05-08 15:56:38 -0700 222) const char *name;
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 223) ns = ns_ops->get(task);
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 224) if (ns) {
25b14e92af1a5 (Kirill Tkhai 2017-05-08 15:56:38 -0700 225) name = ns_ops->real_ns_name ? : ns_ops->name;
25b14e92af1a5 (Kirill Tkhai 2017-05-08 15:56:38 -0700 226) res = snprintf(buf, size, "%s:[%u]", name, ns->inum);
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 227) ns_ops->put(ns);
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 228) }
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 229) return res;
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 230) }
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 231)
303cc571d107b (Christian Brauner 2020-05-05 16:04:31 +0200 232) bool proc_ns_file(const struct file *file)
303cc571d107b (Christian Brauner 2020-05-05 16:04:31 +0200 233) {
303cc571d107b (Christian Brauner 2020-05-05 16:04:31 +0200 234) return file->f_op == &ns_file_operations;
303cc571d107b (Christian Brauner 2020-05-05 16:04:31 +0200 235) }
303cc571d107b (Christian Brauner 2020-05-05 16:04:31 +0200 236)
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 237) struct file *proc_ns_fget(int fd)
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 238) {
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 239) struct file *file;
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 240)
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 241) file = fget(fd);
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 242) if (!file)
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 243) return ERR_PTR(-EBADF);
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 244)
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 245) if (file->f_op != &ns_file_operations)
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 246) goto out_invalid;
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 247)
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 248) return file;
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 249)
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 250) out_invalid:
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 251) fput(file);
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 252) return ERR_PTR(-EINVAL);
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 253) }
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 254)
1e2328e762548 (Carlos Neira 2020-03-04 17:41:55 -0300 255) /**
1e2328e762548 (Carlos Neira 2020-03-04 17:41:55 -0300 256) * ns_match() - Returns true if current namespace matches dev/ino provided.
1e2328e762548 (Carlos Neira 2020-03-04 17:41:55 -0300 257) * @ns_common: current ns
1e2328e762548 (Carlos Neira 2020-03-04 17:41:55 -0300 258) * @dev: dev_t from nsfs that will be matched against current nsfs
1e2328e762548 (Carlos Neira 2020-03-04 17:41:55 -0300 259) * @ino: ino_t from nsfs that will be matched against current nsfs
1e2328e762548 (Carlos Neira 2020-03-04 17:41:55 -0300 260) *
1e2328e762548 (Carlos Neira 2020-03-04 17:41:55 -0300 261) * Return: true if dev and ino matches the current nsfs.
1e2328e762548 (Carlos Neira 2020-03-04 17:41:55 -0300 262) */
1e2328e762548 (Carlos Neira 2020-03-04 17:41:55 -0300 263) bool ns_match(const struct ns_common *ns, dev_t dev, ino_t ino)
1e2328e762548 (Carlos Neira 2020-03-04 17:41:55 -0300 264) {
1e2328e762548 (Carlos Neira 2020-03-04 17:41:55 -0300 265) return (ns->inum == ino) && (nsfs_mnt->mnt_sb->s_dev == dev);
1e2328e762548 (Carlos Neira 2020-03-04 17:41:55 -0300 266) }
1e2328e762548 (Carlos Neira 2020-03-04 17:41:55 -0300 267)
1e2328e762548 (Carlos Neira 2020-03-04 17:41:55 -0300 268)
75509fd88fbd5 (Eric W. Biederman 2015-05-24 12:49:04 -0500 269) static int nsfs_show_path(struct seq_file *seq, struct dentry *dentry)
75509fd88fbd5 (Eric W. Biederman 2015-05-24 12:49:04 -0500 270) {
75509fd88fbd5 (Eric W. Biederman 2015-05-24 12:49:04 -0500 271) struct inode *inode = d_inode(dentry);
75509fd88fbd5 (Eric W. Biederman 2015-05-24 12:49:04 -0500 272) const struct proc_ns_operations *ns_ops = dentry->d_fsdata;
75509fd88fbd5 (Eric W. Biederman 2015-05-24 12:49:04 -0500 273)
6798a8caaf64f (Joe Perches 2015-09-11 13:07:48 -0700 274) seq_printf(seq, "%s:[%lu]", ns_ops->name, inode->i_ino);
6798a8caaf64f (Joe Perches 2015-09-11 13:07:48 -0700 275) return 0;
75509fd88fbd5 (Eric W. Biederman 2015-05-24 12:49:04 -0500 276) }
75509fd88fbd5 (Eric W. Biederman 2015-05-24 12:49:04 -0500 277)
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 278) static const struct super_operations nsfs_ops = {
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 279) .statfs = simple_statfs,
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 280) .evict_inode = nsfs_evict,
75509fd88fbd5 (Eric W. Biederman 2015-05-24 12:49:04 -0500 281) .show_path = nsfs_show_path,
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 282) };
059b20d9da69d (David Howells 2019-03-25 16:38:23 +0000 283)
059b20d9da69d (David Howells 2019-03-25 16:38:23 +0000 284) static int nsfs_init_fs_context(struct fs_context *fc)
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 285) {
059b20d9da69d (David Howells 2019-03-25 16:38:23 +0000 286) struct pseudo_fs_context *ctx = init_pseudo(fc, NSFS_MAGIC);
059b20d9da69d (David Howells 2019-03-25 16:38:23 +0000 287) if (!ctx)
059b20d9da69d (David Howells 2019-03-25 16:38:23 +0000 288) return -ENOMEM;
059b20d9da69d (David Howells 2019-03-25 16:38:23 +0000 289) ctx->ops = &nsfs_ops;
059b20d9da69d (David Howells 2019-03-25 16:38:23 +0000 290) ctx->dops = &ns_dentry_operations;
059b20d9da69d (David Howells 2019-03-25 16:38:23 +0000 291) return 0;
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 292) }
059b20d9da69d (David Howells 2019-03-25 16:38:23 +0000 293)
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 294) static struct file_system_type nsfs = {
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 295) .name = "nsfs",
059b20d9da69d (David Howells 2019-03-25 16:38:23 +0000 296) .init_fs_context = nsfs_init_fs_context,
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 297) .kill_sb = kill_anon_super,
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 298) };
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 299)
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 300) void __init nsfs_init(void)
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 301) {
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 302) nsfs_mnt = kern_mount(&nsfs);
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 303) if (IS_ERR(nsfs_mnt))
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 304) panic("can't set nsfs up\n");
1751e8a6cb935 (Linus Torvalds 2017-11-27 13:05:09 -0800 305) nsfs_mnt->mnt_sb->s_flags &= ~SB_NOUSER;
e149ed2b805fe (Al Viro 2014-11-01 10:57:28 -0400 306) }