SUNRPC: Fix race corrupting rpc upcall

If rpc_queue_upcall() adds a new upcall to the rpci->pipe list just
after rpc_pipe_release calls rpc_purge_list(), but before it calls
gss_pipe_release (as rpci->ops->release_pipe(inode)), then the latter
will free a message without deleting it from the rpci->pipe list.

We will be left with a freed object on the rpc->pipe list.  Most
frequent symptoms are kernel crashes in rpc.gssd system calls on the
pipe in question.

Reported-by: J. Bruce Fields <bfields@redhat.com>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Cc: stable@kernel.org
This commit is contained in:
Trond Myklebust
2010-09-12 19:55:25 -04:00
parent f2d47d02fd
commit 5a67657a2e
2 changed files with 8 additions and 7 deletions

View File

@@ -745,17 +745,18 @@ gss_pipe_release(struct inode *inode)
struct rpc_inode *rpci = RPC_I(inode);
struct gss_upcall_msg *gss_msg;
restart:
spin_lock(&inode->i_lock);
while (!list_empty(&rpci->in_downcall)) {
list_for_each_entry(gss_msg, &rpci->in_downcall, list) {
gss_msg = list_entry(rpci->in_downcall.next,
struct gss_upcall_msg, list);
if (!list_empty(&gss_msg->msg.list))
continue;
gss_msg->msg.errno = -EPIPE;
atomic_inc(&gss_msg->count);
__gss_unhash_msg(gss_msg);
spin_unlock(&inode->i_lock);
gss_release_msg(gss_msg);
spin_lock(&inode->i_lock);
goto restart;
}
spin_unlock(&inode->i_lock);