Commit 1c0ca9cd authored by Wenpeng Liang's avatar Wenpeng Liang Committed by Jason Gunthorpe
Browse files

RDMA/hns: Limit the length of data copied between kernel and userspace

For ib_copy_from_user(), the length of udata may not be the same as that
of cmd. For ib_copy_to_user(), the length of udata may not be the same as
that of resp. So limit the length to prevent out-of-bounds read and write
operations from ib_copy_from_user() and ib_copy_to_user().

Fixes: de77503a ("RDMA/hns: RDMA/hns: Assign rq head pointer when enable rq record db")
Fixes: 633fb4d9 ("RDMA/hns: Use structs to describe the uABI instead of opencoding")
Fixes: ae85bf92 ("RDMA/hns: Optimize qp param setup flow")
Fixes: 6fd610c5 ("RDMA/hns: Support 0 hop addressing for SRQ buffer")
Fixes: 9d9d4ff7 ("RDMA/hns: Update the kernel header file of hns")
Link: https://lore.kernel.org/r/1607650657-35992-2-git-send-email-liweihang@huawei.com


Signed-off-by: default avatarWenpeng Liang <liangwenpeng@huawei.com>
Signed-off-by: default avatarWeihang Li <liweihang@huawei.com>
Signed-off-by: default avatarJason Gunthorpe <jgg@nvidia.com>
parent 6f320f69
Loading
Loading
Loading
Loading
+3 −2
Original line number Diff line number Diff line
@@ -276,7 +276,7 @@ int hns_roce_create_cq(struct ib_cq *ib_cq, const struct ib_cq_init_attr *attr,

	if (udata) {
		ret = ib_copy_from_udata(&ucmd, udata,
					 min(sizeof(ucmd), udata->inlen));
					 min(udata->inlen, sizeof(ucmd)));
		if (ret) {
			ibdev_err(ibdev, "Failed to copy CQ udata, err %d\n",
				  ret);
@@ -315,7 +315,8 @@ int hns_roce_create_cq(struct ib_cq *ib_cq, const struct ib_cq_init_attr *attr,

	if (udata) {
		resp.cqn = hr_cq->cqn;
		ret = ib_copy_to_udata(udata, &resp, sizeof(resp));
		ret = ib_copy_to_udata(udata, &resp,
				       min(udata->outlen, sizeof(resp)));
		if (ret)
			goto err_cqc;
	}
+2 −1
Original line number Diff line number Diff line
@@ -327,7 +327,8 @@ static int hns_roce_alloc_ucontext(struct ib_ucontext *uctx,

	resp.cqe_size = hr_dev->caps.cqe_sz;

	ret = ib_copy_to_udata(udata, &resp, sizeof(resp));
	ret = ib_copy_to_udata(udata, &resp,
			       min(udata->outlen, sizeof(resp)));
	if (ret)
		goto error_fail_copy_to_udata;

+6 −5
Original line number Diff line number Diff line
@@ -69,16 +69,17 @@ int hns_roce_alloc_pd(struct ib_pd *ibpd, struct ib_udata *udata)
	}

	if (udata) {
		struct hns_roce_ib_alloc_pd_resp uresp = {.pdn = pd->pdn};
		struct hns_roce_ib_alloc_pd_resp resp = {.pdn = pd->pdn};

		if (ib_copy_to_udata(udata, &uresp, sizeof(uresp))) {
		ret = ib_copy_to_udata(udata, &resp,
				       min(udata->outlen, sizeof(resp)));
		if (ret) {
			hns_roce_pd_free(to_hr_dev(ib_dev), pd->pdn);
			ibdev_err(ib_dev, "failed to copy to udata\n");
			return -EFAULT;
			ibdev_err(ib_dev, "failed to copy to udata, ret = %d\n", ret);
		}
	}

	return 0;
	return ret;
}

int hns_roce_dealloc_pd(struct ib_pd *pd, struct ib_udata *udata)
+6 −3
Original line number Diff line number Diff line
@@ -924,9 +924,12 @@ static int set_qp_param(struct hns_roce_dev *hr_dev, struct hns_roce_qp *hr_qp,
	}

	if (udata) {
		if (ib_copy_from_udata(ucmd, udata, sizeof(*ucmd))) {
			ibdev_err(ibdev, "Failed to copy QP ucmd\n");
			return -EFAULT;
		ret = ib_copy_from_udata(ucmd, udata,
					 min(udata->inlen, sizeof(*ucmd)));
		if (ret) {
			ibdev_err(ibdev,
				  "failed to copy QP ucmd, ret = %d\n", ret);
			return ret;
		}

		ret = set_user_sq_size(hr_dev, &init_attr->cap, hr_qp, ucmd);
+5 −5
Original line number Diff line number Diff line
@@ -303,7 +303,8 @@ int hns_roce_create_srq(struct ib_srq *ib_srq,
	srq->max_gs = init_attr->attr.max_sge;

	if (udata) {
		ret = ib_copy_from_udata(&ucmd, udata, sizeof(ucmd));
		ret = ib_copy_from_udata(&ucmd, udata,
					 min(udata->inlen, sizeof(ucmd)));
		if (ret) {
			ibdev_err(ibdev, "Failed to copy SRQ udata, err %d\n",
				  ret);
@@ -346,12 +347,11 @@ int hns_roce_create_srq(struct ib_srq *ib_srq,
	resp.srqn = srq->srqn;

	if (udata) {
		if (ib_copy_to_udata(udata, &resp,
				     min(udata->outlen, sizeof(resp)))) {
			ret = -EFAULT;
		ret = ib_copy_to_udata(udata, &resp,
				       min(udata->outlen, sizeof(resp)));
		if (ret)
			goto err_srqc_alloc;
	}
	}

	return 0;