Commit 9043476f authored by Al Viro's avatar Al Viro

[PATCH] sanitize proc_sysctl

* keep references to ctl_table_head and ctl_table in /proc/sys inodes
* grab the former during operations, use the latter for access to
  entry if that succeeds
* have ->d_compare() check if table should be seen for one who does lookup;
  that allows us to avoid flipping inodes - if we have the same name resolve
  to different things, we'll just keep several dentries and ->d_compare()
  will reject the wrong ones.
* have ->lookup() and ->readdir() scan the table of our inode first, then
  walk all ctl_table_header and scan ->attached_by for those that are
  attached to our directory.
* implement ->getattr().
* get rid of insane amounts of tree-walking
* get rid of the need to know dentry in ->permission() and of the contortions
  induced by that.
Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent ae7edecc
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/smp_lock.h> #include <linux/smp_lock.h>
#include <linux/sysctl.h>
#include <asm/system.h> #include <asm/system.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
...@@ -65,6 +66,8 @@ static void proc_delete_inode(struct inode *inode) ...@@ -65,6 +66,8 @@ static void proc_delete_inode(struct inode *inode)
module_put(de->owner); module_put(de->owner);
de_put(de); de_put(de);
} }
if (PROC_I(inode)->sysctl)
sysctl_head_put(PROC_I(inode)->sysctl);
clear_inode(inode); clear_inode(inode);
} }
...@@ -84,6 +87,8 @@ static struct inode *proc_alloc_inode(struct super_block *sb) ...@@ -84,6 +87,8 @@ static struct inode *proc_alloc_inode(struct super_block *sb)
ei->fd = 0; ei->fd = 0;
ei->op.proc_get_link = NULL; ei->op.proc_get_link = NULL;
ei->pde = NULL; ei->pde = NULL;
ei->sysctl = NULL;
ei->sysctl_entry = NULL;
inode = &ei->vfs_inode; inode = &ei->vfs_inode;
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
return inode; return inode;
......
This diff is collapsed.
...@@ -282,11 +282,16 @@ union proc_op { ...@@ -282,11 +282,16 @@ union proc_op {
struct task_struct *task); struct task_struct *task);
}; };
struct ctl_table_header;
struct ctl_table;
struct proc_inode { struct proc_inode {
struct pid *pid; struct pid *pid;
int fd; int fd;
union proc_op op; union proc_op op;
struct proc_dir_entry *pde; struct proc_dir_entry *pde;
struct ctl_table_header *sysctl;
struct ctl_table *sysctl_entry;
struct inode vfs_inode; struct inode vfs_inode;
}; };
......
...@@ -961,6 +961,7 @@ struct ctl_table_header; ...@@ -961,6 +961,7 @@ struct ctl_table_header;
extern void sysctl_head_get(struct ctl_table_header *); extern void sysctl_head_get(struct ctl_table_header *);
extern void sysctl_head_put(struct ctl_table_header *); extern void sysctl_head_put(struct ctl_table_header *);
extern int sysctl_is_seen(struct ctl_table_header *);
extern struct ctl_table_header *sysctl_head_grab(struct ctl_table_header *); extern struct ctl_table_header *sysctl_head_grab(struct ctl_table_header *);
extern struct ctl_table_header *sysctl_head_next(struct ctl_table_header *prev); extern struct ctl_table_header *sysctl_head_next(struct ctl_table_header *prev);
extern struct ctl_table_header *__sysctl_head_next(struct nsproxy *namespaces, extern struct ctl_table_header *__sysctl_head_next(struct nsproxy *namespaces,
......
...@@ -1932,6 +1932,21 @@ void unregister_sysctl_table(struct ctl_table_header * header) ...@@ -1932,6 +1932,21 @@ void unregister_sysctl_table(struct ctl_table_header * header)
spin_unlock(&sysctl_lock); spin_unlock(&sysctl_lock);
} }
int sysctl_is_seen(struct ctl_table_header *p)
{
struct ctl_table_set *set = p->set;
int res;
spin_lock(&sysctl_lock);
if (p->unregistering)
res = 0;
else if (!set->is_seen)
res = 1;
else
res = set->is_seen(set);
spin_unlock(&sysctl_lock);
return res;
}
void setup_sysctl_set(struct ctl_table_set *p, void setup_sysctl_set(struct ctl_table_set *p,
struct ctl_table_set *parent, struct ctl_table_set *parent,
int (*is_seen)(struct ctl_table_set *)) int (*is_seen)(struct ctl_table_set *))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment