diff mbox series

RDMA/siw: Fix QP destroy to wait for all references dropped.

Message ID 20220920082503.224189-1-bmt@zurich.ibm.com (mailing list archive)
State Accepted
Headers show
Series RDMA/siw: Fix QP destroy to wait for all references dropped. | expand

Commit Message

Bernard Metzler Sept. 20, 2022, 8:25 a.m. UTC
Delay QP destroy completion until all siw references to QP are
dropped. The calling RDMA core will free QP structure after
successful return from siw_qp_destroy() call, so siw must not
hold any remaining reference to the QP upon return.
A use-after-free was encountered in xfstest generic/460, while
testing NFSoRDMA. Here, after a TCP connection drop by peer,
the triggered siw_cm_work_handler got delayed until after
QP destroy call, referencing a QP which has already freed.

Fixes: 303ae1cdfdf7 ("rdma/siw: application interface")

Reported-by: Olga Kornievskaia <kolga@netapp.com>
Signed-off-by: Bernard Metzler <bmt@zurich.ibm.com>
---
 drivers/infiniband/sw/siw/siw.h       | 1 +
 drivers/infiniband/sw/siw/siw_qp.c    | 2 +-
 drivers/infiniband/sw/siw/siw_verbs.c | 3 +++
 3 files changed, 5 insertions(+), 1 deletion(-)

Comments

Leon Romanovsky Sept. 20, 2022, 6:24 p.m. UTC | #1
On Tue, 20 Sep 2022 10:25:03 +0200, Bernard Metzler wrote:
> Delay QP destroy completion until all siw references to QP are
> dropped. The calling RDMA core will free QP structure after
> successful return from siw_qp_destroy() call, so siw must not
> hold any remaining reference to the QP upon return.
> A use-after-free was encountered in xfstest generic/460, while
> testing NFSoRDMA. Here, after a TCP connection drop by peer,
> the triggered siw_cm_work_handler got delayed until after
> QP destroy call, referencing a QP which has already freed.
> 
> [...]

Applied, thanks!

[1/1] RDMA/siw: Fix QP destroy to wait for all references dropped.
      https://git.kernel.org/rdma/rdma/c/a3c278807a459e

Best regards,
diff mbox series

Patch

diff --git a/drivers/infiniband/sw/siw/siw.h b/drivers/infiniband/sw/siw/siw.h
index df03d84c6868..2f3a9cda3850 100644
--- a/drivers/infiniband/sw/siw/siw.h
+++ b/drivers/infiniband/sw/siw/siw.h
@@ -418,6 +418,7 @@  struct siw_qp {
 	struct ib_qp base_qp;
 	struct siw_device *sdev;
 	struct kref ref;
+	struct completion qp_free;
 	struct list_head devq;
 	int tx_cpu;
 	struct siw_qp_attrs attrs;
diff --git a/drivers/infiniband/sw/siw/siw_qp.c b/drivers/infiniband/sw/siw/siw_qp.c
index 7e01f2438afc..e6f634971228 100644
--- a/drivers/infiniband/sw/siw/siw_qp.c
+++ b/drivers/infiniband/sw/siw/siw_qp.c
@@ -1342,6 +1342,6 @@  void siw_free_qp(struct kref *ref)
 	vfree(qp->orq);
 
 	siw_put_tx_cpu(qp->tx_cpu);
-
+	complete(&qp->qp_free);
 	atomic_dec(&sdev->num_qp);
 }
diff --git a/drivers/infiniband/sw/siw/siw_verbs.c b/drivers/infiniband/sw/siw/siw_verbs.c
index 8dedae7ae79e..3e814cfb298c 100644
--- a/drivers/infiniband/sw/siw/siw_verbs.c
+++ b/drivers/infiniband/sw/siw/siw_verbs.c
@@ -480,6 +480,8 @@  int siw_create_qp(struct ib_qp *ibqp, struct ib_qp_init_attr *attrs,
 	list_add_tail(&qp->devq, &sdev->qp_list);
 	spin_unlock_irqrestore(&sdev->lock, flags);
 
+	init_completion(&qp->qp_free);
+
 	return 0;
 
 err_out_xa:
@@ -624,6 +626,7 @@  int siw_destroy_qp(struct ib_qp *base_qp, struct ib_udata *udata)
 	qp->scq = qp->rcq = NULL;
 
 	siw_qp_put(qp);
+	wait_for_completion(&qp->qp_free);
 
 	return 0;
 }