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); } /**