Commit bb6a7765 authored by Chengchang Tang's avatar Chengchang Tang
Browse files

RDMA/hns: Fix HW UAF when destroy context timeout

driver inclusion
category: bugfix
bugzilla: https://gitee.com/openeuler/kernel/issues/IAL7SX



----------------------------------------------------------------------

If mbox timeout during detroying some resource, the HW may still access
the related resource which caused an UAF.

To fix it, if resource destruction fails, the resource till be retained
until driver uninit.

Fixes: 431c875e ("RDMA/hns: Fix simultaneous reset and resource deregistration")
Signed-off-by: default avatarChengchang Tang <tangchengchang@huawei.com>
Signed-off-by: default avatarXinghai Cen <cenxinghai@h-partners.com>
parent ae7d7dfc
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
@@ -229,12 +229,12 @@ static void free_cqc(struct hns_roce_dev *hr_dev, struct hns_roce_cq *hr_cq)

	ret = hns_roce_destroy_hw_ctx(hr_dev, HNS_ROCE_CMD_DESTROY_CQC,
				      hr_cq->cqn);
	if (ret)
	if (ret) {
		hr_cq->delayed_destroy_flag = true;
		dev_err_ratelimited(dev,
				    "DESTROY_CQ failed (%d) for CQN %06lx\n",
				    ret, hr_cq->cqn);
	if (ret == -EBUSY)
		hr_cq->delayed_destroy_flag = true;
	}

	xa_erase_irq(&cq_table->array, hr_cq->cqn);

+3 −4
Original line number Diff line number Diff line
@@ -6262,11 +6262,13 @@ int hns_roce_v2_destroy_qp_common(struct hns_roce_dev *hr_dev,
		/* Modify qp to reset before destroying qp */
		ret = hns_roce_v2_modify_qp(&hr_qp->ibqp, NULL, 0,
					    hr_qp->state, IB_QPS_RESET, udata);
		if (ret)
		if (ret) {
			hr_qp->delayed_destroy_flag = true;
			ibdev_err_ratelimited(ibdev,
				  "failed to modify QP to RST, ret = %d.\n",
				  ret);
		}
	}

	send_cq = hr_qp->ibqp.send_cq ? to_hr_cq(hr_qp->ibqp.send_cq) : NULL;
	recv_cq = hr_qp->ibqp.recv_cq ? to_hr_cq(hr_qp->ibqp.recv_cq) : NULL;
@@ -6334,9 +6336,6 @@ int hns_roce_v2_destroy_qp(struct ib_qp *ibqp, struct ib_udata *udata)
			  "failed to destroy QP, QPN = 0x%06lx, ret = %d.\n",
			  hr_qp->qpn, ret);

	if (ret == -EBUSY)
		hr_qp->delayed_destroy_flag = true;

	hns_roce_qp_destroy(hr_dev, hr_qp, udata);

	return 0;
+3 −3
Original line number Diff line number Diff line
@@ -152,11 +152,11 @@ static void hns_roce_mr_free(struct hns_roce_dev *hr_dev, struct hns_roce_mr *mr
		ret = hns_roce_destroy_hw_ctx(hr_dev, HNS_ROCE_CMD_DESTROY_MPT,
					      key_to_hw_index(mr->key) &
					      (hr_dev->caps.num_mtpts - 1));
		if (ret)
		if (ret) {
			mr->delayed_destroy_flag = true;
			ibdev_warn_ratelimited(ibdev, "failed to destroy mpt, ret = %d.\n",
				   ret);
		if (ret == -EBUSY)
			mr->delayed_destroy_flag = true;
		}
	}

	free_mr_pbl(hr_dev, mr);
+3 −3
Original line number Diff line number Diff line
@@ -161,12 +161,12 @@ static void free_srqc(struct hns_roce_dev *hr_dev, struct hns_roce_srq *srq)

	ret = hns_roce_destroy_hw_ctx(hr_dev, HNS_ROCE_CMD_DESTROY_SRQ,
				      srq->srqn);
	if (ret)
	if (ret) {
		srq->delayed_destroy_flag = true;
		dev_err_ratelimited(hr_dev->dev,
				    "DESTROY_SRQ failed (%d) for SRQN %06lx\n",
				    ret, srq->srqn);
	if (ret == -EBUSY)
		srq->delayed_destroy_flag = true;
	}

	xa_erase_irq(&srq_table->xa, srq->srqn);