SUNRPC: Move fault injection call sites
authorChuck Lever <chuck.lever@oracle.com>
Wed, 31 Mar 2021 17:22:14 +0000 (13:22 -0400)
committerTrond Myklebust <trond.myklebust@hammerspace.com>
Wed, 14 Apr 2021 13:36:29 +0000 (09:36 -0400)
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>
net/sunrpc/clnt.c
net/sunrpc/xprt.c
net/sunrpc/xprtrdma/transport.c

index 612f0a641f4cf62eb20e1259cb2efe106b9f7823..c2a01125be1a1f9878ad1ae15cd2a025e96137f9 100644 (file)
@@ -1799,7 +1799,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 a853f75d49681827ed316181c0e561779571c8d6..80c94ead4aa0adf5aa1004629b77c27efa24d049 100644 (file)
@@ -1485,7 +1485,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);
 }
 
 /**
@@ -1887,7 +1890,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 78d29d1bcc203e885e26d5b7c69e36876c28b531..09953597d055a01ae52f54eb04b17189733f1930 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)