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