aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/proc/inode.c6
-rw-r--r--fs/proc/namespaces.c169
2 files changed, 152 insertions, 23 deletions
diff --git a/fs/proc/inode.c b/fs/proc/inode.c
index 3b22bbdee9ec..439ae6886507 100644
--- a/fs/proc/inode.c
+++ b/fs/proc/inode.c
@@ -31,6 +31,7 @@ static void proc_evict_inode(struct inode *inode)
31 struct proc_dir_entry *de; 31 struct proc_dir_entry *de;
32 struct ctl_table_header *head; 32 struct ctl_table_header *head;
33 const struct proc_ns_operations *ns_ops; 33 const struct proc_ns_operations *ns_ops;
34 void *ns;
34 35
35 truncate_inode_pages(&inode->i_data, 0); 36 truncate_inode_pages(&inode->i_data, 0);
36 clear_inode(inode); 37 clear_inode(inode);
@@ -49,8 +50,9 @@ static void proc_evict_inode(struct inode *inode)
49 } 50 }
50 /* Release any associated namespace */ 51 /* Release any associated namespace */
51 ns_ops = PROC_I(inode)->ns_ops; 52 ns_ops = PROC_I(inode)->ns_ops;
52 if (ns_ops && ns_ops->put) 53 ns = PROC_I(inode)->ns;
53 ns_ops->put(PROC_I(inode)->ns); 54 if (ns_ops && ns)
55 ns_ops->put(ns);
54} 56}
55 57
56static struct kmem_cache * proc_inode_cachep; 58static struct kmem_cache * proc_inode_cachep;
diff --git a/fs/proc/namespaces.c b/fs/proc/namespaces.c
index 030250c27d70..7a6d8d69cdb8 100644
--- a/fs/proc/namespaces.c
+++ b/fs/proc/namespaces.c
@@ -38,6 +38,151 @@ static const struct file_operations ns_file_operations = {
38 .llseek = no_llseek, 38 .llseek = no_llseek,
39}; 39};
40 40
41static const struct inode_operations ns_inode_operations = {
42 .setattr = proc_setattr,
43};
44
45static int ns_delete_dentry(const struct dentry *dentry)
46{
47 /* Don't cache namespace inodes when not in use */
48 return 1;
49}
50
51static char *ns_dname(struct dentry *dentry, char *buffer, int buflen)
52{
53 struct inode *inode = dentry->d_inode;
54 const struct proc_ns_operations *ns_ops = PROC_I(inode)->ns_ops;
55
56 return dynamic_dname(dentry, buffer, buflen, "%s:[%lu]",
57 ns_ops->name, inode->i_ino);
58}
59
60const struct dentry_operations ns_dentry_operations =
61{
62 .d_delete = ns_delete_dentry,
63 .d_dname = ns_dname,
64};
65
66static struct dentry *proc_ns_get_dentry(struct super_block *sb,
67 struct task_struct *task, const struct proc_ns_operations *ns_ops)
68{
69 struct dentry *dentry, *result;
70 struct inode *inode;
71 struct proc_inode *ei;
72 struct qstr qname = { .name = "", };
73 void *ns;
74
75 ns = ns_ops->get(task);
76 if (!ns)
77 return ERR_PTR(-ENOENT);
78
79 dentry = d_alloc_pseudo(sb, &qname);
80 if (!dentry) {
81 ns_ops->put(ns);
82 return ERR_PTR(-ENOMEM);
83 }
84
85 inode = new_inode(sb);
86 if (!inode) {
87 dput(dentry);
88 ns_ops->put(ns);
89 return ERR_PTR(-ENOMEM);
90 }
91
92 ei = PROC_I(inode);
93 inode->i_ino = get_next_ino();
94 inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
95 inode->i_op = &ns_inode_operations;
96 inode->i_mode = S_IFREG | S_IRUGO;
97 inode->i_fop = &ns_file_operations;
98 ei->ns_ops = ns_ops;
99 ei->ns = ns;
100
101 d_set_d_op(dentry, &ns_dentry_operations);
102 result = d_instantiate_unique(dentry, inode);
103 if (result) {
104 dput(dentry);
105 dentry = result;
106 }
107
108 return dentry;
109}
110
111static void *proc_ns_follow_link(struct dentry *dentry, struct nameidata *nd)
112{
113 struct inode *inode = dentry->d_inode;
114 struct super_block *sb = inode->i_sb;
115 struct proc_inode *ei = PROC_I(inode);
116 struct task_struct *task;
117 struct dentry *ns_dentry;
118 void *error = ERR_PTR(-EACCES);
119
120 task = get_proc_task(inode);
121 if (!task)
122 goto out;
123
124 if (!ptrace_may_access(task, PTRACE_MODE_READ))
125 goto out_put_task;
126
127 ns_dentry = proc_ns_get_dentry(sb, task, ei->ns_ops);
128 if (IS_ERR(ns_dentry)) {
129 error = ERR_CAST(ns_dentry);
130 goto out_put_task;
131 }
132
133 dput(nd->path.dentry);
134 nd->path.dentry = ns_dentry;
135 error = NULL;
136
137out_put_task:
138 put_task_struct(task);
139out:
140 return error;
141}
142
143static int proc_ns_readlink(struct dentry *dentry, char __user *buffer, int buflen)
144{
145 struct inode *inode = dentry->d_inode;
146 struct proc_inode *ei = PROC_I(inode);
147 const struct proc_ns_operations *ns_ops = ei->ns_ops;
148 struct task_struct *task;
149 void *ns;
150 char name[50];
151 int len = -EACCES;
152
153 task = get_proc_task(inode);
154 if (!task)
155 goto out;
156
157 if (!ptrace_may_access(task, PTRACE_MODE_READ))
158 goto out_put_task;
159
160 len = -ENOENT;
161 ns = ns_ops->get(task);
162 if (!ns)
163 goto out_put_task;
164
165 snprintf(name, sizeof(name), "%s", ns_ops->name);
166 len = strlen(name);
167
168 if (len > buflen)
169 len = buflen;
170 if (copy_to_user(buffer, ns_ops->name, len))
171 len = -EFAULT;
172
173 ns_ops->put(ns);
174out_put_task:
175 put_task_struct(task);
176out:
177 return len;
178}
179
180static const struct inode_operations proc_ns_link_inode_operations = {
181 .readlink = proc_ns_readlink,
182 .follow_link = proc_ns_follow_link,
183 .setattr = proc_setattr,
184};
185
41static struct dentry *proc_ns_instantiate(struct inode *dir, 186static struct dentry *proc_ns_instantiate(struct inode *dir,
42 struct dentry *dentry, struct task_struct *task, const void *ptr) 187 struct dentry *dentry, struct task_struct *task, const void *ptr)
43{ 188{
@@ -45,21 +190,15 @@ static struct dentry *proc_ns_instantiate(struct inode *dir,
45 struct inode *inode; 190 struct inode *inode;
46 struct proc_inode *ei; 191 struct proc_inode *ei;
47 struct dentry *error = ERR_PTR(-ENOENT); 192 struct dentry *error = ERR_PTR(-ENOENT);
48 void *ns;
49 193
50 inode = proc_pid_make_inode(dir->i_sb, task); 194 inode = proc_pid_make_inode(dir->i_sb, task);
51 if (!inode) 195 if (!inode)
52 goto out; 196 goto out;
53 197
54 ns = ns_ops->get(task);
55 if (!ns)
56 goto out_iput;
57
58 ei = PROC_I(inode); 198 ei = PROC_I(inode);
59 inode->i_mode = S_IFREG|S_IRUSR; 199 inode->i_mode = S_IFLNK|S_IRWXUGO;
60 inode->i_fop = &ns_file_operations; 200 inode->i_op = &proc_ns_link_inode_operations;
61 ei->ns_ops = ns_ops; 201 ei->ns_ops = ns_ops;
62 ei->ns = ns;
63 202
64 d_set_d_op(dentry, &pid_dentry_operations); 203 d_set_d_op(dentry, &pid_dentry_operations);
65 d_add(dentry, inode); 204 d_add(dentry, inode);
@@ -68,9 +207,6 @@ static struct dentry *proc_ns_instantiate(struct inode *dir,
68 error = NULL; 207 error = NULL;
69out: 208out:
70 return error; 209 return error;
71out_iput:
72 iput(inode);
73 goto out;
74} 210}
75 211
76static int proc_ns_fill_cache(struct file *filp, void *dirent, 212static int proc_ns_fill_cache(struct file *filp, void *dirent,
@@ -97,10 +233,6 @@ static int proc_ns_dir_readdir(struct file *filp, void *dirent,
97 if (!task) 233 if (!task)
98 goto out_no_task; 234 goto out_no_task;
99 235
100 ret = -EPERM;
101 if (!ptrace_may_access(task, PTRACE_MODE_READ))
102 goto out;
103
104 ret = 0; 236 ret = 0;
105 i = filp->f_pos; 237 i = filp->f_pos;
106 switch (i) { 238 switch (i) {
@@ -160,10 +292,6 @@ static struct dentry *proc_ns_dir_lookup(struct inode *dir,
160 if (!task) 292 if (!task)
161 goto out_no_task; 293 goto out_no_task;
162 294
163 error = ERR_PTR(-EPERM);
164 if (!ptrace_may_access(task, PTRACE_MODE_READ))
165 goto out;
166
167 last = &ns_entries[ARRAY_SIZE(ns_entries)]; 295 last = &ns_entries[ARRAY_SIZE(ns_entries)];
168 for (entry = ns_entries; entry < last; entry++) { 296 for (entry = ns_entries; entry < last; entry++) {
169 if (strlen((*entry)->name) != len) 297 if (strlen((*entry)->name) != len)
@@ -171,7 +299,6 @@ static struct dentry *proc_ns_dir_lookup(struct inode *dir,
171 if (!memcmp(dentry->d_name.name, (*entry)->name, len)) 299 if (!memcmp(dentry->d_name.name, (*entry)->name, len))
172 break; 300 break;
173 } 301 }
174 error = ERR_PTR(-ENOENT);
175 if (entry == last) 302 if (entry == last)
176 goto out; 303 goto out;
177 304