| From be75bcf96a54020cc0f6cab6f2c7610c6ddd95ab Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Wed, 31 Mar 2021 13:22:14 -0400 |
| Subject: SUNRPC: Move fault injection call sites |
| |
| From: Chuck Lever <chuck.lever@oracle.com> |
| |
| [ Upstream commit 7638e0bfaed1b653d3ca663e560e9ffb44bb1030 ] |
| |
| I've hit some crashes that occur in the xprt_rdma_inject_disconnect |
| path. It appears that, for some provides, rdma_disconnect() can |
| take so long that the transport can disconnect and release its |
| hardware resources while rdma_disconnect() is still running, |
| resulting in a UAF in the provider. |
| |
| The transport's fault injection method may depend on the stability |
| of transport data structures. That means it needs to be invoked |
| only from contexts that hold the transport write lock. |
| |
| Fixes: 4a0682583988 ("SUNRPC: Transport fault injection") |
| Signed-off-by: Chuck Lever <chuck.lever@oracle.com> |
| Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| net/sunrpc/clnt.c | 1 - |
| net/sunrpc/xprt.c | 6 ++++-- |
| net/sunrpc/xprtrdma/transport.c | 6 ++++-- |
| 3 files changed, 8 insertions(+), 5 deletions(-) |
| |
| diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c |
| index 3259120462ed..69d8843a26e0 100644 |
| --- a/net/sunrpc/clnt.c |
| +++ b/net/sunrpc/clnt.c |
| @@ -1802,7 +1802,6 @@ call_allocate(struct rpc_task *task) |
| |
| status = xprt->ops->buf_alloc(task); |
| trace_rpc_buf_alloc(task, status); |
| - xprt_inject_disconnect(xprt); |
| if (status == 0) |
| return; |
| if (status != -ENOMEM) { |
| diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c |
| index 57f09ea3ef2a..99d07513237e 100644 |
| --- a/net/sunrpc/xprt.c |
| +++ b/net/sunrpc/xprt.c |
| @@ -1455,7 +1455,10 @@ bool xprt_prepare_transmit(struct rpc_task *task) |
| |
| void xprt_end_transmit(struct rpc_task *task) |
| { |
| - xprt_release_write(task->tk_rqstp->rq_xprt, task); |
| + struct rpc_xprt *xprt = task->tk_rqstp->rq_xprt; |
| + |
| + xprt_inject_disconnect(xprt); |
| + xprt_release_write(xprt, task); |
| } |
| |
| /** |
| @@ -1857,7 +1860,6 @@ void xprt_release(struct rpc_task *task) |
| spin_unlock(&xprt->transport_lock); |
| if (req->rq_buffer) |
| xprt->ops->buf_free(task); |
| - xprt_inject_disconnect(xprt); |
| xdr_free_bvec(&req->rq_rcv_buf); |
| xdr_free_bvec(&req->rq_snd_buf); |
| if (req->rq_cred != NULL) |
| diff --git a/net/sunrpc/xprtrdma/transport.c b/net/sunrpc/xprtrdma/transport.c |
| index 035060c05fd5..f93ff4282bf4 100644 |
| --- a/net/sunrpc/xprtrdma/transport.c |
| +++ b/net/sunrpc/xprtrdma/transport.c |
| @@ -262,8 +262,10 @@ xprt_rdma_connect_worker(struct work_struct *work) |
| * xprt_rdma_inject_disconnect - inject a connection fault |
| * @xprt: transport context |
| * |
| - * If @xprt is connected, disconnect it to simulate spurious connection |
| - * loss. |
| + * If @xprt is connected, disconnect it to simulate spurious |
| + * connection loss. Caller must hold @xprt's send lock to |
| + * ensure that data structures and hardware resources are |
| + * stable during the rdma_disconnect() call. |
| */ |
| static void |
| xprt_rdma_inject_disconnect(struct rpc_xprt *xprt) |
| -- |
| 2.30.2 |
| |