|
|
b233244 |
From 4abc12dd59bed74aa1730c2b3129d1750604d530 Mon Sep 17 00:00:00 2001
|
|
|
b233244 |
From: Alan Stern <stern@rowland.harvard.edu>
|
|
|
b233244 |
Date: Mon, 3 Aug 2015 11:57:29 -0400
|
|
|
b233244 |
Subject: [PATCH 2/2] SCSI: fix bug in scsi_dev_info_list matching
|
|
|
b233244 |
|
|
|
b233244 |
The "compatible" matching algorithm used for looking up old-style
|
|
|
b233244 |
blacklist entries in a scsi_dev_info_list is buggy. The core of the
|
|
|
b233244 |
algorithm looks like this:
|
|
|
b233244 |
|
|
|
b233244 |
if (memcmp(devinfo->vendor, vendor,
|
|
|
b233244 |
min(max, strlen(devinfo->vendor))))
|
|
|
b233244 |
/* not a match */
|
|
|
b233244 |
|
|
|
b233244 |
where max is the length of the device's vendor string after leading
|
|
|
b233244 |
spaces have been removed but trailing spaces have not. Because of the
|
|
|
b233244 |
min() computation, either entry could be a proper substring of the
|
|
|
b233244 |
other and the code would still think that they match.
|
|
|
b233244 |
|
|
|
b233244 |
In the case originally reported, the device's vendor and product
|
|
|
b233244 |
strings were "Inateck " and " ". These matched against
|
|
|
b233244 |
the following entry in the global device list:
|
|
|
b233244 |
|
|
|
b233244 |
{"", "Scanner", "1.80", BLIST_NOLUN}
|
|
|
b233244 |
|
|
|
b233244 |
because "" is a substring of "Inateck " and "" (the result of removing
|
|
|
b233244 |
leading spaces from the device's product string) is a substring of
|
|
|
b233244 |
"Scanner". The mistaken match prevented the system from scanning and
|
|
|
b233244 |
finding the device's second Logical Unit.
|
|
|
b233244 |
|
|
|
b233244 |
This patch fixes the problem by making two changes. First, the code
|
|
|
b233244 |
for leading-space removal is hoisted out of the loop. (This means it
|
|
|
b233244 |
will sometimes run unnecessarily, but since a large percentage of all
|
|
|
b233244 |
lookups involve the "compatible" entries in global device list, this
|
|
|
b233244 |
should be an overall improvement.) Second and more importantly, the
|
|
|
b233244 |
patch removes trailing spaces and adds a check to verify that the two
|
|
|
b233244 |
resulting strings are exactly the same length. This prevents matches
|
|
|
b233244 |
where one entry is a proper substring of the other.
|
|
|
b233244 |
|
|
|
b233244 |
Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
|
|
|
b233244 |
Reported-by: Giulio Bernardi <ugilio@gmail.com>
|
|
|
b233244 |
Tested-by: Giulio Bernardi <ugilio@gmail.com>
|
|
|
b233244 |
Signed-off-by: James Bottomley <JBottomley@Odin.com>
|
|
|
b233244 |
---
|
|
|
b233244 |
drivers/scsi/scsi_devinfo.c | 69 +++++++++++++++++++++++----------------------
|
|
|
b233244 |
1 file changed, 35 insertions(+), 34 deletions(-)
|
|
|
b233244 |
|
|
|
b233244 |
diff --git a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c
|
|
|
b233244 |
index 2f49a224462d..2c1160c7ec92 100644
|
|
|
b233244 |
--- a/drivers/scsi/scsi_devinfo.c
|
|
|
b233244 |
+++ b/drivers/scsi/scsi_devinfo.c
|
|
|
b233244 |
@@ -407,51 +407,52 @@ static struct scsi_dev_info_list *scsi_dev_info_list_find(const char *vendor,
|
|
|
b233244 |
struct scsi_dev_info_list *devinfo;
|
|
|
b233244 |
struct scsi_dev_info_list_table *devinfo_table =
|
|
|
b233244 |
scsi_devinfo_lookup_by_key(key);
|
|
|
b233244 |
+ size_t vmax, mmax;
|
|
|
b233244 |
+ const char *vskip, *mskip;
|
|
|
b233244 |
|
|
|
b233244 |
if (IS_ERR(devinfo_table))
|
|
|
b233244 |
return (struct scsi_dev_info_list *) devinfo_table;
|
|
|
b233244 |
|
|
|
b233244 |
+ /* Prepare for "compatible" matches */
|
|
|
b233244 |
+
|
|
|
b233244 |
+ /*
|
|
|
b233244 |
+ * XXX why skip leading spaces? If an odd INQUIRY
|
|
|
b233244 |
+ * value, that should have been part of the
|
|
|
b233244 |
+ * scsi_static_device_list[] entry, such as " FOO"
|
|
|
b233244 |
+ * rather than "FOO". Since this code is already
|
|
|
b233244 |
+ * here, and we don't know what device it is
|
|
|
b233244 |
+ * trying to work with, leave it as-is.
|
|
|
b233244 |
+ */
|
|
|
b233244 |
+ vmax = 8; /* max length of vendor */
|
|
|
b233244 |
+ vskip = vendor;
|
|
|
b233244 |
+ while (vmax > 0 && *vskip == ' ') {
|
|
|
b233244 |
+ vmax--;
|
|
|
b233244 |
+ vskip++;
|
|
|
b233244 |
+ }
|
|
|
b233244 |
+ /* Also skip trailing spaces */
|
|
|
b233244 |
+ while (vmax > 0 && vskip[vmax - 1] == ' ')
|
|
|
b233244 |
+ --vmax;
|
|
|
b233244 |
+
|
|
|
b233244 |
+ mmax = 16; /* max length of model */
|
|
|
b233244 |
+ mskip = model;
|
|
|
b233244 |
+ while (mmax > 0 && *mskip == ' ') {
|
|
|
b233244 |
+ mmax--;
|
|
|
b233244 |
+ mskip++;
|
|
|
b233244 |
+ }
|
|
|
b233244 |
+ while (mmax > 0 && mskip[mmax - 1] == ' ')
|
|
|
b233244 |
+ --mmax;
|
|
|
b233244 |
+
|
|
|
b233244 |
list_for_each_entry(devinfo, &devinfo_table->scsi_dev_info_list,
|
|
|
b233244 |
dev_info_list) {
|
|
|
b233244 |
if (devinfo->compatible) {
|
|
|
b233244 |
/*
|
|
|
b233244 |
* Behave like the older version of get_device_flags.
|
|
|
b233244 |
*/
|
|
|
b233244 |
- size_t max;
|
|
|
b233244 |
- /*
|
|
|
b233244 |
- * XXX why skip leading spaces? If an odd INQUIRY
|
|
|
b233244 |
- * value, that should have been part of the
|
|
|
b233244 |
- * scsi_static_device_list[] entry, such as " FOO"
|
|
|
b233244 |
- * rather than "FOO". Since this code is already
|
|
|
b233244 |
- * here, and we don't know what device it is
|
|
|
b233244 |
- * trying to work with, leave it as-is.
|
|
|
b233244 |
- */
|
|
|
b233244 |
- max = 8; /* max length of vendor */
|
|
|
b233244 |
- while ((max > 0) && *vendor == ' ') {
|
|
|
b233244 |
- max--;
|
|
|
b233244 |
- vendor++;
|
|
|
b233244 |
- }
|
|
|
b233244 |
- /*
|
|
|
b233244 |
- * XXX removing the following strlen() would be
|
|
|
b233244 |
- * good, using it means that for a an entry not in
|
|
|
b233244 |
- * the list, we scan every byte of every vendor
|
|
|
b233244 |
- * listed in scsi_static_device_list[], and never match
|
|
|
b233244 |
- * a single one (and still have to compare at
|
|
|
b233244 |
- * least the first byte of each vendor).
|
|
|
b233244 |
- */
|
|
|
b233244 |
- if (memcmp(devinfo->vendor, vendor,
|
|
|
b233244 |
- min(max, strlen(devinfo->vendor))))
|
|
|
b233244 |
+ if (memcmp(devinfo->vendor, vskip, vmax) ||
|
|
|
b233244 |
+ devinfo->vendor[vmax])
|
|
|
b233244 |
continue;
|
|
|
b233244 |
- /*
|
|
|
b233244 |
- * Skip spaces again.
|
|
|
b233244 |
- */
|
|
|
b233244 |
- max = 16; /* max length of model */
|
|
|
b233244 |
- while ((max > 0) && *model == ' ') {
|
|
|
b233244 |
- max--;
|
|
|
b233244 |
- model++;
|
|
|
b233244 |
- }
|
|
|
b233244 |
- if (memcmp(devinfo->model, model,
|
|
|
b233244 |
- min(max, strlen(devinfo->model))))
|
|
|
b233244 |
+ if (memcmp(devinfo->model, mskip, mmax) ||
|
|
|
b233244 |
+ devinfo->model[mmax])
|
|
|
b233244 |
continue;
|
|
|
b233244 |
return devinfo;
|
|
|
b233244 |
} else {
|
|
|
b233244 |
--
|
|
|
b233244 |
2.5.0
|
|
|
b233244 |
|