]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
SUNRPC: Move fault injection call sites
authorChuck Lever <chuck.lever@oracle.com>
Wed, 31 Mar 2021 17:22:14 +0000 (13:22 -0400)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 19 May 2021 08:13:03 +0000 (10:13 +0200)
[ 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
net/sunrpc/xprt.c
net/sunrpc/xprtrdma/transport.c

index 3259120462ed718a14ebdc08f7ea4413fac4af2f..69d8843a26e073e242d71efa46af415d6be27e08 100644 (file)
@@ -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) {
index 57f09ea3ef2af761e726579c6e7a1a70693f9b48..99d07513237e060b2e3e80f4dadcce34c9d12ee5 100644 (file)
@@ -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)
index 035060c05fd5aac9f5d3d0dd0fbaf2d8ad4fffb2..f93ff4282bf4f82d6bb5dce77253dec7d42ba25d 100644 (file)
@@ -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)