aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2010-03-19 15:36:22 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2010-03-22 05:32:44 -0400
commitc9acb42ef1904d15d0fb315061cefbe638f67f3a (patch)
tree7c94dff168dfc90a279990cb2860cce626ae76a3
parentcdead7cf12896c0e50a8be2e52de52c364603095 (diff)
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>
-rw-r--r--include/linux/sunrpc/bc_xprt.h5
-rw-r--r--net/sunrpc/bc_svc.c15
-rw-r--r--net/sunrpc/xprt.c22
-rw-r--r--net/sunrpc/xprtsock.c3
4 files changed, 13 insertions, 32 deletions
diff --git a/include/linux/sunrpc/bc_xprt.h b/include/linux/sunrpc/bc_xprt.h
index d7152b451e21..7c91260c44a9 100644
--- a/include/linux/sunrpc/bc_xprt.h
+++ b/include/linux/sunrpc/bc_xprt.h
@@ -36,7 +36,6 @@ struct rpc_rqst *xprt_alloc_bc_request(struct rpc_xprt *xprt);
36void xprt_free_bc_request(struct rpc_rqst *req); 36void xprt_free_bc_request(struct rpc_rqst *req);
37int xprt_setup_backchannel(struct rpc_xprt *, unsigned int min_reqs); 37int xprt_setup_backchannel(struct rpc_xprt *, unsigned int min_reqs);
38void xprt_destroy_backchannel(struct rpc_xprt *, int max_reqs); 38void xprt_destroy_backchannel(struct rpc_xprt *, int max_reqs);
39void bc_release_request(struct rpc_task *);
40int bc_send(struct rpc_rqst *req); 39int bc_send(struct rpc_rqst *req);
41 40
42/* 41/*
@@ -59,6 +58,10 @@ static inline int svc_is_backchannel(const struct svc_rqst *rqstp)
59{ 58{
60 return 0; 59 return 0;
61} 60}
61
62static inline void xprt_free_bc_request(struct rpc_rqst *req)
63{
64}
62#endif /* CONFIG_NFS_V4_1 */ 65#endif /* CONFIG_NFS_V4_1 */
63#endif /* _LINUX_SUNRPC_BC_XPRT_H */ 66#endif /* _LINUX_SUNRPC_BC_XPRT_H */
64 67
diff --git a/net/sunrpc/bc_svc.c b/net/sunrpc/bc_svc.c
index 13f214f53120..f0c05d3311c1 100644
--- a/net/sunrpc/bc_svc.c
+++ b/net/sunrpc/bc_svc.c
@@ -37,21 +37,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 37
38#define RPCDBG_FACILITY RPCDBG_SVCDSP 38#define RPCDBG_FACILITY RPCDBG_SVCDSP
39 39
40void bc_release_request(struct rpc_task *task)
41{
42 struct rpc_rqst *req = task->tk_rqstp;
43
44 dprintk("RPC: bc_release_request: task= %p\n", task);
45
46 /*
47 * Release this request only if it's a backchannel
48 * preallocated request
49 */
50 if (!bc_prealloc(req))
51 return;
52 xprt_free_bc_request(req);
53}
54
55/* Empty callback ops */ 40/* Empty callback ops */
56static const struct rpc_call_ops nfs41_callback_ops = { 41static const struct rpc_call_ops nfs41_callback_ops = {
57}; 42};
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 @@
46 46
47#include <linux/sunrpc/clnt.h> 47#include <linux/sunrpc/clnt.h>
48#include <linux/sunrpc/metrics.h> 48#include <linux/sunrpc/metrics.h>
49#include <linux/sunrpc/bc_xprt.h>
49 50
50#include "sunrpc.h" 51#include "sunrpc.h"
51 52
@@ -1032,21 +1033,16 @@ void xprt_release(struct rpc_task *task)
1032 if (req->rq_release_snd_buf) 1033 if (req->rq_release_snd_buf)
1033 req->rq_release_snd_buf(req); 1034 req->rq_release_snd_buf(req);
1034 1035
1035 /*
1036 * Early exit if this is a backchannel preallocated request.
1037 * There is no need to have it added to the RPC slot list.
1038 */
1039 if (is_bc_request)
1040 return;
1041
1042 memset(req, 0, sizeof(*req)); /* mark unused */
1043
1044 dprintk("RPC: %5u release request %p\n", task->tk_pid, req); 1036 dprintk("RPC: %5u release request %p\n", task->tk_pid, req);
1037 if (likely(!is_bc_request)) {
1038 memset(req, 0, sizeof(*req)); /* mark unused */
1045 1039
1046 spin_lock(&xprt->reserve_lock); 1040 spin_lock(&xprt->reserve_lock);
1047 list_add(&req->rq_list, &xprt->free); 1041 list_add(&req->rq_list, &xprt->free);
1048 rpc_wake_up_next(&xprt->backlog); 1042 rpc_wake_up_next(&xprt->backlog);
1049 spin_unlock(&xprt->reserve_lock); 1043 spin_unlock(&xprt->reserve_lock);
1044 } else
1045 xprt_free_bc_request(req);
1050} 1046}
1051 1047
1052/** 1048/**
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c
index e4839c07c913..9847c30b5001 100644
--- a/net/sunrpc/xprtsock.c
+++ b/net/sunrpc/xprtsock.c
@@ -2251,9 +2251,6 @@ static struct rpc_xprt_ops xs_tcp_ops = {
2251 .buf_free = rpc_free, 2251 .buf_free = rpc_free,
2252 .send_request = xs_tcp_send_request, 2252 .send_request = xs_tcp_send_request,
2253 .set_retrans_timeout = xprt_set_retrans_timeout_def, 2253 .set_retrans_timeout = xprt_set_retrans_timeout_def,
2254#if defined(CONFIG_NFS_V4_1)
2255 .release_request = bc_release_request,
2256#endif /* CONFIG_NFS_V4_1 */
2257 .close = xs_tcp_close, 2254 .close = xs_tcp_close,
2258 .destroy = xs_destroy, 2255 .destroy = xs_destroy,
2259 .print_stats = xs_tcp_print_stats, 2256 .print_stats = xs_tcp_print_stats,