From: Wenpeng Liang <liangwenp...@huawei.com>

[ Upstream commit 1c0ca9cd1741687f529498ddb899805fc2c51caa ]

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: de77503a5940 ("RDMA/hns: RDMA/hns: Assign rq head pointer when enable rq 
record db")
Fixes: 633fb4d9fdaa ("RDMA/hns: Use structs to describe the uABI instead of 
opencoding")
Fixes: ae85bf92effc ("RDMA/hns: Optimize qp param setup flow")
Fixes: 6fd610c5733d ("RDMA/hns: Support 0 hop addressing for SRQ buffer")
Fixes: 9d9d4ff78884 ("RDMA/hns: Update the kernel header file of hns")
Link: 
https://lore.kernel.org/r/1607650657-35992-2-git-send-email-liweih...@huawei.com
Signed-off-by: Wenpeng Liang <liangwenp...@huawei.com>
Signed-off-by: Weihang Li <liweih...@huawei.com>
Signed-off-by: Jason Gunthorpe <j...@nvidia.com>
Signed-off-by: Sasha Levin <sas...@kernel.org>
---
 drivers/infiniband/hw/hns/hns_roce_cq.c   |  5 +++--
 drivers/infiniband/hw/hns/hns_roce_main.c |  3 ++-
 drivers/infiniband/hw/hns/hns_roce_pd.c   | 11 ++++++-----
 drivers/infiniband/hw/hns/hns_roce_qp.c   |  9 ++++++---
 drivers/infiniband/hw/hns/hns_roce_srq.c  | 10 +++++-----
 5 files changed, 22 insertions(+), 16 deletions(-)

diff --git a/drivers/infiniband/hw/hns/hns_roce_cq.c 
b/drivers/infiniband/hw/hns/hns_roce_cq.c
index 809b22aa5056c..da346129f6e9e 100644
--- a/drivers/infiniband/hw/hns/hns_roce_cq.c
+++ b/drivers/infiniband/hw/hns/hns_roce_cq.c
@@ -274,7 +274,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);
@@ -313,7 +313,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;
        }
diff --git a/drivers/infiniband/hw/hns/hns_roce_main.c 
b/drivers/infiniband/hw/hns/hns_roce_main.c
index afeffafc59f90..a6277d1c36ba9 100644
--- a/drivers/infiniband/hw/hns/hns_roce_main.c
+++ b/drivers/infiniband/hw/hns/hns_roce_main.c
@@ -325,7 +325,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;
 
diff --git a/drivers/infiniband/hw/hns/hns_roce_pd.c 
b/drivers/infiniband/hw/hns/hns_roce_pd.c
index 98f69496adb49..f78fa1d3d8075 100644
--- a/drivers/infiniband/hw/hns/hns_roce_pd.c
+++ b/drivers/infiniband/hw/hns/hns_roce_pd.c
@@ -70,16 +70,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)
diff --git a/drivers/infiniband/hw/hns/hns_roce_qp.c 
b/drivers/infiniband/hw/hns/hns_roce_qp.c
index 71ea8fd9041b9..800141ab643a3 100644
--- a/drivers/infiniband/hw/hns/hns_roce_qp.c
+++ b/drivers/infiniband/hw/hns/hns_roce_qp.c
@@ -865,9 +865,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);
diff --git a/drivers/infiniband/hw/hns/hns_roce_srq.c 
b/drivers/infiniband/hw/hns/hns_roce_srq.c
index 8caf74e44efd9..75d74f4bb52c9 100644
--- a/drivers/infiniband/hw/hns/hns_roce_srq.c
+++ b/drivers/infiniband/hw/hns/hns_roce_srq.c
@@ -300,7 +300,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);
@@ -343,11 +344,10 @@ 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;
-- 
2.27.0



Reply via email to