All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] scsi: fix scsi_mode_sense()
@ 2021-08-19  7:37 Damien Le Moal
  2021-08-19  9:30 ` Niklas Cassel
  2021-08-19 17:04 ` Bart Van Assche
  0 siblings, 2 replies; 6+ messages in thread
From: Damien Le Moal @ 2021-08-19  7:37 UTC (permalink / raw)
  To: linux-scsi, Martin K . Petersen

The allocation length field of the MODE SENSE 10 command is 16-bits,
occupying bytes 7 and 8 of the CDB. With this command, access to mode
pages larger than 255 bytes is thus possible. Make sure that
scsi_mode_sense() code reflects this by initializing the allocation
length field using put_unaligned_be16() instead of directly setting
only byte 8 of the CDB with the buffer length.

While at it, also fix the folowing:
* use get_unaligned_be16() to retrieve the mode data length and block
  descriptor length fields of the mode sense reply header instead of
  using an open coded calculation.
* Fix the kdoc dbd argument explanation: the DBD bit stands for
  Disable Block Descriptor, which is the opposite of what the dbd
  argument description was.

Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
---
 drivers/scsi/scsi_lib.c | 9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index 7456a26aef51..92db00d81733 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -2070,7 +2070,7 @@ EXPORT_SYMBOL_GPL(scsi_mode_select);
 /**
  *	scsi_mode_sense - issue a mode sense, falling back from 10 to six bytes if necessary.
  *	@sdev:	SCSI device to be queried
- *	@dbd:	set if mode sense will allow block descriptors to be returned
+ *	@dbd:	set to prevent mode sense from returning block descriptors
  *	@modepage: mode page being requested
  *	@buffer: request buffer (may not be smaller than eight bytes)
  *	@len:	length of request buffer.
@@ -2112,7 +2112,7 @@ scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage,
 			len = 8;
 
 		cmd[0] = MODE_SENSE_10;
-		cmd[8] = len;
+		put_unaligned_be16(len, &cmd[7]);
 		header_length = 8;
 	} else {
 		if (len < 4)
@@ -2166,12 +2166,11 @@ scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage,
 		data->longlba = 0;
 		data->block_descriptor_length = 0;
 	} else if (use_10_for_ms) {
-		data->length = buffer[0]*256 + buffer[1] + 2;
+		data->length = get_unaligned_be16(&buffer[0]) + 2;
 		data->medium_type = buffer[2];
 		data->device_specific = buffer[3];
 		data->longlba = buffer[4] & 0x01;
-		data->block_descriptor_length = buffer[6]*256
-			+ buffer[7];
+		data->block_descriptor_length = get_unaligned_be16(&buffer[6]);
 	} else {
 		data->length = buffer[0] + 1;
 		data->medium_type = buffer[1];
-- 
2.31.1


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] scsi: fix scsi_mode_sense()
  2021-08-19  7:37 [PATCH] scsi: fix scsi_mode_sense() Damien Le Moal
@ 2021-08-19  9:30 ` Niklas Cassel
  2021-08-19  9:35   ` Damien Le Moal
  2021-08-19 17:04 ` Bart Van Assche
  1 sibling, 1 reply; 6+ messages in thread
From: Niklas Cassel @ 2021-08-19  9:30 UTC (permalink / raw)
  To: Damien Le Moal; +Cc: linux-scsi, Martin K . Petersen

On Thu, Aug 19, 2021 at 04:37:50PM +0900, Damien Le Moal wrote:
> The allocation length field of the MODE SENSE 10 command is 16-bits,
> occupying bytes 7 and 8 of the CDB. With this command, access to mode
> pages larger than 255 bytes is thus possible. Make sure that
> scsi_mode_sense() code reflects this by initializing the allocation
> length field using put_unaligned_be16() instead of directly setting
> only byte 8 of the CDB with the buffer length.
> 
> While at it, also fix the folowing:
> * use get_unaligned_be16() to retrieve the mode data length and block
>   descriptor length fields of the mode sense reply header instead of
>   using an open coded calculation.
> * Fix the kdoc dbd argument explanation: the DBD bit stands for
>   Disable Block Descriptor, which is the opposite of what the dbd
>   argument description was.
> 
> Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
> ---
>  drivers/scsi/scsi_lib.c | 9 ++++-----
>  1 file changed, 4 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
> index 7456a26aef51..92db00d81733 100644
> --- a/drivers/scsi/scsi_lib.c
> +++ b/drivers/scsi/scsi_lib.c
> @@ -2070,7 +2070,7 @@ EXPORT_SYMBOL_GPL(scsi_mode_select);
>  /**
>   *	scsi_mode_sense - issue a mode sense, falling back from 10 to six bytes if necessary.
>   *	@sdev:	SCSI device to be queried
> - *	@dbd:	set if mode sense will allow block descriptors to be returned
> + *	@dbd:	set to prevent mode sense from returning block descriptors
>   *	@modepage: mode page being requested
>   *	@buffer: request buffer (may not be smaller than eight bytes)
>   *	@len:	length of request buffer.
> @@ -2112,7 +2112,7 @@ scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage,
>  			len = 8;
>  
>  		cmd[0] = MODE_SENSE_10;
> -		cmd[8] = len;
> +		put_unaligned_be16(len, &cmd[7]);
>  		header_length = 8;
>  	} else {
>  		if (len < 4)
> @@ -2166,12 +2166,11 @@ scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage,
>  		data->longlba = 0;
>  		data->block_descriptor_length = 0;
>  	} else if (use_10_for_ms) {
> -		data->length = buffer[0]*256 + buffer[1] + 2;
> +		data->length = get_unaligned_be16(&buffer[0]) + 2;
>  		data->medium_type = buffer[2];
>  		data->device_specific = buffer[3];
>  		data->longlba = buffer[4] & 0x01;
> -		data->block_descriptor_length = buffer[6]*256
> -			+ buffer[7];
> +		data->block_descriptor_length = get_unaligned_be16(&buffer[6]);
>  	} else {
>  		data->length = buffer[0] + 1;
>  		data->medium_type = buffer[1];

(Nit:
When the subject contains "fix", I think that people automatically look
for a Fixes-tag. However, AFAIK, there isn't a caller that sends in a
length > 1 byte. So a slightly better subject might have been:
"scsi: allow scsi_mode_sense() to read more than 255 bytes")

Reviewed-by: Niklas Cassel <niklas.cassel@wdc.com>

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] scsi: fix scsi_mode_sense()
  2021-08-19  9:30 ` Niklas Cassel
@ 2021-08-19  9:35   ` Damien Le Moal
  0 siblings, 0 replies; 6+ messages in thread
From: Damien Le Moal @ 2021-08-19  9:35 UTC (permalink / raw)
  To: Niklas Cassel; +Cc: linux-scsi, Martin K . Petersen

On 2021/08/19 18:30, Niklas Cassel wrote:
> On Thu, Aug 19, 2021 at 04:37:50PM +0900, Damien Le Moal wrote:
>> The allocation length field of the MODE SENSE 10 command is 16-bits,
>> occupying bytes 7 and 8 of the CDB. With this command, access to mode
>> pages larger than 255 bytes is thus possible. Make sure that
>> scsi_mode_sense() code reflects this by initializing the allocation
>> length field using put_unaligned_be16() instead of directly setting
>> only byte 8 of the CDB with the buffer length.
>>
>> While at it, also fix the folowing:
>> * use get_unaligned_be16() to retrieve the mode data length and block
>>   descriptor length fields of the mode sense reply header instead of
>>   using an open coded calculation.
>> * Fix the kdoc dbd argument explanation: the DBD bit stands for
>>   Disable Block Descriptor, which is the opposite of what the dbd
>>   argument description was.
>>
>> Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
>> ---
>>  drivers/scsi/scsi_lib.c | 9 ++++-----
>>  1 file changed, 4 insertions(+), 5 deletions(-)
>>
>> diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
>> index 7456a26aef51..92db00d81733 100644
>> --- a/drivers/scsi/scsi_lib.c
>> +++ b/drivers/scsi/scsi_lib.c
>> @@ -2070,7 +2070,7 @@ EXPORT_SYMBOL_GPL(scsi_mode_select);
>>  /**
>>   *	scsi_mode_sense - issue a mode sense, falling back from 10 to six bytes if necessary.
>>   *	@sdev:	SCSI device to be queried
>> - *	@dbd:	set if mode sense will allow block descriptors to be returned
>> + *	@dbd:	set to prevent mode sense from returning block descriptors
>>   *	@modepage: mode page being requested
>>   *	@buffer: request buffer (may not be smaller than eight bytes)
>>   *	@len:	length of request buffer.
>> @@ -2112,7 +2112,7 @@ scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage,
>>  			len = 8;
>>  
>>  		cmd[0] = MODE_SENSE_10;
>> -		cmd[8] = len;
>> +		put_unaligned_be16(len, &cmd[7]);
>>  		header_length = 8;
>>  	} else {
>>  		if (len < 4)
>> @@ -2166,12 +2166,11 @@ scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage,
>>  		data->longlba = 0;
>>  		data->block_descriptor_length = 0;
>>  	} else if (use_10_for_ms) {
>> -		data->length = buffer[0]*256 + buffer[1] + 2;
>> +		data->length = get_unaligned_be16(&buffer[0]) + 2;
>>  		data->medium_type = buffer[2];
>>  		data->device_specific = buffer[3];
>>  		data->longlba = buffer[4] & 0x01;
>> -		data->block_descriptor_length = buffer[6]*256
>> -			+ buffer[7];
>> +		data->block_descriptor_length = get_unaligned_be16(&buffer[6]);
>>  	} else {
>>  		data->length = buffer[0] + 1;
>>  		data->medium_type = buffer[1];
> 
> (Nit:
> When the subject contains "fix", I think that people automatically look
> for a Fixes-tag. However, AFAIK, there isn't a caller that sends in a
> length > 1 byte. So a slightly better subject might have been:
> "scsi: allow scsi_mode_sense() to read more than 255 bytes")

Indeed, that is better.

Martin,

Can you fix that up ? Or should I resend ?

There is also the fact that the argument len is not being checked against 255.
So if the device does not have use_10_for_ms set, weird things can happen.
I did not add the check because this code has been like this since a long time
and no problem is being reported...

> 
> Reviewed-by: Niklas Cassel <niklas.cassel@wdc.com>
> 


-- 
Damien Le Moal
Western Digital Research

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] scsi: fix scsi_mode_sense()
  2021-08-19  7:37 [PATCH] scsi: fix scsi_mode_sense() Damien Le Moal
  2021-08-19  9:30 ` Niklas Cassel
@ 2021-08-19 17:04 ` Bart Van Assche
  2021-08-20  2:25   ` Damien Le Moal
  1 sibling, 1 reply; 6+ messages in thread
From: Bart Van Assche @ 2021-08-19 17:04 UTC (permalink / raw)
  To: Damien Le Moal, linux-scsi, Martin K . Petersen

On 8/19/21 12:37 AM, Damien Le Moal wrote:
> The allocation length field of the MODE SENSE 10 command is 16-bits,
> occupying bytes 7 and 8 of the CDB. With this command, access to mode
> pages larger than 255 bytes is thus possible. Make sure that
> scsi_mode_sense() code reflects this by initializing the allocation
> length field using put_unaligned_be16() instead of directly setting
> only byte 8 of the CDB with the buffer length.
> 
> While at it, also fix the folowing:
> * use get_unaligned_be16() to retrieve the mode data length and block
>    descriptor length fields of the mode sense reply header instead of
>    using an open coded calculation.
> * Fix the kdoc dbd argument explanation: the DBD bit stands for
>    Disable Block Descriptor, which is the opposite of what the dbd
>    argument description was.
> 
> Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
> ---
>   drivers/scsi/scsi_lib.c | 9 ++++-----
>   1 file changed, 4 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
> index 7456a26aef51..92db00d81733 100644
> --- a/drivers/scsi/scsi_lib.c
> +++ b/drivers/scsi/scsi_lib.c
> @@ -2070,7 +2070,7 @@ EXPORT_SYMBOL_GPL(scsi_mode_select);
>   /**
>    *	scsi_mode_sense - issue a mode sense, falling back from 10 to six bytes if necessary.
>    *	@sdev:	SCSI device to be queried
> - *	@dbd:	set if mode sense will allow block descriptors to be returned
> + *	@dbd:	set to prevent mode sense from returning block descriptors
>    *	@modepage: mode page being requested
>    *	@buffer: request buffer (may not be smaller than eight bytes)
>    *	@len:	length of request buffer.
> @@ -2112,7 +2112,7 @@ scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage,
>   			len = 8;
>   
>   		cmd[0] = MODE_SENSE_10;
> -		cmd[8] = len;
> +		put_unaligned_be16(len, &cmd[7]);
>   		header_length = 8;
>   	} else {
>   		if (len < 4)
> @@ -2166,12 +2166,11 @@ scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage,
>   		data->longlba = 0;
>   		data->block_descriptor_length = 0;
>   	} else if (use_10_for_ms) {
> -		data->length = buffer[0]*256 + buffer[1] + 2;
> +		data->length = get_unaligned_be16(&buffer[0]) + 2;
>   		data->medium_type = buffer[2];
>   		data->device_specific = buffer[3];
>   		data->longlba = buffer[4] & 0x01;
> -		data->block_descriptor_length = buffer[6]*256
> -			+ buffer[7];
> +		data->block_descriptor_length = get_unaligned_be16(&buffer[6]);
>   	} else {
>   		data->length = buffer[0] + 1;
>   		data->medium_type = buffer[1];

If the type of the scsi_mode_sense() 'len' argument is changed from 
'int' into 'uint16_t', feel free to add:

Reviewed-by: Bart Van Assche <bvanassche@acm.org>



^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] scsi: fix scsi_mode_sense()
  2021-08-19 17:04 ` Bart Van Assche
@ 2021-08-20  2:25   ` Damien Le Moal
  2021-08-20  3:57     ` Bart Van Assche
  0 siblings, 1 reply; 6+ messages in thread
From: Damien Le Moal @ 2021-08-20  2:25 UTC (permalink / raw)
  To: Bart Van Assche, linux-scsi, Martin K . Petersen

On 2021/08/20 2:04, Bart Van Assche wrote:
> On 8/19/21 12:37 AM, Damien Le Moal wrote:
>> The allocation length field of the MODE SENSE 10 command is 16-bits,
>> occupying bytes 7 and 8 of the CDB. With this command, access to mode
>> pages larger than 255 bytes is thus possible. Make sure that
>> scsi_mode_sense() code reflects this by initializing the allocation
>> length field using put_unaligned_be16() instead of directly setting
>> only byte 8 of the CDB with the buffer length.
>>
>> While at it, also fix the folowing:
>> * use get_unaligned_be16() to retrieve the mode data length and block
>>    descriptor length fields of the mode sense reply header instead of
>>    using an open coded calculation.
>> * Fix the kdoc dbd argument explanation: the DBD bit stands for
>>    Disable Block Descriptor, which is the opposite of what the dbd
>>    argument description was.
>>
>> Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
>> ---
>>   drivers/scsi/scsi_lib.c | 9 ++++-----
>>   1 file changed, 4 insertions(+), 5 deletions(-)
>>
>> diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
>> index 7456a26aef51..92db00d81733 100644
>> --- a/drivers/scsi/scsi_lib.c
>> +++ b/drivers/scsi/scsi_lib.c
>> @@ -2070,7 +2070,7 @@ EXPORT_SYMBOL_GPL(scsi_mode_select);
>>   /**
>>    *	scsi_mode_sense - issue a mode sense, falling back from 10 to six bytes if necessary.
>>    *	@sdev:	SCSI device to be queried
>> - *	@dbd:	set if mode sense will allow block descriptors to be returned
>> + *	@dbd:	set to prevent mode sense from returning block descriptors
>>    *	@modepage: mode page being requested
>>    *	@buffer: request buffer (may not be smaller than eight bytes)
>>    *	@len:	length of request buffer.
>> @@ -2112,7 +2112,7 @@ scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage,
>>   			len = 8;
>>   
>>   		cmd[0] = MODE_SENSE_10;
>> -		cmd[8] = len;
>> +		put_unaligned_be16(len, &cmd[7]);
>>   		header_length = 8;
>>   	} else {
>>   		if (len < 4)
>> @@ -2166,12 +2166,11 @@ scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage,
>>   		data->longlba = 0;
>>   		data->block_descriptor_length = 0;
>>   	} else if (use_10_for_ms) {
>> -		data->length = buffer[0]*256 + buffer[1] + 2;
>> +		data->length = get_unaligned_be16(&buffer[0]) + 2;
>>   		data->medium_type = buffer[2];
>>   		data->device_specific = buffer[3];
>>   		data->longlba = buffer[4] & 0x01;
>> -		data->block_descriptor_length = buffer[6]*256
>> -			+ buffer[7];
>> +		data->block_descriptor_length = get_unaligned_be16(&buffer[6]);
>>   	} else {
>>   		data->length = buffer[0] + 1;
>>   		data->medium_type = buffer[1];
> 
> If the type of the scsi_mode_sense() 'len' argument is changed from 
> 'int' into 'uint16_t', feel free to add:

Bart,

I would rather keep the argument as an int and add a check for
"len > UINT16_MAX" to return an error (-EINVAL) rather than having the interface
automatically cast/truncate len values that are too large. Doing so, buggy
drivers will get back an error and can be fixed. With the change to uint16_t,
errors may end up being hidden.

scsi_mode_select() has such check. And looking at that function, it also has
problems with the buffer length max possible values as the added length of the
header is not accounted for. I fixed that too in a different patch (not sent
yet). Thoughts ?

> 
> Reviewed-by: Bart Van Assche <bvanassche@acm.org>
> 
> 
> 


-- 
Damien Le Moal
Western Digital Research

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] scsi: fix scsi_mode_sense()
  2021-08-20  2:25   ` Damien Le Moal
@ 2021-08-20  3:57     ` Bart Van Assche
  0 siblings, 0 replies; 6+ messages in thread
From: Bart Van Assche @ 2021-08-20  3:57 UTC (permalink / raw)
  To: Damien Le Moal, linux-scsi, Martin K . Petersen

On 8/19/21 7:25 PM, Damien Le Moal wrote:
> I would rather keep the argument as an int and add a check for
> "len > UINT16_MAX" to return an error (-EINVAL) rather than having the interface
> automatically cast/truncate len values that are too large. Doing so, buggy
> drivers will get back an error and can be fixed. With the change to uint16_t,
> errors may end up being hidden.
> 
> scsi_mode_select() has such check. And looking at that function, it also has
> problems with the buffer length max possible values as the added length of the
> header is not accounted for. I fixed that too in a different patch (not sent
> yet). Thoughts ?

Changing the argument type into uint16_t would make it possible for the
compiler to warn about integer truncation. The compiler probably would
only warn about truncation if the scsi_mode_sense() len argument is a
constant.

Anyway, I'm also fine with a runtime check for the len argument and
keeping its type.

Bart.

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2021-08-20  3:58 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-08-19  7:37 [PATCH] scsi: fix scsi_mode_sense() Damien Le Moal
2021-08-19  9:30 ` Niklas Cassel
2021-08-19  9:35   ` Damien Le Moal
2021-08-19 17:04 ` Bart Van Assche
2021-08-20  2:25   ` Damien Le Moal
2021-08-20  3:57     ` Bart Van Assche

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.