]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
scsi: core: Convert INQUIRY information
authorBart Van Assche <bvanassche@acm.org>
Fri, 15 May 2026 20:52:21 +0000 (13:52 -0700)
committerMartin K. Petersen <martin.petersen@oracle.com>
Sat, 23 May 2026 01:49:05 +0000 (21:49 -0400)
Currently the vendor, model, and revision members of struct scsi_device
are pointers to fixed-length strings that are not NUL-terminated.
Fixed-precision format specifiers (e.g., "%.8s") are required whenever
they are printed and strncmp() must be used to compare these fields.
This is error-prone.

Convert these fields to fixed-size character arrays within struct
scsi_device. Remove an !sdev->model check because sdev->model is now
guaranteed not to be NULL.

This patch fixes a bug in the qla2xxx driver. It makes the following
code safe:

if (state_flags & BIT_4)
scmd_printk(KERN_WARNING, cp,
    "Unsupported device '%s' found.\n",
    cp->device->vendor);

Signed-off-by: Bart Van Assche <bvanassche@acm.org>
Tested-by: Brian Bunker <brian@purestorage.com>
Link: https://patch.msgid.link/20260515205222.1754621-4-bvanassche@acm.org
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/hwmon/drivetemp.c
drivers/scsi/scsi_scan.c
include/scsi/scsi_device.h

index 002e0660a0b87eef2e474184354131c213a22eab..efe8b229bdbe2d4ba66de1a9d8a8501fbd518892 100644 (file)
@@ -306,13 +306,10 @@ static bool drivetemp_sct_avoid(struct drivetemp_data *st)
        struct scsi_device *sdev = st->sdev;
        unsigned int ctr;
 
-       if (!sdev->model)
-               return false;
-
        /*
         * The "model" field contains just the raw SCSI INQUIRY response
         * "product identification" field, which has a width of 16 bytes.
-        * This field is space-filled, but is NOT NULL-terminated.
+        * This field is space-filled and NUL-terminated.
         */
        for (ctr = 0; ctr < ARRAY_SIZE(sct_avoid_models); ctr++)
                if (!strncmp(sdev->model, sct_avoid_models[ctr],
index b0473f4595c17745d1f927f71d30c53ca79a6856..7e60e3a4bca66b96b2e79d68bdc6b845b5344624 100644 (file)
@@ -292,9 +292,9 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget,
        if (!sdev)
                goto out;
 
-       sdev->vendor = scsi_null_device_strs;
-       sdev->model = scsi_null_device_strs;
-       sdev->rev = scsi_null_device_strs;
+       strscpy(sdev->vendor, scsi_null_device_strs);
+       strscpy(sdev->model, scsi_null_device_strs);
+       strscpy(sdev->rev, scsi_null_device_strs);
        sdev->host = shost;
        sdev->queue_ramp_up_period = SCSI_DEFAULT_RAMP_UP_PERIOD;
        sdev->id = starget->id;
@@ -910,9 +910,15 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result,
        if (sdev->inquiry == NULL)
                return SCSI_SCAN_NO_RESPONSE;
 
-       sdev->vendor = (char *) (sdev->inquiry + 8);
-       sdev->model = (char *) (sdev->inquiry + 16);
-       sdev->rev = (char *) (sdev->inquiry + 32);
+       strscpy(sdev->vendor, sdev->inquiry + INQUIRY_VENDOR_OFFSET);
+       strscpy(sdev->model, sdev->inquiry + INQUIRY_MODEL_OFFSET);
+       /*
+        * memcpy() instead of strscpy() because strscpy() would read past
+        * the end of sdev->inquiry if its length is exactly 36 bytes.
+        */
+       memcpy(sdev->rev, sdev->inquiry + INQUIRY_REVISION_OFFSET,
+              INQUIRY_REVISION_LEN);
+       sdev->rev[INQUIRY_REVISION_LEN] = '\0';
 
        sdev->is_ata = strncmp(sdev->vendor, "ATA     ", 8) == 0;
        if (sdev->is_ata) {
index 9c2a7bbe5891efbcb3bd12b29983138f04a15abc..029f5115b2ea09306fe1b8006372891bc9e13e8a 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/workqueue.h>
 #include <linux/blk-mq.h>
 #include <scsi/scsi.h>
+#include <scsi/scsi_common.h>
 #include <linux/atomic.h>
 #include <linux/sbitmap.h>
 
@@ -137,9 +138,9 @@ struct scsi_device {
        struct mutex inquiry_mutex;
        unsigned char inquiry_len;      /* valid bytes in 'inquiry' */
        unsigned char * inquiry;        /* INQUIRY response data */
-       const char * vendor;            /* [back_compat] point into 'inquiry' ... */
-       const char * model;             /* ... after scan; point to static string */
-       const char * rev;               /* ... "nullnullnullnull" before scan */
+       char vendor[INQUIRY_VENDOR_LEN + 1];
+       char model[INQUIRY_MODEL_LEN + 1];
+       char rev[INQUIRY_REVISION_LEN + 1];
 
 #define SCSI_DEFAULT_VPD_LEN   255     /* default SCSI VPD page size (max) */
        struct scsi_vpd __rcu *vpd_pg0;