RDMA/siw: Fix QP destroy to wait for all references dropped.
authorBernard Metzler <bmt@zurich.ibm.com>
Tue, 20 Sep 2022 08:25:03 +0000 (10:25 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 26 Oct 2022 10:35:11 +0000 (12:35 +0200)
[ Upstream commit a3c278807a459e6f50afee6971cabe74cccfb490 ]

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>
Link: https://lore.kernel.org/r/20220920082503.224189-1-bmt@zurich.ibm.com
Signed-off-by: Leon Romanovsky <leon@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
drivers/infiniband/sw/siw/siw.h
drivers/infiniband/sw/siw/siw_qp.c
drivers/infiniband/sw/siw/siw_verbs.c

index df03d84c6868ace3d5fe68c47e62cdd33e8b44d2..2f3a9cda3850f61c4b7c0d134c28a995714333c6 100644 (file)
@@ -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;
index 7e01f2438afc5ed759182cac9a18514b92a7b850..e6f634971228e4993f26ac17a19fb41d8a588ed5 100644 (file)
@@ -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);
 }
index aa3f60d54a70f4713bada607dfcd7a5b946f3ce9..ff33659acffa96b1288dda15d7249304ff0c09d2 100644 (file)
@@ -478,6 +478,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:
@@ -622,6 +624,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;
 }