sysctl: merge equal proc_sys_read and proc_sys_write
[linux-2.6.git] / fs / proc / proc_sysctl.c
1 /*
2  * /proc/sys support
3  */
4
5 #include <linux/sysctl.h>
6 #include <linux/proc_fs.h>
7 #include <linux/security.h>
8 #include "internal.h"
9
10 static struct dentry_operations proc_sys_dentry_operations;
11 static const struct file_operations proc_sys_file_operations;
12 static const struct inode_operations proc_sys_inode_operations;
13
14 static void proc_sys_refresh_inode(struct inode *inode, struct ctl_table *table)
15 {
16         /* Refresh the cached information bits in the inode */
17         if (table) {
18                 inode->i_uid = 0;
19                 inode->i_gid = 0;
20                 inode->i_mode = table->mode;
21                 if (table->proc_handler) {
22                         inode->i_mode |= S_IFREG;
23                         inode->i_nlink = 1;
24                 } else {
25                         inode->i_mode |= S_IFDIR;
26                         inode->i_nlink = 0;     /* It is too hard to figure out */
27                 }
28         }
29 }
30
31 static struct inode *proc_sys_make_inode(struct inode *dir, struct ctl_table *table)
32 {
33         struct inode *inode;
34         struct proc_inode *dir_ei, *ei;
35         int depth;
36
37         inode = new_inode(dir->i_sb);
38         if (!inode)
39                 goto out;
40
41         /* A directory is always one deeper than it's parent */
42         dir_ei = PROC_I(dir);
43         depth = dir_ei->fd + 1;
44
45         ei = PROC_I(inode);
46         ei->fd = depth;
47         inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
48         inode->i_op = &proc_sys_inode_operations;
49         inode->i_fop = &proc_sys_file_operations;
50         inode->i_flags |= S_PRIVATE; /* tell selinux to ignore this inode */
51         proc_sys_refresh_inode(inode, table);
52 out:
53         return inode;
54 }
55
56 static struct dentry *proc_sys_ancestor(struct dentry *dentry, int depth)
57 {
58         for (;;) {
59                 struct proc_inode *ei;
60
61                 ei = PROC_I(dentry->d_inode);
62                 if (ei->fd == depth)
63                         break; /* found */
64
65                 dentry = dentry->d_parent;
66         }
67         return dentry;
68 }
69
70 static struct ctl_table *proc_sys_lookup_table_one(struct ctl_table *table,
71                                                         struct qstr *name)
72 {
73         int len;
74         for ( ; table->ctl_name || table->procname; table++) {
75
76                 if (!table->procname)
77                         continue;
78
79                 len = strlen(table->procname);
80                 if (len != name->len)
81                         continue;
82
83                 if (memcmp(table->procname, name->name, len) != 0)
84                         continue;
85
86                 /* I have a match */
87                 return table;
88         }
89         return NULL;
90 }
91
92 static struct ctl_table *proc_sys_lookup_table(struct dentry *dentry,
93                                                 struct ctl_table *table)
94 {
95         struct dentry *ancestor;
96         struct proc_inode *ei;
97         int depth, i;
98
99         ei = PROC_I(dentry->d_inode);
100         depth = ei->fd;
101
102         if (depth == 0)
103                 return table;
104
105         for (i = 1; table && (i <= depth); i++) {
106                 ancestor = proc_sys_ancestor(dentry, i);
107                 table = proc_sys_lookup_table_one(table, &ancestor->d_name);
108                 if (table)
109                         table = table->child;
110         }
111         return table;
112
113 }
114 static struct ctl_table *proc_sys_lookup_entry(struct dentry *dparent,
115                                                 struct qstr *name,
116                                                 struct ctl_table *table)
117 {
118         table = proc_sys_lookup_table(dparent, table);
119         if (table)
120                 table = proc_sys_lookup_table_one(table, name);
121         return table;
122 }
123
124 static struct ctl_table *do_proc_sys_lookup(struct dentry *parent,
125                                                 struct qstr *name,
126                                                 struct ctl_table_header **ptr)
127 {
128         struct ctl_table_header *head;
129         struct ctl_table *table = NULL;
130
131         for (head = sysctl_head_next(NULL); head;
132                         head = sysctl_head_next(head)) {
133                 table = proc_sys_lookup_entry(parent, name, head->ctl_table);
134                 if (table)
135                         break;
136         }
137         *ptr = head;
138         return table;
139 }
140
141 static struct dentry *proc_sys_lookup(struct inode *dir, struct dentry *dentry,
142                                         struct nameidata *nd)
143 {
144         struct ctl_table_header *head;
145         struct inode *inode;
146         struct dentry *err;
147         struct ctl_table *table;
148
149         err = ERR_PTR(-ENOENT);
150         table = do_proc_sys_lookup(dentry->d_parent, &dentry->d_name, &head);
151         if (!table)
152                 goto out;
153
154         err = ERR_PTR(-ENOMEM);
155         inode = proc_sys_make_inode(dir, table);
156         if (!inode)
157                 goto out;
158
159         err = NULL;
160         dentry->d_op = &proc_sys_dentry_operations;
161         d_add(dentry, inode);
162
163 out:
164         sysctl_head_finish(head);
165         return err;
166 }
167
168 static ssize_t proc_sys_call_handler(struct file *filp, void __user *buf,
169                 size_t count, loff_t *ppos, int write)
170 {
171         struct dentry *dentry = filp->f_dentry;
172         struct ctl_table_header *head;
173         struct ctl_table *table;
174         ssize_t error;
175         size_t res;
176
177         table = do_proc_sys_lookup(dentry->d_parent, &dentry->d_name, &head);
178         /* Has the sysctl entry disappeared on us? */
179         error = -ENOENT;
180         if (!table)
181                 goto out;
182
183         /* Has the sysctl entry been replaced by a directory? */
184         error = -EISDIR;
185         if (!table->proc_handler)
186                 goto out;
187
188         /*
189          * At this point we know that the sysctl was not unregistered
190          * and won't be until we finish.
191          */
192         error = -EPERM;
193         if (sysctl_perm(table, write ? MAY_WRITE : MAY_READ))
194                 goto out;
195
196         /* careful: calling conventions are nasty here */
197         res = count;
198         error = table->proc_handler(table, write, filp, buf, &res, ppos);
199         if (!error)
200                 error = res;
201 out:
202         sysctl_head_finish(head);
203
204         return error;
205 }
206
207 static ssize_t proc_sys_read(struct file *filp, char __user *buf,
208                                 size_t count, loff_t *ppos)
209 {
210         return proc_sys_call_handler(filp, (void __user *)buf, count, ppos, 0);
211 }
212
213 static ssize_t proc_sys_write(struct file *filp, const char __user *buf,
214                                 size_t count, loff_t *ppos)
215 {
216         return proc_sys_call_handler(filp, (void __user *)buf, count, ppos, 1);
217 }
218
219
220 static int proc_sys_fill_cache(struct file *filp, void *dirent,
221                                 filldir_t filldir, struct ctl_table *table)
222 {
223         struct ctl_table_header *head;
224         struct ctl_table *child_table = NULL;
225         struct dentry *child, *dir = filp->f_path.dentry;
226         struct inode *inode;
227         struct qstr qname;
228         ino_t ino = 0;
229         unsigned type = DT_UNKNOWN;
230         int ret;
231
232         qname.name = table->procname;
233         qname.len  = strlen(table->procname);
234         qname.hash = full_name_hash(qname.name, qname.len);
235
236         /* Suppress duplicates.
237          * Only fill a directory entry if it is the value that
238          * an ordinary lookup of that name returns.  Hide all
239          * others.
240          *
241          * If we ever cache this translation in the dcache
242          * I should do a dcache lookup first.  But for now
243          * it is just simpler not to.
244          */
245         ret = 0;
246         child_table = do_proc_sys_lookup(dir, &qname, &head);
247         sysctl_head_finish(head);
248         if (child_table != table)
249                 return 0;
250
251         child = d_lookup(dir, &qname);
252         if (!child) {
253                 struct dentry *new;
254                 new = d_alloc(dir, &qname);
255                 if (new) {
256                         inode = proc_sys_make_inode(dir->d_inode, table);
257                         if (!inode)
258                                 child = ERR_PTR(-ENOMEM);
259                         else {
260                                 new->d_op = &proc_sys_dentry_operations;
261                                 d_add(new, inode);
262                         }
263                         if (child)
264                                 dput(new);
265                         else
266                                 child = new;
267                 }
268         }
269         if (!child || IS_ERR(child) || !child->d_inode)
270                 goto end_instantiate;
271         inode = child->d_inode;
272         if (inode) {
273                 ino  = inode->i_ino;
274                 type = inode->i_mode >> 12;
275         }
276         dput(child);
277 end_instantiate:
278         if (!ino)
279                 ino= find_inode_number(dir, &qname);
280         if (!ino)
281                 ino = 1;
282         return filldir(dirent, qname.name, qname.len, filp->f_pos, ino, type);
283 }
284
285 static int proc_sys_readdir(struct file *filp, void *dirent, filldir_t filldir)
286 {
287         struct dentry *dentry = filp->f_dentry;
288         struct inode *inode = dentry->d_inode;
289         struct ctl_table_header *head = NULL;
290         struct ctl_table *table;
291         unsigned long pos;
292         int ret;
293
294         ret = -ENOTDIR;
295         if (!S_ISDIR(inode->i_mode))
296                 goto out;
297
298         ret = 0;
299         /* Avoid a switch here: arm builds fail with missing __cmpdi2 */
300         if (filp->f_pos == 0) {
301                 if (filldir(dirent, ".", 1, filp->f_pos,
302                                 inode->i_ino, DT_DIR) < 0)
303                         goto out;
304                 filp->f_pos++;
305         }
306         if (filp->f_pos == 1) {
307                 if (filldir(dirent, "..", 2, filp->f_pos,
308                                 parent_ino(dentry), DT_DIR) < 0)
309                         goto out;
310                 filp->f_pos++;
311         }
312         pos = 2;
313
314         /* - Find each instance of the directory
315          * - Read all entries in each instance
316          * - Before returning an entry to user space lookup the entry
317          *   by name and if I find a different entry don't return
318          *   this one because it means it is a buried dup.
319          * For sysctl this should only happen for directory entries.
320          */
321         for (head = sysctl_head_next(NULL); head; head = sysctl_head_next(head)) {
322                 table = proc_sys_lookup_table(dentry, head->ctl_table);
323
324                 if (!table)
325                         continue;
326
327                 for (; table->ctl_name || table->procname; table++, pos++) {
328                         /* Can't do anything without a proc name */
329                         if (!table->procname)
330                                 continue;
331
332                         if (pos < filp->f_pos)
333                                 continue;
334
335                         if (proc_sys_fill_cache(filp, dirent, filldir, table) < 0)
336                                 goto out;
337                         filp->f_pos = pos + 1;
338                 }
339         }
340         ret = 1;
341 out:
342         sysctl_head_finish(head);
343         return ret;
344 }
345
346 static int proc_sys_permission(struct inode *inode, int mask, struct nameidata *nd)
347 {
348         /*
349          * sysctl entries that are not writeable,
350          * are _NOT_ writeable, capabilities or not.
351          */
352         struct ctl_table_header *head;
353         struct ctl_table *table;
354         struct dentry *dentry;
355         int mode;
356         int depth;
357         int error;
358
359         head = NULL;
360         depth = PROC_I(inode)->fd;
361
362         /* First check the cached permissions, in case we don't have
363          * enough information to lookup the sysctl table entry.
364          */
365         error = -EACCES;
366         mode = inode->i_mode;
367
368         if (current->euid == 0)
369                 mode >>= 6;
370         else if (in_group_p(0))
371                 mode >>= 3;
372
373         if ((mode & mask & (MAY_READ|MAY_WRITE|MAY_EXEC)) == mask)
374                 error = 0;
375
376         /* If we can't get a sysctl table entry the permission
377          * checks on the cached mode will have to be enough.
378          */
379         if (!nd || !depth)
380                 goto out;
381
382         dentry = nd->path.dentry;
383         table = do_proc_sys_lookup(dentry->d_parent, &dentry->d_name, &head);
384
385         /* If the entry does not exist deny permission */
386         error = -EACCES;
387         if (!table)
388                 goto out;
389
390         /* Use the permissions on the sysctl table entry */
391         error = sysctl_perm(table, mask);
392 out:
393         sysctl_head_finish(head);
394         return error;
395 }
396
397 static int proc_sys_setattr(struct dentry *dentry, struct iattr *attr)
398 {
399         struct inode *inode = dentry->d_inode;
400         int error;
401
402         if (attr->ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID))
403                 return -EPERM;
404
405         error = inode_change_ok(inode, attr);
406         if (!error)
407                 error = inode_setattr(inode, attr);
408
409         return error;
410 }
411
412 /* I'm lazy and don't distinguish between files and directories,
413  * until access time.
414  */
415 static const struct file_operations proc_sys_file_operations = {
416         .read           = proc_sys_read,
417         .write          = proc_sys_write,
418         .readdir        = proc_sys_readdir,
419 };
420
421 static const struct inode_operations proc_sys_inode_operations = {
422         .lookup         = proc_sys_lookup,
423         .permission     = proc_sys_permission,
424         .setattr        = proc_sys_setattr,
425 };
426
427 static int proc_sys_revalidate(struct dentry *dentry, struct nameidata *nd)
428 {
429         struct ctl_table_header *head;
430         struct ctl_table *table;
431         table = do_proc_sys_lookup(dentry->d_parent, &dentry->d_name, &head);
432         proc_sys_refresh_inode(dentry->d_inode, table);
433         sysctl_head_finish(head);
434         return !!table;
435 }
436
437 static struct dentry_operations proc_sys_dentry_operations = {
438         .d_revalidate   = proc_sys_revalidate,
439 };
440
441 static struct proc_dir_entry *proc_sys_root;
442
443 int proc_sys_init(void)
444 {
445         proc_sys_root = proc_mkdir("sys", NULL);
446         proc_sys_root->proc_iops = &proc_sys_inode_operations;
447         proc_sys_root->proc_fops = &proc_sys_file_operations;
448         proc_sys_root->nlink = 0;
449         return 0;
450 }