RDMA/hns: Prevent undefined behavior in hns_roce_set_user_sq_size()
authorJason Gunthorpe <jgg@mellanox.com>
Sat, 8 Jun 2019 09:25:14 +0000 (12:25 +0300)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 17 Jan 2020 18:48:35 +0000 (19:48 +0100)
commit 515f60004ed985d2b2f03659365752e0b6142986 upstream.

The "ucmd->log_sq_bb_count" variable is a user controlled variable in the
0-255 range.  If we shift more than then number of bits in an int then
it's undefined behavior (it shift wraps), and potentially the int could
become negative.

Fixes: 9a4435375cd1 ("IB/hns: Add driver files for hns RoCE driver")
Link: https://lore.kernel.org/r/20190608092514.GC28890@mwanda
Reported-by: Dan Carpenter <dan.carpenter@oracle.com>
Signed-off-by: Jason Gunthorpe <jgg@mellanox.com>
Reviewed-by: Dan Carpenter <dan.carpenter@oracle.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/infiniband/hw/hns/hns_roce_qp.c

index bd78ff9..8dd2d66 100644 (file)
@@ -332,9 +332,8 @@ static int check_sq_size_with_integrity(struct hns_roce_dev *hr_dev,
        u8 max_sq_stride = ilog2(roundup_sq_stride);
 
        /* Sanity check SQ size before proceeding */
-       if ((u32)(1 << ucmd->log_sq_bb_count) > hr_dev->caps.max_wqes ||
-            ucmd->log_sq_stride > max_sq_stride ||
-            ucmd->log_sq_stride < HNS_ROCE_IB_MIN_SQ_STRIDE) {
+       if (ucmd->log_sq_stride > max_sq_stride ||
+           ucmd->log_sq_stride < HNS_ROCE_IB_MIN_SQ_STRIDE) {
                ibdev_err(&hr_dev->ib_dev, "check SQ size error!\n");
                return -EINVAL;
        }
@@ -358,13 +357,16 @@ static int hns_roce_set_user_sq_size(struct hns_roce_dev *hr_dev,
        u32 max_cnt;
        int ret;
 
+       if (check_shl_overflow(1, ucmd->log_sq_bb_count, &hr_qp->sq.wqe_cnt) ||
+           hr_qp->sq.wqe_cnt > hr_dev->caps.max_wqes)
+               return -EINVAL;
+
        ret = check_sq_size_with_integrity(hr_dev, cap, ucmd);
        if (ret) {
                ibdev_err(&hr_dev->ib_dev, "Sanity check sq size failed\n");
                return ret;
        }
 
-       hr_qp->sq.wqe_cnt = 1 << ucmd->log_sq_bb_count;
        hr_qp->sq.wqe_shift = ucmd->log_sq_stride;
 
        max_cnt = max(1U, cap->max_send_sge);