Commit 7e0e953bb0cf649f93277ac8fb67ecbb7f7b04a9

Authored by Al Viro
1 parent 0db59e5929

procfs: fix race between symlink removals and traversals

use_pde()/unuse_pde() in ->follow_link()/->put_link() resp.

Cc: stable@vger.kernel.org
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>

Showing 3 changed files with 22 additions and 12 deletions Side-by-side Diff

... ... @@ -19,7 +19,6 @@
19 19 #include <linux/mount.h>
20 20 #include <linux/init.h>
21 21 #include <linux/idr.h>
22   -#include <linux/namei.h>
23 22 #include <linux/bitops.h>
24 23 #include <linux/spinlock.h>
25 24 #include <linux/completion.h>
... ... @@ -222,17 +221,6 @@
222 221 ida_remove(&proc_inum_ida, inum - PROC_DYNAMIC_FIRST);
223 222 spin_unlock_irqrestore(&proc_inum_lock, flags);
224 223 }
225   -
226   -static void *proc_follow_link(struct dentry *dentry, struct nameidata *nd)
227   -{
228   - nd_set_link(nd, __PDE_DATA(dentry->d_inode));
229   - return NULL;
230   -}
231   -
232   -static const struct inode_operations proc_link_inode_operations = {
233   - .readlink = generic_readlink,
234   - .follow_link = proc_follow_link,
235   -};
236 224  
237 225 /*
238 226 * Don't create negative dentries here, return -ENOENT by hand
... ... @@ -23,6 +23,7 @@
23 23 #include <linux/slab.h>
24 24 #include <linux/mount.h>
25 25 #include <linux/magic.h>
  26 +#include <linux/namei.h>
26 27  
27 28 #include <asm/uaccess.h>
28 29  
... ... @@ -392,6 +393,26 @@
392 393 .release = proc_reg_release,
393 394 };
394 395 #endif
  396 +
  397 +static void *proc_follow_link(struct dentry *dentry, struct nameidata *nd)
  398 +{
  399 + struct proc_dir_entry *pde = PDE(dentry->d_inode);
  400 + if (unlikely(!use_pde(pde)))
  401 + return ERR_PTR(-EINVAL);
  402 + nd_set_link(nd, pde->data);
  403 + return pde;
  404 +}
  405 +
  406 +static void proc_put_link(struct dentry *dentry, struct nameidata *nd, void *p)
  407 +{
  408 + unuse_pde(p);
  409 +}
  410 +
  411 +const struct inode_operations proc_link_inode_operations = {
  412 + .readlink = generic_readlink,
  413 + .follow_link = proc_follow_link,
  414 + .put_link = proc_put_link,
  415 +};
395 416  
396 417 struct inode *proc_get_inode(struct super_block *sb, struct proc_dir_entry *de)
397 418 {
... ... @@ -200,6 +200,7 @@
200 200 int closing;
201 201 struct completion *c;
202 202 };
  203 +extern const struct inode_operations proc_link_inode_operations;
203 204  
204 205 extern const struct inode_operations proc_pid_link_inode_operations;
205 206