~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/fs/nsfs.c

Version: ~ [ linux-5.8 ] ~ [ linux-5.7.14 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.57 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.138 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.193 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.232 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.232 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.85 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0
  2 #include <linux/mount.h>
  3 #include <linux/pseudo_fs.h>
  4 #include <linux/file.h>
  5 #include <linux/fs.h>
  6 #include <linux/proc_fs.h>
  7 #include <linux/proc_ns.h>
  8 #include <linux/magic.h>
  9 #include <linux/ktime.h>
 10 #include <linux/seq_file.h>
 11 #include <linux/user_namespace.h>
 12 #include <linux/nsfs.h>
 13 #include <linux/uaccess.h>
 14 
 15 #include "internal.h"
 16 
 17 static struct vfsmount *nsfs_mnt;
 18 
 19 static long ns_ioctl(struct file *filp, unsigned int ioctl,
 20                         unsigned long arg);
 21 static const struct file_operations ns_file_operations = {
 22         .llseek         = no_llseek,
 23         .unlocked_ioctl = ns_ioctl,
 24 };
 25 
 26 static char *ns_dname(struct dentry *dentry, char *buffer, int buflen)
 27 {
 28         struct inode *inode = d_inode(dentry);
 29         const struct proc_ns_operations *ns_ops = dentry->d_fsdata;
 30 
 31         return dynamic_dname(dentry, buffer, buflen, "%s:[%lu]",
 32                 ns_ops->name, inode->i_ino);
 33 }
 34 
 35 static void ns_prune_dentry(struct dentry *dentry)
 36 {
 37         struct inode *inode = d_inode(dentry);
 38         if (inode) {
 39                 struct ns_common *ns = inode->i_private;
 40                 atomic_long_set(&ns->stashed, 0);
 41         }
 42 }
 43 
 44 const struct dentry_operations ns_dentry_operations =
 45 {
 46         .d_prune        = ns_prune_dentry,
 47         .d_delete       = always_delete_dentry,
 48         .d_dname        = ns_dname,
 49 };
 50 
 51 static void nsfs_evict(struct inode *inode)
 52 {
 53         struct ns_common *ns = inode->i_private;
 54         clear_inode(inode);
 55         ns->ops->put(ns);
 56 }
 57 
 58 static int __ns_get_path(struct path *path, struct ns_common *ns)
 59 {
 60         struct vfsmount *mnt = nsfs_mnt;
 61         struct dentry *dentry;
 62         struct inode *inode;
 63         unsigned long d;
 64 
 65         rcu_read_lock();
 66         d = atomic_long_read(&ns->stashed);
 67         if (!d)
 68                 goto slow;
 69         dentry = (struct dentry *)d;
 70         if (!lockref_get_not_dead(&dentry->d_lockref))
 71                 goto slow;
 72         rcu_read_unlock();
 73         ns->ops->put(ns);
 74 got_it:
 75         path->mnt = mntget(mnt);
 76         path->dentry = dentry;
 77         return 0;
 78 slow:
 79         rcu_read_unlock();
 80         inode = new_inode_pseudo(mnt->mnt_sb);
 81         if (!inode) {
 82                 ns->ops->put(ns);
 83                 return -ENOMEM;
 84         }
 85         inode->i_ino = ns->inum;
 86         inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode);
 87         inode->i_flags |= S_IMMUTABLE;
 88         inode->i_mode = S_IFREG | S_IRUGO;
 89         inode->i_fop = &ns_file_operations;
 90         inode->i_private = ns;
 91 
 92         dentry = d_alloc_anon(mnt->mnt_sb);
 93         if (!dentry) {
 94                 iput(inode);
 95                 return -ENOMEM;
 96         }
 97         d_instantiate(dentry, inode);
 98         dentry->d_fsdata = (void *)ns->ops;
 99         d = atomic_long_cmpxchg(&ns->stashed, 0, (unsigned long)dentry);
100         if (d) {
101                 d_delete(dentry);       /* make sure ->d_prune() does nothing */
102                 dput(dentry);
103                 cpu_relax();
104                 return -EAGAIN;
105         }
106         goto got_it;
107 }
108 
109 int ns_get_path_cb(struct path *path, ns_get_path_helper_t *ns_get_cb,
110                      void *private_data)
111 {
112         int ret;
113 
114         do {
115                 struct ns_common *ns = ns_get_cb(private_data);
116                 if (!ns)
117                         return -ENOENT;
118                 ret = __ns_get_path(path, ns);
119         } while (ret == -EAGAIN);
120 
121         return ret;
122 }
123 
124 struct ns_get_path_task_args {
125         const struct proc_ns_operations *ns_ops;
126         struct task_struct *task;
127 };
128 
129 static struct ns_common *ns_get_path_task(void *private_data)
130 {
131         struct ns_get_path_task_args *args = private_data;
132 
133         return args->ns_ops->get(args->task);
134 }
135 
136 int ns_get_path(struct path *path, struct task_struct *task,
137                   const struct proc_ns_operations *ns_ops)
138 {
139         struct ns_get_path_task_args args = {
140                 .ns_ops = ns_ops,
141                 .task   = task,
142         };
143 
144         return ns_get_path_cb(path, ns_get_path_task, &args);
145 }
146 
147 int open_related_ns(struct ns_common *ns,
148                    struct ns_common *(*get_ns)(struct ns_common *ns))
149 {
150         struct path path = {};
151         struct file *f;
152         int err;
153         int fd;
154 
155         fd = get_unused_fd_flags(O_CLOEXEC);
156         if (fd < 0)
157                 return fd;
158 
159         do {
160                 struct ns_common *relative;
161 
162                 relative = get_ns(ns);
163                 if (IS_ERR(relative)) {
164                         put_unused_fd(fd);
165                         return PTR_ERR(relative);
166                 }
167 
168                 err = __ns_get_path(&path, relative);
169         } while (err == -EAGAIN);
170 
171         if (err) {
172                 put_unused_fd(fd);
173                 return err;
174         }
175 
176         f = dentry_open(&path, O_RDONLY, current_cred());
177         path_put(&path);
178         if (IS_ERR(f)) {
179                 put_unused_fd(fd);
180                 fd = PTR_ERR(f);
181         } else
182                 fd_install(fd, f);
183 
184         return fd;
185 }
186 EXPORT_SYMBOL_GPL(open_related_ns);
187 
188 static long ns_ioctl(struct file *filp, unsigned int ioctl,
189                         unsigned long arg)
190 {
191         struct user_namespace *user_ns;
192         struct ns_common *ns = get_proc_ns(file_inode(filp));
193         uid_t __user *argp;
194         uid_t uid;
195 
196         switch (ioctl) {
197         case NS_GET_USERNS:
198                 return open_related_ns(ns, ns_get_owner);
199         case NS_GET_PARENT:
200                 if (!ns->ops->get_parent)
201                         return -EINVAL;
202                 return open_related_ns(ns, ns->ops->get_parent);
203         case NS_GET_NSTYPE:
204                 return ns->ops->type;
205         case NS_GET_OWNER_UID:
206                 if (ns->ops->type != CLONE_NEWUSER)
207                         return -EINVAL;
208                 user_ns = container_of(ns, struct user_namespace, ns);
209                 argp = (uid_t __user *) arg;
210                 uid = from_kuid_munged(current_user_ns(), user_ns->owner);
211                 return put_user(uid, argp);
212         default:
213                 return -ENOTTY;
214         }
215 }
216 
217 int ns_get_name(char *buf, size_t size, struct task_struct *task,
218                         const struct proc_ns_operations *ns_ops)
219 {
220         struct ns_common *ns;
221         int res = -ENOENT;
222         const char *name;
223         ns = ns_ops->get(task);
224         if (ns) {
225                 name = ns_ops->real_ns_name ? : ns_ops->name;
226                 res = snprintf(buf, size, "%s:[%u]", name, ns->inum);
227                 ns_ops->put(ns);
228         }
229         return res;
230 }
231 
232 struct file *proc_ns_fget(int fd)
233 {
234         struct file *file;
235 
236         file = fget(fd);
237         if (!file)
238                 return ERR_PTR(-EBADF);
239 
240         if (file->f_op != &ns_file_operations)
241                 goto out_invalid;
242 
243         return file;
244 
245 out_invalid:
246         fput(file);
247         return ERR_PTR(-EINVAL);
248 }
249 
250 static int nsfs_show_path(struct seq_file *seq, struct dentry *dentry)
251 {
252         struct inode *inode = d_inode(dentry);
253         const struct proc_ns_operations *ns_ops = dentry->d_fsdata;
254 
255         seq_printf(seq, "%s:[%lu]", ns_ops->name, inode->i_ino);
256         return 0;
257 }
258 
259 static const struct super_operations nsfs_ops = {
260         .statfs = simple_statfs,
261         .evict_inode = nsfs_evict,
262         .show_path = nsfs_show_path,
263 };
264 
265 static int nsfs_init_fs_context(struct fs_context *fc)
266 {
267         struct pseudo_fs_context *ctx = init_pseudo(fc, NSFS_MAGIC);
268         if (!ctx)
269                 return -ENOMEM;
270         ctx->ops = &nsfs_ops;
271         ctx->dops = &ns_dentry_operations;
272         return 0;
273 }
274 
275 static struct file_system_type nsfs = {
276         .name = "nsfs",
277         .init_fs_context = nsfs_init_fs_context,
278         .kill_sb = kill_anon_super,
279 };
280 
281 void __init nsfs_init(void)
282 {
283         nsfs_mnt = kern_mount(&nsfs);
284         if (IS_ERR(nsfs_mnt))
285                 panic("can't set nsfs up\n");
286         nsfs_mnt->mnt_sb->s_flags &= ~SB_NOUSER;
287 }
288 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp