Re: [PATCH for-rc] IB/qib: Fix issues noted by fuzzing on the iovecs

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Mon, Oct 04, 2021 at 07:56:25AM -0400, Dennis Dalessandro wrote:
> From: Mike Marciniszyn <mike.marciniszyn@xxxxxxxxxxxxxxxxxxxx>
> 
> Add protection for bytes_togo and n to avoid going beyond variables
> in PSM pkt structure.
> 
> Reported-by: Ilja Van Sprundel <ivansprundel@xxxxxxxxxxxx>
> Reviewed-by: Dennis Dalessandro <dennis.dalessandro@xxxxxxxxxxxxxxxxxxxx>
> Signed-off-by: Mike Marciniszyn <mike.marciniszyn@xxxxxxxxxxxxxxxxxxxx>
> Signed-off-by: Dennis Dalessandro <dennis.dalessandro@xxxxxxxxxxxxxxxxxxxx>
>  drivers/infiniband/hw/qib/qib_user_sdma.c |   20 ++++++++++++--------
>  1 file changed, 12 insertions(+), 8 deletions(-)

This commit message isn't good enough for a rc patch

    IB/qib: Protect from buffer overflow in struct qib_user_sdma_pkt::addr

    Overflowing either n or bytes_togo can allow userspace to trigger a buffer
    overflow of kernel memory. Check for overflows in all the places
    doing math on user controlled buffers

Don't forget the Fixes line.

  
> @@ -878,7 +878,7 @@ static int qib_user_sdma_queue_pkts(const struct qib_devdata *dd,
>  			const unsigned long faddr =
>  				(unsigned long) iov[idx].iov_base;
>  
> -			if (slen & 3 || faddr & 3 || !slen) {
> +			if (slen & 3 || faddr & 3 || !slen || bytes_togo >= (U32_MAX-slen)) {
>  				ret = -EINVAL;
>  				goto free_pbc;
>  			}

This is not the expected way to write overflow checks these days, like this:

-                       bytes_togo += slen;
+                       if (check_add_overflow(bytes_togo, slen, &bytes_togo)) {
+                               ret = -EINVAL;
+                               goto free_pbc;
+                       }


> @@ -904,10 +904,14 @@ static int qib_user_sdma_queue_pkts(const struct qib_devdata *dd,
>  		}
>  
>  		if (frag_size) {
> -			int tidsmsize, n;
> -			size_t pktsize;
> +			size_t tidsmsize, n, pktsize;
>  
>  			n = npages*((2*PAGE_SIZE/frag_size)+1);
> +			if (n >= (U16_MAX - ARRAY_SIZE(pkt->addr))) {
> +				ret = -EINVAL;
> +				goto free_pbc;
> +			}
> +
>  			pktsize = struct_size(pkt, addr, n);

And I think this is supposed to be more like this:

-                       if (n >= (U16_MAX - ARRAY_SIZE(pkt->addr))) {
+                       if (check_add_overflow(n, ARRAY_SIZE(pkt->addr),
+                                              &addrlimit) ||
+                           addrlimit > type_max(typeof(pkt->addrlimit))) {
                                ret = -EINVAL;
-                               goto free_pbc;
+                               goto free pbc;
                        }

And this is probably missing too:

-                       pkt = kmalloc(pktsize+tidsmsize, GFP_KERNEL);
+                       pktsize = struct_size(pkt, addr, n);
+                       if (check_add_overflow(pktsize, tidsmsize,
+                                              &allocsize)) {
+                               ret = -EINVAL;
+                               goto free_pbc;
+                       }
+                       pkt = kmalloc(allocsize, GFP_KERNEL);

The struct_size() of this:

struct qib_user_sdma_pkt {
	struct {
	} addr[4];   /* max pages, any more and we coalesce */
};

Is also super weird, that addr[4] should typically be [0]

Jason



[Index of Archives]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Photo]     [Yosemite News]     [Yosemite Photos]     [Linux Kernel]     [Linux SCSI]     [XFree86]

  Powered by Linux