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