aboutsummaryrefslogtreecommitdiffstats
path: root/fs/proc/proc_sysctl.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/proc/proc_sysctl.c')
-rw-r--r--fs/proc/proc_sysctl.c35
1 files changed, 24 insertions, 11 deletions
diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c
index 5be436ea088e..d167de365a8d 100644
--- a/fs/proc/proc_sysctl.c
+++ b/fs/proc/proc_sysctl.c
@@ -5,6 +5,7 @@
5#include <linux/sysctl.h> 5#include <linux/sysctl.h>
6#include <linux/proc_fs.h> 6#include <linux/proc_fs.h>
7#include <linux/security.h> 7#include <linux/security.h>
8#include <linux/namei.h>
8#include "internal.h" 9#include "internal.h"
9 10
10static const struct dentry_operations proc_sys_dentry_operations; 11static const struct dentry_operations proc_sys_dentry_operations;
@@ -23,13 +24,14 @@ static struct inode *proc_sys_make_inode(struct super_block *sb,
23 if (!inode) 24 if (!inode)
24 goto out; 25 goto out;
25 26
27 inode->i_ino = get_next_ino();
28
26 sysctl_head_get(head); 29 sysctl_head_get(head);
27 ei = PROC_I(inode); 30 ei = PROC_I(inode);
28 ei->sysctl = head; 31 ei->sysctl = head;
29 ei->sysctl_entry = table; 32 ei->sysctl_entry = table;
30 33
31 inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; 34 inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
32 inode->i_flags |= S_PRIVATE; /* tell selinux to ignore this inode */
33 inode->i_mode = table->mode; 35 inode->i_mode = table->mode;
34 if (!table->child) { 36 if (!table->child) {
35 inode->i_mode |= S_IFREG; 37 inode->i_mode |= S_IFREG;
@@ -118,7 +120,7 @@ static struct dentry *proc_sys_lookup(struct inode *dir, struct dentry *dentry,
118 goto out; 120 goto out;
119 121
120 err = NULL; 122 err = NULL;
121 dentry->d_op = &proc_sys_dentry_operations; 123 d_set_d_op(dentry, &proc_sys_dentry_operations);
122 d_add(dentry, inode); 124 d_add(dentry, inode);
123 125
124out: 126out:
@@ -199,7 +201,7 @@ static int proc_sys_fill_cache(struct file *filp, void *dirent,
199 dput(child); 201 dput(child);
200 return -ENOMEM; 202 return -ENOMEM;
201 } else { 203 } else {
202 child->d_op = &proc_sys_dentry_operations; 204 d_set_d_op(child, &proc_sys_dentry_operations);
203 d_add(child, inode); 205 d_add(child, inode);
204 } 206 }
205 } else { 207 } else {
@@ -292,7 +294,7 @@ out:
292 return ret; 294 return ret;
293} 295}
294 296
295static int proc_sys_permission(struct inode *inode, int mask) 297static int proc_sys_permission(struct inode *inode, int mask,unsigned int flags)
296{ 298{
297 /* 299 /*
298 * sysctl entries that are not writeable, 300 * sysctl entries that are not writeable,
@@ -364,6 +366,7 @@ static int proc_sys_getattr(struct vfsmount *mnt, struct dentry *dentry, struct
364static const struct file_operations proc_sys_file_operations = { 366static const struct file_operations proc_sys_file_operations = {
365 .read = proc_sys_read, 367 .read = proc_sys_read,
366 .write = proc_sys_write, 368 .write = proc_sys_write,
369 .llseek = default_llseek,
367}; 370};
368 371
369static const struct file_operations proc_sys_dir_file_operations = { 372static const struct file_operations proc_sys_dir_file_operations = {
@@ -386,23 +389,33 @@ static const struct inode_operations proc_sys_dir_operations = {
386 389
387static int proc_sys_revalidate(struct dentry *dentry, struct nameidata *nd) 390static int proc_sys_revalidate(struct dentry *dentry, struct nameidata *nd)
388{ 391{
392 if (nd->flags & LOOKUP_RCU)
393 return -ECHILD;
389 return !PROC_I(dentry->d_inode)->sysctl->unregistering; 394 return !PROC_I(dentry->d_inode)->sysctl->unregistering;
390} 395}
391 396
392static int proc_sys_delete(struct dentry *dentry) 397static int proc_sys_delete(const struct dentry *dentry)
393{ 398{
394 return !!PROC_I(dentry->d_inode)->sysctl->unregistering; 399 return !!PROC_I(dentry->d_inode)->sysctl->unregistering;
395} 400}
396 401
397static int proc_sys_compare(struct dentry *dir, struct qstr *qstr, 402static int proc_sys_compare(const struct dentry *parent,
398 struct qstr *name) 403 const struct inode *pinode,
404 const struct dentry *dentry, const struct inode *inode,
405 unsigned int len, const char *str, const struct qstr *name)
399{ 406{
400 struct dentry *dentry = container_of(qstr, struct dentry, d_name); 407 struct ctl_table_header *head;
401 if (qstr->len != name->len) 408 /* Although proc doesn't have negative dentries, rcu-walk means
409 * that inode here can be NULL */
410 /* AV: can it, indeed? */
411 if (!inode)
412 return 1;
413 if (name->len != len)
402 return 1; 414 return 1;
403 if (memcmp(qstr->name, name->name, name->len)) 415 if (memcmp(name->name, str, len))
404 return 1; 416 return 1;
405 return !sysctl_is_seen(PROC_I(dentry->d_inode)->sysctl); 417 head = rcu_dereference(PROC_I(inode)->sysctl);
418 return !head || !sysctl_is_seen(head);
406} 419}
407 420
408static const struct dentry_operations proc_sys_dentry_operations = { 421static const struct dentry_operations proc_sys_dentry_operations = {