Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 27922b4260f65d317aabda37e42bbbff > files > 1202

kernel-2.6.18-238.el5.src.rpm

From: Jeff Layton <jlayton@redhat.com>
Date: Fri, 23 Apr 2010 13:38:53 -0400
Subject: [fs] vfs: fix LOOKUP_FOLLOW on automount symlinks
Message-id: <1272029933-9767-1-git-send-email-jlayton@redhat.com>
Patchwork-id: 24608
O-Subject: [RHEL5 PATCH] BZ#567816: vfs: fix LOOKUP_FOLLOW on automount
	"symlinks" (CVE-2010-1088)
Bugzilla: 567816
CVE: CVE-2010-1088
RH-Acked-by: Eric Sandeen <sandeen@redhat.com>
RH-Acked-by: Eugene Teo <eugene@redhat.com>

From: Al Viro <viro@ZenIV.linux.org.uk>

(Backported from ac278a9c505092dd82077a2446af8f9fc0d9c095)

    https://bugzilla.redhat.com/show_bug.cgi?id=567816

When a NFS client crosses a mountpoint in the server's export tree, the
kernel creates a "special" directory inode that has the follow_link op
set and uses that to trigger a new submount. This helps prevent inode
number collisions on a NFS mount by having the client's mount tree
mirror the one the server has exported.

This patch fixes a local DoS that can be exploited by an unprivileged
user doing a specific sequence of operations on one of these inodes.
While the patch and CVE are public, I've been asked not to disclose the
reproducer. I tested with it myself however and verified that this does
fix the problem.

Original patch description follows:

-------------------------[snip]-----------------------

Make sure that automount "symlinks" are followed regardless of
LOOKUP_FOLLOW; it should have no effect on them.

Cc: stable@kernel.org
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>

diff --git a/fs/namei.c b/fs/namei.c
index 6ec2513..b50ccb9 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -811,6 +811,17 @@ fail:
 }
 
 /*
+ * This is a temporary kludge to deal with "automount" symlinks; proper
+ * solution is to trigger them on follow_mount(), so that do_lookup()
+ * would DTRT.  To be killed before 2.6.34-final.
+ */
+static inline int follow_on_final(struct inode *inode, unsigned lookup_flags)
+{
+	return inode && inode->i_op && unlikely(inode->i_op->follow_link) &&
+		((lookup_flags & LOOKUP_FOLLOW) || S_ISDIR(inode->i_mode));
+}
+
+/*
  * Name resolution.
  * This is the basic name resolution function, turning a pathname into
  * the final dentry. We expect 'base' to be positive and a directory.
@@ -954,8 +965,7 @@ last_component:
 		if (err)
 			break;
 		inode = next.dentry->d_inode;
-		if ((lookup_flags & LOOKUP_FOLLOW)
-		    && inode && inode->i_op && inode->i_op->follow_link) {
+		if (follow_on_final(inode, lookup_flags)) {
 			err = do_follow_link(&next, nd);
 			if (err)
 				goto return_err;