summaryrefslogtreecommitdiffstats
path: root/net/sunrpc/xprt.c
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2010-03-19 20:36:22 +0100
committerTrond Myklebust <Trond.Myklebust@netapp.com>2010-03-22 10:32:44 +0100
commitc9acb42ef1904d15d0fb315061cefbe638f67f3a (patch)
tree7c94dff168dfc90a279990cb2860cce626ae76a3 /net/sunrpc/xprt.c
parentSUNRPC: Fix a potential memory leak in auth_gss (diff)
downloadlinux-c9acb42ef1904d15d0fb315061cefbe638f67f3a.tar.xz
linux-c9acb42ef1904d15d0fb315061cefbe638f67f3a.zip
SUNRPC: Fix a use after free bug with the NFSv4.1 backchannel
The ->release_request() callback was designed to allow the transport layer to do housekeeping after the RPC call is done. It cannot be used to free the request itself, and doing so leads to a use-after-free bug in xprt_release(). Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'net/sunrpc/xprt.c')
-rw-r--r--net/sunrpc/xprt.c22
1 files changed, 9 insertions, 13 deletions
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c
index 469de292c23c..42f09ade0044 100644
--- a/net/sunrpc/xprt.c
+++ b/net/sunrpc/xprt.c
@@ -46,6 +46,7 @@
#include <linux/sunrpc/clnt.h>
#include <linux/sunrpc/metrics.h>
+#include <linux/sunrpc/bc_xprt.h>
#include "sunrpc.h"
@@ -1032,21 +1033,16 @@ void xprt_release(struct rpc_task *task)
if (req->rq_release_snd_buf)
req->rq_release_snd_buf(req);
- /*
- * Early exit if this is a backchannel preallocated request.
- * There is no need to have it added to the RPC slot list.
- */
- if (is_bc_request)
- return;
-
- memset(req, 0, sizeof(*req)); /* mark unused */
-
dprintk("RPC: %5u release request %p\n", task->tk_pid, req);
+ if (likely(!is_bc_request)) {
+ memset(req, 0, sizeof(*req)); /* mark unused */
- spin_lock(&xprt->reserve_lock);
- list_add(&req->rq_list, &xprt->free);
- rpc_wake_up_next(&xprt->backlog);
- spin_unlock(&xprt->reserve_lock);
+ spin_lock(&xprt->reserve_lock);
+ list_add(&req->rq_list, &xprt->free);
+ rpc_wake_up_next(&xprt->backlog);
+ spin_unlock(&xprt->reserve_lock);
+ } else
+ xprt_free_bc_request(req);
}
/**