Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > media > main-src > by-pkgid > d0a35cd31c1125e2132804d68547073d > files > 2630

kernel-2.6.18-194.26.1.el5.src.rpm

From: Jeff Layton <jlayton@redhat.com>
Date: Mon, 26 Apr 2010 13:12:54 -0400
Subject: [nfs] fix an oops when truncating a file
Message-id: <1272287574-4333-1-git-send-email-jlayton@redhat.com>
Patchwork-id: 24616
O-Subject: [RHEL5 PATCH] BZ#567195: NFS: Fix an Oops when truncating a file
	(CVE-2010-1087)
Bugzilla: 567195
CVE: CVE-2010-1087
RH-Acked-by: Steve Dickson <SteveD@redhat.com>

From: Trond Myklebust <Trond.Myklebust@netapp.com>

(Backported from 9f557cd8073104b39528794d44e129331ded649f)

This is has been sent along as a CVE. I'm not aware of a reproducer
for this problem, but it seems like a SIGKILL at an inopportune time
could crash the box here.

I've stress-tested the patch on my KVM rig and it doesn't seem to
have caused any issues.

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

The VM/VFS does not allow mapping->a_ops->invalidatepage() to fail.
Unfortunately, nfs_wb_page_cancel() may fail if a fatal signal occurs.
Since the NFS code assumes that the page stays mapped for as long as the
writeback is active, we can end up Oopsing (among other things).

The only safe fix here is to convert nfs_wait_on_request(), so as to make
it uninterruptible (as is already the case with wait_on_page_writeback()).

Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Cc: stable@kernel.org

diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c
index ef4ae2f..4c2c9eb 100644
--- a/fs/nfs/pagelist.c
+++ b/fs/nfs/pagelist.c
@@ -194,32 +194,24 @@ static int nfs_wait_bit_interruptible(void *word)
 	return ret;
 }
 
+static int nfs_wait_bit_uninterruptible(void *word)
+{
+	io_schedule();
+	return 0;
+}
+
 /**
  * nfs_wait_on_request - Wait for a request to complete.
  * @req: request to wait upon.
  *
- * Interruptible by signals only if mounted with intr flag.
  * The user is responsible for holding a count on the request.
  */
 int
 nfs_wait_on_request(struct nfs_page *req)
 {
-	struct rpc_clnt *clnt = NFS_CLIENT(req->wb_context->path.dentry->d_inode);
-	sigset_t oldmask;
-	int ret = 0;
-
-	if (!test_bit(PG_BUSY, &req->wb_flags))
-		goto out;
-	/*
-	 * Note: the call to rpc_clnt_sigmask() suffices to ensure that we
-	 *	 are not interrupted if intr flag is not set
-	 */
-	rpc_clnt_sigmask(clnt, &oldmask);
-	ret = out_of_line_wait_on_bit(&req->wb_flags, PG_BUSY,
-			nfs_wait_bit_interruptible, TASK_INTERRUPTIBLE);
-	rpc_clnt_sigunmask(clnt, &oldmask);
-out:
-	return ret;
+	return wait_on_bit(&req->wb_flags, PG_BUSY,
+			nfs_wait_bit_uninterruptible,
+			TASK_UNINTERRUPTIBLE);
 }
 
 /**