Skip to content

Commit 1da4d37

Browse files
Alexey Dobriyantorvalds
authored andcommitted
proc: revalidate misc dentries
If module removes proc directory while another process pins it by chdir'ing to it, then subsequent recreation of proc entry and all entries down the tree will not be visible to any process until pinning process unchdir from directory and unpins everything. Steps to reproduce: proc_mkdir("aaa", NULL); proc_create("aaa/bbb", ...); chdir("/proc/aaa"); remove_proc_entry("aaa/bbb", NULL); remove_proc_entry("aaa", NULL); proc_mkdir("aaa", NULL); # inaccessible because "aaa" dentry still points # to the original "aaa". proc_create("aaa/bbb", ...); Fix is to implement ->d_revalidate and ->d_delete. Link: http://lkml.kernel.org/r/20180312201938.GA4871@avx2 Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com> Cc: Al Viro <viro@zeniv.linux.org.uk> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
1 parent a9f2a84 commit 1da4d37

File tree

1 file changed

+22
-1
lines changed

1 file changed

+22
-1
lines changed

fs/proc/generic.c

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include <linux/stat.h>
1616
#include <linux/mm.h>
1717
#include <linux/module.h>
18+
#include <linux/namei.h>
1819
#include <linux/slab.h>
1920
#include <linux/printk.h>
2021
#include <linux/mount.h>
@@ -217,6 +218,26 @@ void proc_free_inum(unsigned int inum)
217218
ida_simple_remove(&proc_inum_ida, inum - PROC_DYNAMIC_FIRST);
218219
}
219220

221+
static int proc_misc_d_revalidate(struct dentry *dentry, unsigned int flags)
222+
{
223+
if (flags & LOOKUP_RCU)
224+
return -ECHILD;
225+
226+
if (atomic_read(&PDE(d_inode(dentry))->in_use) < 0)
227+
return 0; /* revalidate */
228+
return 1;
229+
}
230+
231+
static int proc_misc_d_delete(const struct dentry *dentry)
232+
{
233+
return atomic_read(&PDE(d_inode(dentry))->in_use) < 0;
234+
}
235+
236+
static const struct dentry_operations proc_misc_dentry_ops = {
237+
.d_revalidate = proc_misc_d_revalidate,
238+
.d_delete = proc_misc_d_delete,
239+
};
240+
220241
/*
221242
* Don't create negative dentries here, return -ENOENT by hand
222243
* instead.
@@ -234,7 +255,7 @@ struct dentry *proc_lookup_de(struct inode *dir, struct dentry *dentry,
234255
inode = proc_get_inode(dir->i_sb, de);
235256
if (!inode)
236257
return ERR_PTR(-ENOMEM);
237-
d_set_d_op(dentry, &simple_dentry_operations);
258+
d_set_d_op(dentry, &proc_misc_dentry_ops);
238259
d_add(dentry, inode);
239260
return NULL;
240261
}

0 commit comments

Comments
 (0)