]> git.itanic.dy.fi Git - linux-stable/commitdiff
scsi: ses: Fix possible addl_desc_ptr out-of-bounds accesses
authorTomas Henzl <thenzl@redhat.com>
Thu, 2 Feb 2023 16:24:49 +0000 (17:24 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 10 Mar 2023 08:34:29 +0000 (09:34 +0100)
commit db95d4df71cb55506425b6e4a5f8d68e3a765b63 upstream.

Sanitize possible addl_desc_ptr out-of-bounds accesses in
ses_enclosure_data_process().

Link: https://lore.kernel.org/r/20230202162451.15346-3-thenzl@redhat.com
Cc: stable@vger.kernel.org
Signed-off-by: Tomas Henzl <thenzl@redhat.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/scsi/ses.c

index 4739c03b4e1d1d307bcddd9d51ad9694231f5951..4b66f9aec0f4a8a666d626da4c1cef1d278faae8 100644 (file)
@@ -433,8 +433,8 @@ int ses_match_host(struct enclosure_device *edev, void *data)
 }
 #endif  /*  0  */
 
-static void ses_process_descriptor(struct enclosure_component *ecomp,
-                                  unsigned char *desc)
+static int ses_process_descriptor(struct enclosure_component *ecomp,
+                                  unsigned char *desc, int max_desc_len)
 {
        int eip = desc[0] & 0x10;
        int invalid = desc[0] & 0x80;
@@ -445,22 +445,32 @@ static void ses_process_descriptor(struct enclosure_component *ecomp,
        unsigned char *d;
 
        if (invalid)
-               return;
+               return 0;
 
        switch (proto) {
        case SCSI_PROTOCOL_FCP:
                if (eip) {
+                       if (max_desc_len <= 7)
+                               return 1;
                        d = desc + 4;
                        slot = d[3];
                }
                break;
        case SCSI_PROTOCOL_SAS:
+
                if (eip) {
+                       if (max_desc_len <= 27)
+                               return 1;
                        d = desc + 4;
                        slot = d[3];
                        d = desc + 8;
-               } else
+               } else {
+                       if (max_desc_len <= 23)
+                               return 1;
                        d = desc + 4;
+               }
+
+
                /* only take the phy0 addr */
                addr = (u64)d[12] << 56 |
                        (u64)d[13] << 48 |
@@ -477,6 +487,8 @@ static void ses_process_descriptor(struct enclosure_component *ecomp,
        }
        ecomp->slot = slot;
        scomp->addr = addr;
+
+       return 0;
 }
 
 struct efd {
@@ -549,7 +561,7 @@ static void ses_enclosure_data_process(struct enclosure_device *edev,
                /* skip past overall descriptor */
                desc_ptr += len + 4;
        }
-       if (ses_dev->page10)
+       if (ses_dev->page10 && ses_dev->page10_len > 9)
                addl_desc_ptr = ses_dev->page10 + 8;
        type_ptr = ses_dev->page1_types;
        components = 0;
@@ -557,6 +569,7 @@ static void ses_enclosure_data_process(struct enclosure_device *edev,
                for (j = 0; j < type_ptr[1]; j++) {
                        char *name = NULL;
                        struct enclosure_component *ecomp;
+                       int max_desc_len;
 
                        if (desc_ptr) {
                                if (desc_ptr >= buf + page7_len) {
@@ -583,10 +596,14 @@ static void ses_enclosure_data_process(struct enclosure_device *edev,
                                        ecomp = &edev->component[components++];
 
                                if (!IS_ERR(ecomp)) {
-                                       if (addl_desc_ptr)
-                                               ses_process_descriptor(
-                                                       ecomp,
-                                                       addl_desc_ptr);
+                                       if (addl_desc_ptr) {
+                                               max_desc_len = ses_dev->page10_len -
+                                                   (addl_desc_ptr - ses_dev->page10);
+                                               if (ses_process_descriptor(ecomp,
+                                                   addl_desc_ptr,
+                                                   max_desc_len))
+                                                       addl_desc_ptr = NULL;
+                                       }
                                        if (create)
                                                enclosure_component_register(
                                                        ecomp);