Fix race between proc_get_inode() and remove_proc_entry()
proc_lookup remove_proc_entry =========== ================= lock_kernel(); spin_lock(&proc_subdir_lock); [find PDE with refcount 0] spin_unlock(&proc_subdir_lock); spin_lock(&proc_subdir_lock); [find PDE with refcount 0] [check refcount and free PDE] spin_unlock(&proc_subdir_lock); proc_get_inode: de_get(de); /* boom */ Signed-off-by: Alexey Dobriyan <adobriyan@openvz.org> Cc: "Eric W. Biederman" <ebiederm@xmission.com> Cc: Oleg Nesterov <oleg@tv-sign.ru> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
Родитель
79c0b2df79
Коммит
7695650a92
|
@ -398,6 +398,7 @@ struct dentry *proc_lookup(struct inode * dir, struct dentry *dentry, struct nam
|
|||
if (!memcmp(dentry->d_name.name, de->name, de->namelen)) {
|
||||
unsigned int ino = de->low_ino;
|
||||
|
||||
de_get(de);
|
||||
spin_unlock(&proc_subdir_lock);
|
||||
error = -EINVAL;
|
||||
inode = proc_get_inode(dir->i_sb, ino, de);
|
||||
|
@ -414,6 +415,7 @@ struct dentry *proc_lookup(struct inode * dir, struct dentry *dentry, struct nam
|
|||
d_add(dentry, inode);
|
||||
return NULL;
|
||||
}
|
||||
de_put(de);
|
||||
return ERR_PTR(error);
|
||||
}
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
|
||||
#include "internal.h"
|
||||
|
||||
static inline struct proc_dir_entry * de_get(struct proc_dir_entry *de)
|
||||
struct proc_dir_entry *de_get(struct proc_dir_entry *de)
|
||||
{
|
||||
if (de)
|
||||
atomic_inc(&de->count);
|
||||
|
@ -31,7 +31,7 @@ static inline struct proc_dir_entry * de_get(struct proc_dir_entry *de)
|
|||
/*
|
||||
* Decrements the use count and checks for deferred deletion.
|
||||
*/
|
||||
static void de_put(struct proc_dir_entry *de)
|
||||
void de_put(struct proc_dir_entry *de)
|
||||
{
|
||||
if (de) {
|
||||
lock_kernel();
|
||||
|
@ -146,11 +146,6 @@ struct inode *proc_get_inode(struct super_block *sb, unsigned int ino,
|
|||
{
|
||||
struct inode * inode;
|
||||
|
||||
/*
|
||||
* Increment the use count so the dir entry can't disappear.
|
||||
*/
|
||||
de_get(de);
|
||||
|
||||
WARN_ON(de && de->deleted);
|
||||
|
||||
if (de != NULL && !try_module_get(de->owner))
|
||||
|
@ -184,7 +179,6 @@ out_ino:
|
|||
if (de != NULL)
|
||||
module_put(de->owner);
|
||||
out_mod:
|
||||
de_put(de);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -199,6 +193,7 @@ int proc_fill_super(struct super_block *s, void *data, int silent)
|
|||
s->s_op = &proc_sops;
|
||||
s->s_time_gran = 1;
|
||||
|
||||
de_get(&proc_root);
|
||||
root_inode = proc_get_inode(s, PROC_ROOT_INO, &proc_root);
|
||||
if (!root_inode)
|
||||
goto out_no_root;
|
||||
|
@ -212,6 +207,7 @@ int proc_fill_super(struct super_block *s, void *data, int silent)
|
|||
out_no_root:
|
||||
printk("proc_read_super: get root inode failed\n");
|
||||
iput(root_inode);
|
||||
de_put(&proc_root);
|
||||
return -ENOMEM;
|
||||
}
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
@ -106,6 +106,9 @@ int task_statm(struct mm_struct *, int *, int *, int *, int *);
|
|||
char *task_mem(struct mm_struct *, char *);
|
||||
void clear_refs_smap(struct mm_struct *mm);
|
||||
|
||||
struct proc_dir_entry *de_get(struct proc_dir_entry *de);
|
||||
void de_put(struct proc_dir_entry *de);
|
||||
|
||||
extern struct proc_dir_entry *create_proc_entry(const char *name, mode_t mode,
|
||||
struct proc_dir_entry *parent);
|
||||
extern void remove_proc_entry(const char *name, struct proc_dir_entry *parent);
|
||||
|
|
Загрузка…
Ссылка в новой задаче