From: Eric W. Biederman proc_lookup and task exiting are not synchronized, although some of the previous code may have suggested that. Every time before we reuse a dentry namei.c calls d_op->derevalidate which prevents us from reusing a stale dcache entry. Unfortunately it does not prevent us from returning a stale dcache entry. This race has been explicitly plugged in proc_pid_lookup but there is nothing to confine it to just that proc lookup function. So to prevent the race I call revalidate explictily in all of the proc lookup functions after I call d_add, and report an error if the revalidate does not succeed. Years ago Al Viro did something similar but those changes got lost in the churn. Signed-off-by: Eric W. Biederman Signed-off-by: Andrew Morton --- fs/proc/base.c | 54 +++++++++++++++++++++++++---------------------- 1 files changed, 29 insertions(+), 25 deletions(-) diff -puN fs/proc/base.c~proc-close-the-race-of-a-process-dying-durning fs/proc/base.c --- devel/fs/proc/base.c~proc-close-the-race-of-a-process-dying-durning 2006-02-27 20:58:56.000000000 -0800 +++ devel-akpm/fs/proc/base.c 2006-02-27 20:58:56.000000000 -0800 @@ -1393,6 +1393,7 @@ static struct dentry *proc_lookupfd(stru { struct task_struct *task = proc_task(dir); unsigned fd = name_to_int(dentry); + struct dentry *result = ERR_PTR(-ENOENT); struct file * file; struct files_struct * files; struct inode *inode; @@ -1427,15 +1428,18 @@ static struct dentry *proc_lookupfd(stru ei->op.proc_get_link = proc_fd_link; dentry->d_op = &tid_fd_dentry_operations; d_add(dentry, inode); - return NULL; + /* Close the race of the process dying before we return the dentry */ + if (tid_fd_revalidate(dentry, NULL)) + result = NULL; +out: + return result; out_unlock2: rcu_read_unlock(); put_files_struct(files); out_unlock: iput(inode); -out: - return ERR_PTR(-ENOENT); + goto out; } static int proc_task_readdir(struct file * filp, void * dirent, filldir_t filldir); @@ -1535,12 +1539,12 @@ static struct dentry *proc_pident_lookup struct pid_entry *ents) { struct inode *inode; - int error; + struct dentry *error; struct task_struct *task = proc_task(dir); struct pid_entry *p; struct proc_inode *ei; - error = -ENOENT; + error = ERR_PTR(-ENOENT); inode = NULL; if (!pid_alive(task)) @@ -1555,7 +1559,7 @@ static struct dentry *proc_pident_lookup if (!p->name) goto out; - error = -EINVAL; + error = ERR_PTR(-EINVAL); inode = proc_pid_make_inode(dir->i_sb, task, p->type); if (!inode) goto out; @@ -1720,14 +1724,16 @@ static struct dentry *proc_pident_lookup default: printk("procfs: impossible type (%d)",p->type); iput(inode); - return ERR_PTR(-EINVAL); + error = ERR_PTR(-EINVAL); + goto out; } dentry->d_op = &pid_dentry_operations; d_add(dentry, inode); - return NULL; - + /* Close the race of the process dying before we return the dentry */ + if (pid_revalidate(dentry, NULL)) + error = NULL; out: - return ERR_PTR(error); + return error; } static struct dentry *proc_tgid_base_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd){ @@ -1895,6 +1901,7 @@ out: /* SMP-safe */ struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd) { + struct dentry *result = ERR_PTR(-ENOENT); struct task_struct *task; struct inode *inode; struct proc_inode *ei; @@ -1928,12 +1935,9 @@ struct dentry *proc_pid_lookup(struct in goto out; inode = proc_pid_make_inode(dir->i_sb, task, PROC_TGID_INO); + if (!inode) + goto out_put_task; - - if (!inode) { - put_task_struct(task); - goto out; - } inode->i_mode = S_IFDIR|S_IRUGO|S_IXUGO; inode->i_op = &proc_tgid_base_inode_operations; inode->i_fop = &proc_tgid_base_operations; @@ -1947,21 +1951,20 @@ struct dentry *proc_pid_lookup(struct in dentry->d_op = &pid_dentry_operations; d_add(dentry, inode); - if (!pid_alive(task)) { - d_drop(dentry); - shrink_dcache_parent(dentry); - goto out; - } + /* Close the race of the process dying before we return the dentry */ + if (pid_revalidate(dentry, NULL)) + result = NULL; +out_put_task: put_task_struct(task); - return NULL; out: - return ERR_PTR(-ENOENT); + return result; } /* SMP-safe */ static struct dentry *proc_task_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd) { + struct dentry *result = ERR_PTR(-ENOENT); struct task_struct *task; struct task_struct *leader = proc_task(dir); struct inode *inode; @@ -1999,13 +2002,14 @@ static struct dentry *proc_task_lookup(s dentry->d_op = &pid_dentry_operations; d_add(dentry, inode); + /* Close the race of the process dying before we return the dentry */ + if (pid_revalidate(dentry, NULL)) + result = NULL; - put_task_struct(task); - return NULL; out_drop_task: put_task_struct(task); out: - return ERR_PTR(-ENOENT); + return result; } #define PROC_NUMBUF 10 _