IB/ipath: Fix possible data corruption if multiple SGEs used for receive
authorRalph Campbell <ralph.campbell@qlogic.com>
Mon, 18 Jun 2007 21:24:44 +0000 (14:24 -0700)
committerRoland Dreier <rolandd@cisco.com>
Tue, 10 Jul 2007 03:12:26 +0000 (20:12 -0700)
The code to copy data from the receive queue buffers to the IB SGEs
doesn't check the SGE length, only the memory region/page length when
copying data.  This could overwrite parts of the user's memory that
were not intended to be written.  It can only happen if multiple SGEs
are used to describe a receive buffer which almost never happens in
practice.

Signed-off-by: Ralph Campbell <ralph.campbell@qlogic.com>
Signed-off-by: Roland Dreier <rolandd@cisco.com>
drivers/infiniband/hw/ipath/ipath_ruc.c
drivers/infiniband/hw/ipath/ipath_ud.c
drivers/infiniband/hw/ipath/ipath_verbs.c

index 837118676cc779c8fde1b5f926aca37fbb561ee0..1b0e62b761bb011bc9ae8e37205727ba60035b04 100644 (file)
@@ -396,6 +396,8 @@ again:
 
                if (len > sge->length)
                        len = sge->length;
+               if (len > sge->sge_length)
+                       len = sge->sge_length;
                BUG_ON(len == 0);
                ipath_copy_sge(&qp->r_sge, sge->vaddr, len);
                sge->vaddr += len;
index a518f7c8fa83a9372fc9a5327e646825876261bf..0b5a6ac1bb830dcef450951bae70bff1a0bd71e2 100644 (file)
@@ -231,6 +231,8 @@ static void ipath_ud_loopback(struct ipath_qp *sqp,
 
                if (len > length)
                        len = length;
+               if (len > sge->sge_length)
+                       len = sge->sge_length;
                BUG_ON(len == 0);
                ipath_copy_sge(&rsge, sge->vaddr, len);
                sge->vaddr += len;
index cd79a8ca5104213426ba5b82acea6131da2411e3..35241b76d766a7a946a2d3e0fb466e83eece32a2 100644 (file)
@@ -164,9 +164,11 @@ void ipath_copy_sge(struct ipath_sge_state *ss, void *data, u32 length)
        while (length) {
                u32 len = sge->length;
 
-               BUG_ON(len == 0);
                if (len > length)
                        len = length;
+               if (len > sge->sge_length)
+                       len = sge->sge_length;
+               BUG_ON(len == 0);
                memcpy(sge->vaddr, data, len);
                sge->vaddr += len;
                sge->length -= len;
@@ -202,9 +204,11 @@ void ipath_skip_sge(struct ipath_sge_state *ss, u32 length)
        while (length) {
                u32 len = sge->length;
 
-               BUG_ON(len == 0);
                if (len > length)
                        len = length;
+               if (len > sge->sge_length)
+                       len = sge->sge_length;
+               BUG_ON(len == 0);
                sge->vaddr += len;
                sge->length -= len;
                sge->sge_length -= len;