Commit 7e0e953bb0cf649f93277ac8fb67ecbb7f7b04a9
1 parent
0db59e5929
Exists in
ti-lsk-linux-4.1.y
and in
10 other branches
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
fs/proc/generic.c
... | ... | @@ -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 |
fs/proc/inode.c
... | ... | @@ -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 | { |
fs/proc/internal.h