From a93fabd3f90062015859589ee8bf249a1d76a99b Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Mon, 29 Dec 2003 05:44:02 -0800 Subject: [PATCH] [PATCH] Fix proc_pid_lookup vs exit race From: Manfred Spraul Fixes a race between proc_pid_lookup and sys_exit. - The inodes and dentries for /proc//whatever are cached in the dentry cache. d_revalidate is used to protect against stale data: d_revalidate returns invalid if the task exited. Additionally, sys_exit flushes the dentries for the task that died - otherwise the dentries would stay around until they arrive at the end of the LRU, which could take some time. But there is one race: - proc_pid_lookup finds a task and prepares new dentries for it. It must drop all locks for that operation. - the process exits, and the /proc/ dentries are flushed. Nothing happens, because they are not yet in the hash tables. - proc_pid_lookup adds the task to the dentry cache. Result: dentry of a dead task in the hash tables. The patch fixes that problem by flushing again if proc_pid_lookup notices that the thread exited while it created the dentry. The patch should go in, but it's not critical. - task->proc_dentry must be the dentry of /proc/. That way sys_exit can flush the whole subtree at exit time. proc_task_lookup is a direct copy of proc_pid_lookup and handles /proc/<>/task/. It contains the lines that set task->proc_dentry. This is bogus, and must be removed. This hunk is much more critical, because creates a de-facto dentry leak (they are recovered after flushing real dentries from the cache). --- fs/proc/base.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/fs/proc/base.c b/fs/proc/base.c index b04942e0746b0..f16a555f79339 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -1555,6 +1555,7 @@ struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, struct struct inode *inode; struct proc_inode *ei; unsigned tgid; + int died; if (dentry->d_name.len == 4 && !memcmp(dentry->d_name.name,"self",4)) { inode = new_inode(dir->i_sb); @@ -1598,12 +1599,21 @@ struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, struct dentry->d_op = &pid_base_dentry_operations; + died = 0; + d_add(dentry, inode); spin_lock(&task->proc_lock); task->proc_dentry = dentry; - d_add(dentry, inode); + if (!pid_alive(task)) { + dentry = proc_pid_unhash(task); + died = 1; + } spin_unlock(&task->proc_lock); put_task_struct(task); + if (died) { + proc_pid_flush(dentry); + goto out; + } return NULL; out: return ERR_PTR(-ENOENT); @@ -1643,10 +1653,7 @@ static struct dentry *proc_task_lookup(struct inode *dir, struct dentry * dentry dentry->d_op = &pid_base_dentry_operations; - spin_lock(&task->proc_lock); - task->proc_dentry = dentry; d_add(dentry, inode); - spin_unlock(&task->proc_lock); put_task_struct(task); return NULL; -- 2.53.0