Skip to contentSkip to conversation

scsi: ufs: Fix unexpected values get from ufshcd_read_desc_param()

PATCH Applied Can Guo 4 participants 7 messages Oct 22, 2020 – Nov 19, 2020 SCSI

lore
Share & tools
lore

Can Guo

author
#0 lore raw

PATCH v2 1/1 scsi: ufs: Fix unexpected values get from ufshcd_read_desc_param()

Since WB feature has been added, WB related sysfs entries can be accessed even when an UFS device does not support WB feature. In that case, the descriptors which are not supported by the UFS device may be wrongly reported when they are accessed from their corrsponding sysfs entries. Fix it by adding a sanity check of parameter offset against the actual decriptor length.

---
 drivers/scsi/ufs/ufshcd.c | 24 +++++++++++++++---------
 1 file changed, 15 insertions(+), 9 deletions(-)
drivers/scsi/ufs/ufshcd.c +15 -9
index a2ebcc8..aeec10d 100644
@@ -3184,13 +3184,19 @@ int ufshcd_read_desc_param(struct ufs_hba *hba,
 	/* Get the length of descriptor */
 	ufshcd_map_desc_id_to_length(hba, desc_id, &buff_len);
 	if (!buff_len) {
-		dev_err(hba->dev, "%s: Failed to get desc length", __func__);
+		dev_err(hba->dev, "%s: Failed to get desc length\n", __func__);
+		return -EINVAL;
+	}
+
+	if (param_offset >= buff_len) {
+		dev_err(hba->dev, "%s: Invalid offset 0x%x in descriptor IDN 0x%x, length 0x%x\n",
+			__func__, param_offset, desc_id, buff_len);
 		return -EINVAL;
 	}
 
 	/* Check whether we need temp memory */
 	if (param_offset != 0 || param_size < buff_len) {
-		desc_buf = kmalloc(buff_len, GFP_KERNEL);
+		desc_buf = kzalloc(buff_len, GFP_KERNEL);
 		if (!desc_buf)
 			return -ENOMEM;
 	} else {
@@ -3204,14 +3210,14 @@ int ufshcd_read_desc_param(struct ufs_hba *hba,
 					desc_buf, &buff_len);
 
 	if (ret) {
-		dev_err(hba->dev, "%s: Failed reading descriptor. desc_id %d, desc_index %d, param_offset %d, ret %d",
+		dev_err(hba->dev, "%s: Failed reading descriptor. desc_id %d, desc_index %d, param_offset %d, ret %d\n",
 			__func__, desc_id, desc_index, param_offset, ret);
 		goto out;
 	}
 
 	/* Sanity check */
 	if (desc_buf[QUERY_DESC_DESC_TYPE_OFFSET] != desc_id) {
-		dev_err(hba->dev, "%s: invalid desc_id %d in descriptor header",
+		dev_err(hba->dev, "%s: invalid desc_id %d in descriptor header\n",
 			__func__, desc_buf[QUERY_DESC_DESC_TYPE_OFFSET]);
 		ret = -EINVAL;
 		goto out;
@@ -3221,12 +3227,12 @@ int ufshcd_read_desc_param(struct ufs_hba *hba,
 	buff_len = desc_buf[QUERY_DESC_LENGTH_OFFSET];
 	ufshcd_update_desc_length(hba, desc_id, desc_index, buff_len);
 
-	/* Check wherher we will not copy more data, than available */
-	if (is_kmalloc && (param_offset + param_size) > buff_len)
-		param_size = buff_len - param_offset;
-
-	if (is_kmalloc)
+	if (is_kmalloc) {
+		/* Make sure we don't copy more data than available */
+		if (param_offset + param_size > buff_len)
+			param_size = buff_len - param_offset;
 		memcpy(param_read_buf, &desc_buf[param_offset], param_size);
+	}
 out:
 	if (is_kmalloc)
 		kfree(desc_buf);
Signature · 1 line
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.
#1 lore raw
Quoted 6 lines

Since WB feature has been added, WB related sysfs entries can be accessed even when an UFS device does not support WB feature. In that case, the descriptors which are not supported by the UFS device may be wrongly reported when they are accessed from their corrsponding sysfs entries. Fix it by adding a sanity check of parameter offset against the actual decriptor length.s

This should be a bug fix IMO, and be dealt with similarly like ufshcd_is_wb_attrs or ufshcd_is_wb_flag. Thanks,
Avri

author
#2 lore raw

Hi Avri,

Quoted 10 lines · Avri Altman
Quoted 6 lines

Since WB feature has been added, WB related sysfs entries can be accessed even when an UFS device does not support WB feature. In that case, the descriptors which are not supported by the UFS device may be wrongly reported when they are accessed from their corrsponding sysfs entries. Fix it by adding a sanity check of parameter offset against the actual decriptor length.s

This should be a bug fix IMO, and be dealt with similarly like ufshcd_is_wb_attrs or ufshcd_is_wb_flag.
Thanks,
Avri

Could you please elaborate on ufshcd_is_wb_attrs or ufshcd_is_wb_flag? Sorry that I don't quite get it.

Thanks,

Can Guo.

#3 lore raw
Quoted 9 lines · Avri Altman
Quoted 7 lines
Quoted 7 lines

Since WB feature has been added, WB related sysfs entries can be accessed
even when an UFS device does not support WB feature. In that case, the descriptors which are not supported by the UFS device may be wrongly reported when they are accessed from their corrsponding sysfs entries. Fix it by adding a sanity check of parameter offset against the actual decriptor length.s

Quoted 7 lines
Quoted 4 lines

This should be a bug fix IMO, and be dealt with similarly like ufshcd_is_wb_attrs or ufshcd_is_wb_flag.
Thanks,
Avri

Could you please elaborate on ufshcd_is_wb_attrs or ufshcd_is_wb_flag? Sorry that I don't quite get it.

Since this change is only protecting illegal access from sysfs entries, I am suggesting to handle it there, just like ufshcd_is_wb_attrs or ufshcd_is_wb_flag Are doing it for flags and attributes.

Thanks,
Avri

author
#4 lore raw
Quoted 15 lines · Avri Altman
Quoted 8 lines · Avri Altman
Quoted 7 lines
Quoted 7 lines

Since WB feature has been added, WB related sysfs entries can be accessed
even when an UFS device does not support WB feature. In that case, the descriptors which are not supported by the UFS device may be wrongly reported when they are accessed from their corrsponding sysfs entries. Fix it by adding a sanity check of parameter offset against the actual decriptor length.s

Quoted 7 lines
Quoted 4 lines

This should be a bug fix IMO, and be dealt with similarly like ufshcd_is_wb_attrs or ufshcd_is_wb_flag.
Thanks,
Avri

Could you please elaborate on ufshcd_is_wb_attrs or ufshcd_is_wb_flag? Sorry that I don't quite get it.

Quoted 7 lines

Since this change is only protecting illegal access from sysfs entries, I am suggesting to handle it there, just like ufshcd_is_wb_attrs or ufshcd_is_wb_flag
Are doing it for flags and attributes.

Thanks,
Avri

This is a general problem - if later we have HPB entries added into sysfs, we will hit it again. We cannot keep adding checks like ufshcd_is_xxx_attrs or ufshcd_is_xxx_flag to block them, right?

Thanks,

Can Guo.

Reviewed-by on v2 1/1
#5 lore raw
In reply to Can Guo
Quoted 9 lines · Can Guo

Since WB feature has been added, WB related sysfs entries can be accessed even when an UFS device does not support WB feature. In that case, the descriptors which are not supported by the UFS device may be wrongly reported when they are accessed from their corrsponding sysfs entries. Fix it by adding a sanity check of parameter offset against the actual decriptor length.

---

Quoted 65 lines
  drivers/scsi/ufs/ufshcd.c | 24 +++++++++++++++---------
  1 file changed, 15 insertions(+), 9 deletions(-)
drivers/scsi/ufs/ufshcd.c +15 -9
index a2ebcc8..aeec10d 100644
@@ -3184,13 +3184,19 @@ int ufshcd_read_desc_param(struct ufs_hba *hba,
  	/* Get the length of descriptor */
  	ufshcd_map_desc_id_to_length(hba, desc_id, &buff_len);
  	if (!buff_len) {
-		dev_err(hba->dev, "%s: Failed to get desc length", __func__);
+		dev_err(hba->dev, "%s: Failed to get desc length\n", __func__);
+		return -EINVAL;
+	}
+
+	if (param_offset >= buff_len) {
+		dev_err(hba->dev, "%s: Invalid offset 0x%x in descriptor IDN 0x%x, length 0x%x\n",
+			__func__, param_offset, desc_id, buff_len);
  		return -EINVAL;
  	}
 
  	/* Check whether we need temp memory */
  	if (param_offset != 0 || param_size < buff_len) {
-		desc_buf = kmalloc(buff_len, GFP_KERNEL);
+		desc_buf = kzalloc(buff_len, GFP_KERNEL);
  		if (!desc_buf)
  			return -ENOMEM;
  	} else {
@@ -3204,14 +3210,14 @@ int ufshcd_read_desc_param(struct ufs_hba *hba,
  					desc_buf, &buff_len);
 
  	if (ret) {
-		dev_err(hba->dev, "%s: Failed reading descriptor. desc_id %d, desc_index %d, param_offset %d, ret %d",
+		dev_err(hba->dev, "%s: Failed reading descriptor. desc_id %d, desc_index %d, param_offset %d, ret %d\n",
  			__func__, desc_id, desc_index, param_offset, ret);
  		goto out;
  	}
 
  	/* Sanity check */
  	if (desc_buf[QUERY_DESC_DESC_TYPE_OFFSET] != desc_id) {
-		dev_err(hba->dev, "%s: invalid desc_id %d in descriptor header",
+		dev_err(hba->dev, "%s: invalid desc_id %d in descriptor header\n",
  			__func__, desc_buf[QUERY_DESC_DESC_TYPE_OFFSET]);
  		ret = -EINVAL;
  		goto out;
@@ -3221,12 +3227,12 @@ int ufshcd_read_desc_param(struct ufs_hba *hba,
  	buff_len = desc_buf[QUERY_DESC_LENGTH_OFFSET];
  	ufshcd_update_desc_length(hba, desc_id, desc_index, buff_len);
 
-	/* Check wherher we will not copy more data, than available */
-	if (is_kmalloc && (param_offset + param_size) > buff_len)
-		param_size = buff_len - param_offset;
-
-	if (is_kmalloc)
+	if (is_kmalloc) {
+		/* Make sure we don't copy more data than available */
+		if (param_offset + param_size > buff_len)
+			param_size = buff_len - param_offset;
  		memcpy(param_read_buf, &desc_buf[param_offset], param_size);
+	}
  out:
  	if (is_kmalloc)
  		kfree(desc_buf);
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
Linux Foundation Collaborative Project
#6 lore raw
In reply to Can Guo
Quoted 6 lines · Can Guo

Since WB feature has been added, WB related sysfs entries can be accessed even when an UFS device does not support WB feature. In that case, the descriptors which are not supported by the UFS device may be wrongly reported when they are accessed from their corrsponding sysfs entries. Fix it by adding a sanity check of parameter offset against the actual decriptor length.

Applied to 5.10/scsi-fixes, thanks!

[1/1] scsi: ufs: Fix unexpected values from ufshcd_read_desc_param()

      https://git.kernel.org/mkp/scsi/c/1699f980d87f
Signature · 1 line
Martin K. Petersen	Oracle Linux Engineering