at v3.0 4.2 kB view raw
1#include <linux/proc_fs.h> 2#include <linux/nsproxy.h> 3#include <linux/sched.h> 4#include <linux/ptrace.h> 5#include <linux/fs_struct.h> 6#include <linux/mount.h> 7#include <linux/path.h> 8#include <linux/namei.h> 9#include <linux/file.h> 10#include <linux/utsname.h> 11#include <net/net_namespace.h> 12#include <linux/mnt_namespace.h> 13#include <linux/ipc_namespace.h> 14#include <linux/pid_namespace.h> 15#include "internal.h" 16 17 18static const struct proc_ns_operations *ns_entries[] = { 19#ifdef CONFIG_NET_NS 20 &netns_operations, 21#endif 22#ifdef CONFIG_UTS_NS 23 &utsns_operations, 24#endif 25#ifdef CONFIG_IPC_NS 26 &ipcns_operations, 27#endif 28}; 29 30static const struct file_operations ns_file_operations = { 31 .llseek = no_llseek, 32}; 33 34static struct dentry *proc_ns_instantiate(struct inode *dir, 35 struct dentry *dentry, struct task_struct *task, const void *ptr) 36{ 37 const struct proc_ns_operations *ns_ops = ptr; 38 struct inode *inode; 39 struct proc_inode *ei; 40 struct dentry *error = ERR_PTR(-ENOENT); 41 void *ns; 42 43 inode = proc_pid_make_inode(dir->i_sb, task); 44 if (!inode) 45 goto out; 46 47 ns = ns_ops->get(task); 48 if (!ns) 49 goto out_iput; 50 51 ei = PROC_I(inode); 52 inode->i_mode = S_IFREG|S_IRUSR; 53 inode->i_fop = &ns_file_operations; 54 ei->ns_ops = ns_ops; 55 ei->ns = ns; 56 57 dentry->d_op = &pid_dentry_operations; 58 d_add(dentry, inode); 59 /* Close the race of the process dying before we return the dentry */ 60 if (pid_revalidate(dentry, NULL)) 61 error = NULL; 62out: 63 return error; 64out_iput: 65 iput(inode); 66 goto out; 67} 68 69static int proc_ns_fill_cache(struct file *filp, void *dirent, 70 filldir_t filldir, struct task_struct *task, 71 const struct proc_ns_operations *ops) 72{ 73 return proc_fill_cache(filp, dirent, filldir, 74 ops->name, strlen(ops->name), 75 proc_ns_instantiate, task, ops); 76} 77 78static int proc_ns_dir_readdir(struct file *filp, void *dirent, 79 filldir_t filldir) 80{ 81 int i; 82 struct dentry *dentry = filp->f_path.dentry; 83 struct inode *inode = dentry->d_inode; 84 struct task_struct *task = get_proc_task(inode); 85 const struct proc_ns_operations **entry, **last; 86 ino_t ino; 87 int ret; 88 89 ret = -ENOENT; 90 if (!task) 91 goto out_no_task; 92 93 ret = -EPERM; 94 if (!ptrace_may_access(task, PTRACE_MODE_READ)) 95 goto out; 96 97 ret = 0; 98 i = filp->f_pos; 99 switch (i) { 100 case 0: 101 ino = inode->i_ino; 102 if (filldir(dirent, ".", 1, i, ino, DT_DIR) < 0) 103 goto out; 104 i++; 105 filp->f_pos++; 106 /* fall through */ 107 case 1: 108 ino = parent_ino(dentry); 109 if (filldir(dirent, "..", 2, i, ino, DT_DIR) < 0) 110 goto out; 111 i++; 112 filp->f_pos++; 113 /* fall through */ 114 default: 115 i -= 2; 116 if (i >= ARRAY_SIZE(ns_entries)) { 117 ret = 1; 118 goto out; 119 } 120 entry = ns_entries + i; 121 last = &ns_entries[ARRAY_SIZE(ns_entries) - 1]; 122 while (entry <= last) { 123 if (proc_ns_fill_cache(filp, dirent, filldir, 124 task, *entry) < 0) 125 goto out; 126 filp->f_pos++; 127 entry++; 128 } 129 } 130 131 ret = 1; 132out: 133 put_task_struct(task); 134out_no_task: 135 return ret; 136} 137 138const struct file_operations proc_ns_dir_operations = { 139 .read = generic_read_dir, 140 .readdir = proc_ns_dir_readdir, 141}; 142 143static struct dentry *proc_ns_dir_lookup(struct inode *dir, 144 struct dentry *dentry, struct nameidata *nd) 145{ 146 struct dentry *error; 147 struct task_struct *task = get_proc_task(dir); 148 const struct proc_ns_operations **entry, **last; 149 unsigned int len = dentry->d_name.len; 150 151 error = ERR_PTR(-ENOENT); 152 153 if (!task) 154 goto out_no_task; 155 156 error = ERR_PTR(-EPERM); 157 if (!ptrace_may_access(task, PTRACE_MODE_READ)) 158 goto out; 159 160 last = &ns_entries[ARRAY_SIZE(ns_entries) - 1]; 161 for (entry = ns_entries; entry <= last; entry++) { 162 if (strlen((*entry)->name) != len) 163 continue; 164 if (!memcmp(dentry->d_name.name, (*entry)->name, len)) 165 break; 166 } 167 error = ERR_PTR(-ENOENT); 168 if (entry > last) 169 goto out; 170 171 error = proc_ns_instantiate(dir, dentry, task, *entry); 172out: 173 put_task_struct(task); 174out_no_task: 175 return error; 176} 177 178const struct inode_operations proc_ns_dir_inode_operations = { 179 .lookup = proc_ns_dir_lookup, 180 .getattr = pid_getattr, 181 .setattr = proc_setattr, 182}; 183 184struct file *proc_ns_fget(int fd) 185{ 186 struct file *file; 187 188 file = fget(fd); 189 if (!file) 190 return ERR_PTR(-EBADF); 191 192 if (file->f_op != &ns_file_operations) 193 goto out_invalid; 194 195 return file; 196 197out_invalid: 198 fput(file); 199 return ERR_PTR(-EINVAL); 200} 201