diff mbox series

RDMA/hns: prevent undefined behavior in hns_roce_set_user_sq_size()

Message ID 20190608092514.GC28890@mwanda (mailing list archive)
State Changes Requested
Delegated to: Jason Gunthorpe
Headers show
Series RDMA/hns: prevent undefined behavior in hns_roce_set_user_sq_size() | expand

Commit Message

Dan Carpenter June 8, 2019, 9:25 a.m. UTC
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).  It turns out this
doesn't cause any real issues at runtime, but it's good to check anyway.

Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
---
 drivers/infiniband/hw/hns/hns_roce_qp.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

Comments

Dan Carpenter Oct. 7, 2019, 12:18 p.m. UTC | #1
This one still needs to be applied.

regards,
dan carpenter

On Sat, Jun 08, 2019 at 12:25:14PM +0300, Dan Carpenter wrote:
> 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).  It turns out this
> doesn't cause any real issues at runtime, but it's good to check anyway.
> 
> Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
> ---
>  drivers/infiniband/hw/hns/hns_roce_qp.c | 3 ++-
>  1 file changed, 2 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/infiniband/hw/hns/hns_roce_qp.c b/drivers/infiniband/hw/hns/hns_roce_qp.c
> index 8db2817a249e..006b3e7f4ed5 100644
> --- a/drivers/infiniband/hw/hns/hns_roce_qp.c
> +++ b/drivers/infiniband/hw/hns/hns_roce_qp.c
> @@ -342,7 +342,8 @@ static int hns_roce_set_user_sq_size(struct hns_roce_dev *hr_dev,
>  	u32 max_cnt;
>  
>  	/* Sanity check SQ size before proceeding */
> -	if ((u32)(1 << ucmd->log_sq_bb_count) > hr_dev->caps.max_wqes ||
> +	if (ucmd->log_sq_bb_count > 31 ||
> +	    (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) {
>  		dev_err(hr_dev->dev, "check SQ size error!\n");
> -- 
> 2.20.1
Jason Gunthorpe Oct. 24, 2019, 4:37 p.m. UTC | #2
On Mon, Oct 07, 2019 at 03:18:22PM +0300, Dan Carpenter wrote:
> This one still needs to be applied.
> 
> regards,
> dan carpenter

Weird, it is marked changes requested in patchworks. An email must
have been lost??

I think I probably wanted to say that:

> >  	/* Sanity check SQ size before proceeding */
> > -	if ((u32)(1 << ucmd->log_sq_bb_count) > hr_dev->caps.max_wqes ||
> > +	if (ucmd->log_sq_bb_count > 31 ||
> > +	    (u32)(1 << ucmd->log_sq_bb_count) > hr_dev->caps.max_wqes
> > ||

Overall should probably be coded using check_shl_overflow(), as this
later shift:

	hr_qp->sq.wqe_cnt = 1 << ucmd->log_sq_bb_count;

Is storing it into an int and hardwring '31' because it magically
matches that lower shift is pretty fragile.

More like this?

diff --git a/drivers/infiniband/hw/hns/hns_roce_qp.c b/drivers/infiniband/hw/hns/hns_roce_qp.c
index bec48f2593f405..6aa27d6ea3a600 100644
--- a/drivers/infiniband/hw/hns/hns_roce_qp.c
+++ b/drivers/infiniband/hw/hns/hns_roce_qp.c
@@ -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);
Dan Carpenter Oct. 24, 2019, 6:20 p.m. UTC | #3
On Thu, Oct 24, 2019 at 01:37:49PM -0300, Jason Gunthorpe wrote:
> On Mon, Oct 07, 2019 at 03:18:22PM +0300, Dan Carpenter wrote:
> > This one still needs to be applied.
> > 
> > regards,
> > dan carpenter
> 
> Weird, it is marked changes requested in patchworks. An email must
> have been lost??
>

Maybe you replied to a different thread?

> I think I probably wanted to say that:
> 
> > >  	/* Sanity check SQ size before proceeding */
> > > -	if ((u32)(1 << ucmd->log_sq_bb_count) > hr_dev->caps.max_wqes ||
> > > +	if (ucmd->log_sq_bb_count > 31 ||
> > > +	    (u32)(1 << ucmd->log_sq_bb_count) > hr_dev->caps.max_wqes
> > > ||
> 
> Overall should probably be coded using check_shl_overflow(), as this
> later shift:
> 
> 	hr_qp->sq.wqe_cnt = 1 << ucmd->log_sq_bb_count;
> 
> Is storing it into an int and hardwring '31' because it magically
> matches that lower shift is pretty fragile.
> 
> More like this?
> 

Yeah.  I like your patch.  I'd feel silly claiming authorship though.
I'm willing to, because it's nice, but probably you should just give me
Reported-by credit instead.

Reviewed-by: Dan Carpenter <dan.carpenter@oracle.com>

regards,
dan carpenter
Jason Gunthorpe Oct. 28, 2019, 2:23 p.m. UTC | #4
On Thu, Oct 24, 2019 at 09:20:39PM +0300, Dan Carpenter wrote:
> On Thu, Oct 24, 2019 at 01:37:49PM -0300, Jason Gunthorpe wrote:
> > On Mon, Oct 07, 2019 at 03:18:22PM +0300, Dan Carpenter wrote:
> > > This one still needs to be applied.
> > > 
> > > regards,
> > > dan carpenter
> > 
> > Weird, it is marked changes requested in patchworks. An email must
> > have been lost??
> >
> 
> Maybe you replied to a different thread?
> 
> > I think I probably wanted to say that:
> > 
> > > >  	/* Sanity check SQ size before proceeding */
> > > > -	if ((u32)(1 << ucmd->log_sq_bb_count) > hr_dev->caps.max_wqes ||
> > > > +	if (ucmd->log_sq_bb_count > 31 ||
> > > > +	    (u32)(1 << ucmd->log_sq_bb_count) > hr_dev->caps.max_wqes
> > > > ||
> > 
> > Overall should probably be coded using check_shl_overflow(), as this
> > later shift:
> > 
> > 	hr_qp->sq.wqe_cnt = 1 << ucmd->log_sq_bb_count;
> > 
> > Is storing it into an int and hardwring '31' because it magically
> > matches that lower shift is pretty fragile.
> > 
> > More like this?
> > 
> 
> Yeah.  I like your patch.  I'd feel silly claiming authorship though.
> I'm willing to, because it's nice, but probably you should just give me
> Reported-by credit instead.
> 
> Reviewed-by: Dan Carpenter <dan.carpenter@oracle.com>

Okay applied to for-next

Jason
diff mbox series

Patch

diff --git a/drivers/infiniband/hw/hns/hns_roce_qp.c b/drivers/infiniband/hw/hns/hns_roce_qp.c
index 8db2817a249e..006b3e7f4ed5 100644
--- a/drivers/infiniband/hw/hns/hns_roce_qp.c
+++ b/drivers/infiniband/hw/hns/hns_roce_qp.c
@@ -342,7 +342,8 @@  static int hns_roce_set_user_sq_size(struct hns_roce_dev *hr_dev,
 	u32 max_cnt;
 
 	/* Sanity check SQ size before proceeding */
-	if ((u32)(1 << ucmd->log_sq_bb_count) > hr_dev->caps.max_wqes ||
+	if (ucmd->log_sq_bb_count > 31 ||
+	    (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) {
 		dev_err(hr_dev->dev, "check SQ size error!\n");