[PATCH] link_path_walk refcount problem allows umount of active filesystem

Linux Kernel Mailing List <[email protected]> Fri, 25 Mar 2005 19:58:30 +0000
Newsgroups gmane.linux.kernel.commits.2-4
Message-ID <[email protected]>
ChangeSet 1.1478, 2005/03/25 16:58:30-03:00, [email protected]

	[PATCH] link_path_walk refcount problem allows umount of active filesystem
	
	--=-fPp/ESy58Gj/36RjsLWj
	Content-Transfer-Encoding: 7bit
	Content-Type: text/plain
	
	G'day,
	
	The attached patch fixes a bug in the VFS code which causes
	"Busy inodes after unmount" and a subsequent oops.
	
	Greg.
	--
	Greg Banks, R&D Software Engineer, SGI Australian Software Group.
	I don't speak for SGI.
	
	
	--=-fPp/ESy58Gj/36RjsLWj
	Content-Transfer-Encoding: 7bit
	Content-Type: text/x-patch; name=sgi932676-fix-link-following-vfsmount-refcount-bug.patch; charset=ISO-8859-1
	Content-Disposition: attachment; filename=sgi932676-fix-link-following-vfsmount-refcount-bug.patch
	
	Following an absolute symlink opens a window during which the
	filesystem containing the symlink has an outstanding dentry count
	and no outstanding vfsmount count.  A umount() of the filesystem can
	(incorrectly) proceed, resulting in the "Busy inodes after unmount"
	message and an oops shortly thereafter.
	
	Systems using autofs-controlled NFS mounts are especially vulnerable,
	as autofs both increases the number of unmounts happening and does NFS
	mounting in response to lookups which can result in multiple-second
	vulnerability windows.  However the bug could happen on any filesystem.
	
	This patch adds a mntget()/mntput() pair around the link following code
	(as the 2.6 code does).  Attempts to umount() during link following
	now return EBUSY.
	
	
	Signed-off-by: Greg Banks <[email protected]>



 namei.c |    7 +++++++
 1 files changed, 7 insertions(+)


diff -Nru a/fs/namei.c b/fs/namei.c
--- a/fs/namei.c	2005-03-25 20:04:03 -08:00
+++ b/fs/namei.c	2005-03-25 20:04:03 -08:00
@@ -540,8 +540,10 @@
 			goto out_dput;
 
 		if (inode->i_op->follow_link) {
+			struct vfsmount *mnt = mntget(nd->mnt);
 			err = do_follow_link(dentry, nd);
 			dput(dentry);
+			mntput(mnt);
 			if (err)
 				goto return_err;
 			err = -ENOENT;
@@ -595,8 +597,10 @@
 		inode = dentry->d_inode;
 		if ((lookup_flags & LOOKUP_FOLLOW)
 		    && inode && inode->i_op && inode->i_op->follow_link) {
+			struct vfsmount *mnt = mntget(nd->mnt);
 			err = do_follow_link(dentry, nd);
 			dput(dentry);
+			mntput(mnt);
 			if (err)
 				goto return_err;
 			inode = nd->dentry->d_inode;
@@ -1003,6 +1007,7 @@
 	int acc_mode, error = 0;
 	struct inode *inode;
 	struct dentry *dentry;
+	struct vfsmount *mnt;
 	struct dentry *dir;
 	int count = 0;
 
@@ -1185,8 +1190,10 @@
 	 * are done. Procfs-like symlinks just set LAST_BIND.
 	 */
 	UPDATE_ATIME(dentry->d_inode);
+	mnt = mntget(nd->mnt);
 	error = dentry->d_inode->i_op->follow_link(dentry, nd);
 	dput(dentry);
+	mntput(mnt);
 	if (error)
 		return error;
 	if (nd->last_type == LAST_BIND) {