[PATCH] Fix vfs_unlink/NFS NULL pointer dereference

Linux Kernel Mailing List <[email protected]> Wed, 21 Jun 2006 16:59:02 GMT
Newsgroups gmane.linux.kernel.commits.2-4
Message-ID <[email protected]>
commit 3a1250af4913b54940efaa32ca84d60fcd97990d
tree 4609b2df80dee13ff505b54d078deb07ff6667e9
parent 0e978d63375d579260d1eb930f5954f96cd37b7f
author Willy Tarreau <[email protected]> Tue, 20 Jun 2006 01:00:07 +0200
committer Marcelo Tosatti <[email protected]> Tue, 20 Jun 2006 17:43:55 -0300

[PATCH] Fix vfs_unlink/NFS NULL pointer dereference

v2.4.33-pre introduced a fix for lack of synchronization between
link/unlink which requires vfs_unlink to grab i_zombie of both the
victim and its parent with double_down().

Problem is that NFS client deletes the victim dentry on ->unlink,
resulting in a NULL dereference when vfs_unlink() tries to up
dentry->d_inode->i_zombie.

Keep a copy of the inode pointer, incrementing its reference counter, to
fix the situation.

Signed-off-by: Marcelo Tosatti <[email protected]>

 fs/namei.c |   10 ++++++++--
 1 files changed, 8 insertions(+), 2 deletions(-)

diff --git a/fs/namei.c b/fs/namei.c
index 42cce98..374b767 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -1478,12 +1478,16 @@ exit:
 int vfs_unlink(struct inode *dir, struct dentry *dentry)
 {
 	int error;
+	struct inode *inode;
 
 	error = may_delete(dir, dentry, 0);
 	if (error)
 		return error;
 
-	double_down(&dir->i_zombie, &dentry->d_inode->i_zombie);
+	inode = dentry->d_inode;
+	atomic_inc(&inode->i_count);
+	double_down(&dir->i_zombie, &inode->i_zombie);
+
 	error = -EPERM;
 	if (dir->i_op && dir->i_op->unlink) {
 		DQUOT_INIT(dir);
@@ -1495,7 +1499,9 @@ int vfs_unlink(struct inode *dir, struct
 			unlock_kernel();
 		}
 	}
-	double_up(&dir->i_zombie, &dentry->d_inode->i_zombie);
+	double_up(&dir->i_zombie, &inode->i_zombie);
+	iput(inode);
+
 	if (!error) {
 		d_delete(dentry);
 		inode_dir_notify(dir, DN_DELETE);