Ticket #1934: 0001-Fix-buffer-overflow-parsing-VPD-page-0x83.patch

File 0001-Fix-buffer-overflow-parsing-VPD-page-0x83.patch, 6.1 KB (added by Ross Lagerwall, 26 hours ago)
  • scsicmds.cpp

    From fef5ad8a42c040b001eae95ff2cebfce968959e9 Mon Sep 17 00:00:00 2001
    From: Ross Lagerwall <ross.lagerwall@citrix.com>
    Date: Fri, 21 Feb 2025 12:15:35 +0000
    Subject: [PATCH 1/2] Fix buffer overflow parsing VPD page 0x83
    
    The VPD page 0x83 may contain unexpected information, causing smartd to
    want to write more than the allocated buffer. The existing use of
    snprintf in scsi_decode_lu_dev_id() is incorrect. If the buffer is too
    small, snprintf returns the number of bytes it would have written
    which gets added to the total (si). On the next call to snprintf, it
    subtracts the total written from the size of the buffer and gets a
    negative integer which is passed as a size_t, becoming a very large
    positive integer and leaving snprintf to freely overflow the buffer.
    
    Defend against this by ensuring the size passed to snprintf is >= 0.
    
    Signed-off-by: Ross Lagerwall <ross.lagerwall@citrix.com>
    ---
     scsicmds.cpp | 38 ++++++++++++++++++++------------------
     1 file changed, 20 insertions(+), 18 deletions(-)
    
    diff --git a/scsicmds.cpp b/scsicmds.cpp
    index 2d1190659c15..e5e26851685a 100644
    a b scsi_decode_lu_dev_id(const unsigned char * b, int blen, char * s, int slen,  
    755755        return -1;
    756756    }
    757757
     758#define SLEN(a, b) ((a) > (b) ? ((a) - (b)) : 0)
    758759    s[0] = '\0';
    759760    int si = 0;
    760761    int have_scsi_ns = 0;
    scsi_decode_lu_dev_id(const unsigned char * b, int blen, char * s, int slen,  
    764765        const unsigned char * ucp = b + off;
    765766        int i_len = ucp[3];
    766767        if ((off + i_len + 4) > blen) {
    767             snprintf(s+si, slen-si, "error: designator length");
     768            snprintf(s+si, SLEN(slen, si), "error: designator length");
    768769            return -1;
    769770        }
    770771        int assoc = ((ucp[1] >> 4) & 0x3);
    scsi_decode_lu_dev_id(const unsigned char * b, int blen, char * s, int slen,  
    783784            break;
    784785        case 2: /* EUI-64 based */
    785786            if ((8 != i_len) && (12 != i_len) && (16 != i_len)) {
    786                 snprintf(s+si, slen-si, "error: EUI-64 length");
     787                snprintf(s+si, SLEN(slen, si), "error: EUI-64 length");
    787788                return -1;
    788789            }
    789790            if (have_scsi_ns)
    790791                si = 0;
    791             si += snprintf(s+si, slen-si, "0x");
     792            si += snprintf(s+si, SLEN(slen, si), "0x");
    792793            for (int m = 0; m < i_len; ++m)
    793                 si += snprintf(s+si, slen-si, "%02x", (unsigned int)ip[m]);
     794                si += snprintf(s+si, SLEN(slen, si), "%02x", (unsigned int)ip[m]);
    794795            break;
    795796        case 3: /* NAA */
    796797            if (1 != c_set) {
    797                 snprintf(s+si, slen-si, "error: NAA bad code_set");
     798                snprintf(s+si, SLEN(slen, si), "error: NAA bad code_set");
    798799                return -1;
    799800            }
    800801            naa = (ip[0] >> 4) & 0xff;
    801802            if ((naa < 2) || (naa > 6) || (4 == naa)) {
    802                 snprintf(s+si, slen-si, "error: unexpected NAA");
     803                snprintf(s+si, SLEN(slen, si), "error: unexpected NAA");
    803804                return -1;
    804805            }
    805806            if (have_scsi_ns)
    806807                si = 0;
    807808            if (2 == naa) {             /* NAA IEEE Extended */
    808809                if (8 != i_len) {
    809                     snprintf(s+si, slen-si, "error: NAA 2 length");
     810                    snprintf(s+si, SLEN(slen, si), "error: NAA 2 length");
    810811                    return -1;
    811812                }
    812                 si += snprintf(s+si, slen-si, "0x");
     813                si += snprintf(s+si, SLEN(slen, si), "0x");
    813814                for (int m = 0; m < 8; ++m)
    814                     si += snprintf(s+si, slen-si, "%02x", (unsigned int)ip[m]);
     815                    si += snprintf(s+si, SLEN(slen, si), "%02x", (unsigned int)ip[m]);
    815816            } else if ((3 == naa ) || (5 == naa)) {
    816817                /* NAA=3 Locally assigned; NAA=5 IEEE Registered */
    817818                if (8 != i_len) {
    818                     snprintf(s+si, slen-si, "error: NAA 3 or 5 length");
     819                    snprintf(s+si, SLEN(slen, si), "error: NAA 3 or 5 length");
    819820                    return -1;
    820821                }
    821                 si += snprintf(s+si, slen-si, "0x");
     822                si += snprintf(s+si, SLEN(slen, si), "0x");
    822823                for (int m = 0; m < 8; ++m)
    823                     si += snprintf(s+si, slen-si, "%02x", (unsigned int)ip[m]);
     824                    si += snprintf(s+si, SLEN(slen, si), "%02x", (unsigned int)ip[m]);
    824825            } else if (6 == naa) {      /* NAA IEEE Registered extended */
    825826                if (16 != i_len) {
    826                     snprintf(s+si, slen-si, "error: NAA 6 length");
     827                    snprintf(s+si, SLEN(slen, si), "error: NAA 6 length");
    827828                    return -1;
    828829                }
    829                 si += snprintf(s+si, slen-si, "0x");
     830                si += snprintf(s+si, SLEN(slen, si), "0x");
    830831                for (int m = 0; m < 16; ++m)
    831                     si += snprintf(s+si, slen-si, "%02x", (unsigned int)ip[m]);
     832                    si += snprintf(s+si, SLEN(slen, si), "%02x", (unsigned int)ip[m]);
    832833            }
    833834            break;
    834835        case 4: /* Relative target port */
    scsi_decode_lu_dev_id(const unsigned char * b, int blen, char * s, int slen,  
    838839            break;
    839840        case 8: /* SCSI name string */
    840841            if (3 != c_set) {
    841                 snprintf(s+si, slen-si, "error: SCSI name string");
     842                snprintf(s+si, SLEN(slen, si), "error: SCSI name string");
    842843                return -1;
    843844            }
    844845            /* does %s print out UTF-8 ok?? */
    845846            if (si == 0) {
    846                 si += snprintf(s+si, slen-si, "%s", (const char *)ip);
     847                si += snprintf(s+si, SLEN(slen, si), "%s", (const char *)ip);
    847848                ++have_scsi_ns;
    848849            }
    849850            break;
    scsi_decode_lu_dev_id(const unsigned char * b, int blen, char * s, int slen,  
    852853        }
    853854    }
    854855    if (-2 == u) {
    855         snprintf(s+si, slen-si, "error: bad structure");
     856        snprintf(s+si, SLEN(slen, si), "error: bad structure");
    856857        return -1;
    857858    }
    858859    return 0;
     860#undef SLEN
    859861}
    860862
    861863/* Sends LOG SENSE command. Returns 0 if ok, 1 if device NOT READY, 2 if