diff options
Diffstat (limited to 'fs/proc/proc_sysctl.c')
-rw-r--r-- | fs/proc/proc_sysctl.c | 31 |
1 files changed, 21 insertions, 10 deletions
diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c index b652cb00906b..09a1f92a34ef 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 | ||
10 | static const struct dentry_operations proc_sys_dentry_operations; | 11 | static const struct dentry_operations proc_sys_dentry_operations; |
@@ -120,7 +121,7 @@ static struct dentry *proc_sys_lookup(struct inode *dir, struct dentry *dentry, | |||
120 | goto out; | 121 | goto out; |
121 | 122 | ||
122 | err = NULL; | 123 | err = NULL; |
123 | dentry->d_op = &proc_sys_dentry_operations; | 124 | d_set_d_op(dentry, &proc_sys_dentry_operations); |
124 | d_add(dentry, inode); | 125 | d_add(dentry, inode); |
125 | 126 | ||
126 | out: | 127 | out: |
@@ -201,7 +202,7 @@ static int proc_sys_fill_cache(struct file *filp, void *dirent, | |||
201 | dput(child); | 202 | dput(child); |
202 | return -ENOMEM; | 203 | return -ENOMEM; |
203 | } else { | 204 | } else { |
204 | child->d_op = &proc_sys_dentry_operations; | 205 | d_set_d_op(child, &proc_sys_dentry_operations); |
205 | d_add(child, inode); | 206 | d_add(child, inode); |
206 | } | 207 | } |
207 | } else { | 208 | } else { |
@@ -294,7 +295,7 @@ out: | |||
294 | return ret; | 295 | return ret; |
295 | } | 296 | } |
296 | 297 | ||
297 | static int proc_sys_permission(struct inode *inode, int mask) | 298 | static int proc_sys_permission(struct inode *inode, int mask,unsigned int flags) |
298 | { | 299 | { |
299 | /* | 300 | /* |
300 | * sysctl entries that are not writeable, | 301 | * sysctl entries that are not writeable, |
@@ -304,6 +305,9 @@ static int proc_sys_permission(struct inode *inode, int mask) | |||
304 | struct ctl_table *table; | 305 | struct ctl_table *table; |
305 | int error; | 306 | int error; |
306 | 307 | ||
308 | if (flags & IPERM_FLAG_RCU) | ||
309 | return -ECHILD; | ||
310 | |||
307 | /* Executable files are not allowed under /proc/sys/ */ | 311 | /* Executable files are not allowed under /proc/sys/ */ |
308 | if ((mask & MAY_EXEC) && S_ISREG(inode->i_mode)) | 312 | if ((mask & MAY_EXEC) && S_ISREG(inode->i_mode)) |
309 | return -EACCES; | 313 | return -EACCES; |
@@ -389,23 +393,30 @@ static const struct inode_operations proc_sys_dir_operations = { | |||
389 | 393 | ||
390 | static int proc_sys_revalidate(struct dentry *dentry, struct nameidata *nd) | 394 | static int proc_sys_revalidate(struct dentry *dentry, struct nameidata *nd) |
391 | { | 395 | { |
396 | if (nd->flags & LOOKUP_RCU) | ||
397 | return -ECHILD; | ||
392 | return !PROC_I(dentry->d_inode)->sysctl->unregistering; | 398 | return !PROC_I(dentry->d_inode)->sysctl->unregistering; |
393 | } | 399 | } |
394 | 400 | ||
395 | static int proc_sys_delete(struct dentry *dentry) | 401 | static int proc_sys_delete(const struct dentry *dentry) |
396 | { | 402 | { |
397 | return !!PROC_I(dentry->d_inode)->sysctl->unregistering; | 403 | return !!PROC_I(dentry->d_inode)->sysctl->unregistering; |
398 | } | 404 | } |
399 | 405 | ||
400 | static int proc_sys_compare(struct dentry *dir, struct qstr *qstr, | 406 | static int proc_sys_compare(const struct dentry *parent, |
401 | struct qstr *name) | 407 | const struct inode *pinode, |
408 | const struct dentry *dentry, const struct inode *inode, | ||
409 | unsigned int len, const char *str, const struct qstr *name) | ||
402 | { | 410 | { |
403 | struct dentry *dentry = container_of(qstr, struct dentry, d_name); | 411 | /* Although proc doesn't have negative dentries, rcu-walk means |
404 | if (qstr->len != name->len) | 412 | * that inode here can be NULL */ |
413 | if (!inode) | ||
414 | return 0; | ||
415 | if (name->len != len) | ||
405 | return 1; | 416 | return 1; |
406 | if (memcmp(qstr->name, name->name, name->len)) | 417 | if (memcmp(name->name, str, len)) |
407 | return 1; | 418 | return 1; |
408 | return !sysctl_is_seen(PROC_I(dentry->d_inode)->sysctl); | 419 | return !sysctl_is_seen(PROC_I(inode)->sysctl); |
409 | } | 420 | } |
410 | 421 | ||
411 | static const struct dentry_operations proc_sys_dentry_operations = { | 422 | static const struct dentry_operations proc_sys_dentry_operations = { |