[06/19] target: Fix data buffer size for VERIFY and WRITE AND VERIFY commands
diff mbox

Message ID 20170504225102.8931-7-bart.vanassche@sandisk.com
State New, archived
Headers show

Commit Message

Bart Van Assche May 4, 2017, 10:50 p.m. UTC
For VERIFY and WRITE AND VERIFY commands the size of the SCSI
Data-Out buffer can differ from the size of the data area on
the storage medium that is affected by the command. Make sure
that the Data-Out buffer size is computed correctly. Apparently
this part got dropped from my previous VERIFY / WRITE AND VERIFY
patch before I posted it due to rebasing.

Fixes: commit 0e2eb7d12eaa ("target: Fix VERIFY and WRITE VERIFY command parsing")
Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com>
Cc: Hannes Reinecke <hare@suse.com>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Andy Grover <agrover@redhat.com>
Cc: David Disseldorp <ddiss@suse.de>
Cc: <stable@vger.kernel.org>
---
 drivers/target/target_core_sbc.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

Comments

Nicholas A. Bellinger May 7, 2017, 10:49 p.m. UTC | #1
On Thu, 2017-05-04 at 15:50 -0700, Bart Van Assche wrote:
> For VERIFY and WRITE AND VERIFY commands the size of the SCSI
> Data-Out buffer can differ from the size of the data area on
> the storage medium that is affected by the command. Make sure
> that the Data-Out buffer size is computed correctly. Apparently
> this part got dropped from my previous VERIFY / WRITE AND VERIFY
> patch before I posted it due to rebasing.
> 
> Fixes: commit 0e2eb7d12eaa ("target: Fix VERIFY and WRITE VERIFY command parsing")
> Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com>
> Cc: Hannes Reinecke <hare@suse.com>
> Cc: Christoph Hellwig <hch@lst.de>
> Cc: Andy Grover <agrover@redhat.com>
> Cc: David Disseldorp <ddiss@suse.de>
> Cc: <stable@vger.kernel.org>
> ---
>  drivers/target/target_core_sbc.c | 5 +++--
>  1 file changed, 3 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c
> index a0ad618f1b1a..51489d96cb31 100644
> --- a/drivers/target/target_core_sbc.c
> +++ b/drivers/target/target_core_sbc.c
> @@ -888,9 +888,10 @@ static sense_reason_t sbc_parse_verify(struct se_cmd *cmd, int *sectors,
>  sense_reason_t
>  sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops)
>  {
> +	enum { INVALID_SIZE = 1 };
>  	struct se_device *dev = cmd->se_dev;
>  	unsigned char *cdb = cmd->t_task_cdb;
> -	unsigned int size;
> +	unsigned int size = INVALID_SIZE;
>  	u32 sectors = 0;
>  	sense_reason_t ret;
>  
> @@ -1212,7 +1213,7 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops)
>  			return TCM_ADDRESS_OUT_OF_RANGE;
>  		}
>  
> -		if (!(cmd->se_cmd_flags & SCF_COMPARE_AND_WRITE))
> +		if (size == INVALID_SIZE)
>  			size = sbc_get_size(cmd, sectors);
>  	}
>  

This patch has no effect.

All it does for VERIFY + WRITE_AND_VERIFY is prevent sbc_get_size() from
being called twice with the same parameters, because your previous patch
in for-next was incorrectly only doing it for only bytchk = 1.

Anyways, sbc_parse_verify() should not being doing this directly, and
not for only bytchk = 1.

Anyways, I've fixed both cases and will post the proper fix inline
against patch #19.


--
To unsubscribe from this list: send the line "unsubscribe target-devel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Bart Van Assche May 8, 2017, 6:07 p.m. UTC | #2
On Sun, 2017-05-07 at 15:49 -0700, Nicholas A. Bellinger wrote:
> On Thu, 2017-05-04 at 15:50 -0700, Bart Van Assche wrote:
> > For VERIFY and WRITE AND VERIFY commands the size of the SCSI
> > Data-Out buffer can differ from the size of the data area on
> > the storage medium that is affected by the command. Make sure
> > that the Data-Out buffer size is computed correctly. Apparently
> > this part got dropped from my previous VERIFY / WRITE AND VERIFY
> > patch before I posted it due to rebasing.
> > 
> > Fixes: commit 0e2eb7d12eaa ("target: Fix VERIFY and WRITE VERIFY command parsing")
> > Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com>
> > Cc: Hannes Reinecke <hare@suse.com>
> > Cc: Christoph Hellwig <hch@lst.de>
> > Cc: Andy Grover <agrover@redhat.com>
> > Cc: David Disseldorp <ddiss@suse.de>
> > Cc: <stable@vger.kernel.org>
> > ---
> >  drivers/target/target_core_sbc.c | 5 +++--
> >  1 file changed, 3 insertions(+), 2 deletions(-)
> > 
> > diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c
> > index a0ad618f1b1a..51489d96cb31 100644
> > --- a/drivers/target/target_core_sbc.c
> > +++ b/drivers/target/target_core_sbc.c
> > @@ -888,9 +888,10 @@ static sense_reason_t sbc_parse_verify(struct se_cmd *cmd, int *sectors,
> >  sense_reason_t
> >  sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops)
> >  {
> > +	enum { INVALID_SIZE = 1 };
> >  	struct se_device *dev = cmd->se_dev;
> >  	unsigned char *cdb = cmd->t_task_cdb;
> > -	unsigned int size;
> > +	unsigned int size = INVALID_SIZE;
> >  	u32 sectors = 0;
> >  	sense_reason_t ret;
> >  
> > @@ -1212,7 +1213,7 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops)
> >  			return TCM_ADDRESS_OUT_OF_RANGE;
> >  		}
> >  
> > -		if (!(cmd->se_cmd_flags & SCF_COMPARE_AND_WRITE))
> > +		if (size == INVALID_SIZE)
> >  			size = sbc_get_size(cmd, sectors);
> >  	}
> >  
> 
> This patch has no effect.

Hello Nic,

That's a misinterpretation of your side. What this patch does is to ensure
that 'size' remains zero if a VERIFY or WRITE AND VERIFY command is submitted
with BYTCHK == 0. SBC mentions clearly that BYTCHK == 0 means that there is
no Data-Out buffer, or in other words, that the size of the Data-Out buffer
is zero.

From the sg_verify man page:

       When --ndo=NDO is not given then the verify starts at the logical block
       address given by the --lba=LBA option and continues for --count=COUNT
       blocks.

In other words, sg_verify is able to submit a VERIFY command without Data-Out
buffer (NDO is the size of the Data-Out buffer in bytes).

> Anyways, I've fixed both cases and will post the proper fix inline
> against patch #19.

Do you perhaps mean patch "target: Fix sbc_parse_verify bytchk = 0 handling"?
(https://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending.git/commit/?h=for-next&id=d7d40280f868463d01a82186fd61cdc0e590381f)

If you want to know my opinion about that patch: it doesn't fix anything but
breaks the sbc_parse_verify() function and definitely doesn't make the
behavior of VERIFY nor WRITE AND VERIFY more compliant with the SCSI specs.

Bart.--
To unsubscribe from this list: send the line "unsubscribe target-devel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Nicholas A. Bellinger May 10, 2017, 4:28 a.m. UTC | #3
On Mon, 2017-05-08 at 18:07 +0000, Bart Van Assche wrote:
> On Sun, 2017-05-07 at 15:49 -0700, Nicholas A. Bellinger wrote:
> > On Thu, 2017-05-04 at 15:50 -0700, Bart Van Assche wrote:
> > > For VERIFY and WRITE AND VERIFY commands the size of the SCSI
> > > Data-Out buffer can differ from the size of the data area on
> > > the storage medium that is affected by the command. Make sure
> > > that the Data-Out buffer size is computed correctly. Apparently
> > > this part got dropped from my previous VERIFY / WRITE AND VERIFY
> > > patch before I posted it due to rebasing.
> > > 
> > > Fixes: commit 0e2eb7d12eaa ("target: Fix VERIFY and WRITE VERIFY command parsing")
> > > Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com>
> > > Cc: Hannes Reinecke <hare@suse.com>
> > > Cc: Christoph Hellwig <hch@lst.de>
> > > Cc: Andy Grover <agrover@redhat.com>
> > > Cc: David Disseldorp <ddiss@suse.de>
> > > Cc: <stable@vger.kernel.org>
> > > ---
> > >  drivers/target/target_core_sbc.c | 5 +++--
> > >  1 file changed, 3 insertions(+), 2 deletions(-)
> > > 
> > > diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c
> > > index a0ad618f1b1a..51489d96cb31 100644
> > > --- a/drivers/target/target_core_sbc.c
> > > +++ b/drivers/target/target_core_sbc.c
> > > @@ -888,9 +888,10 @@ static sense_reason_t sbc_parse_verify(struct se_cmd *cmd, int *sectors,
> > >  sense_reason_t
> > >  sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops)
> > >  {
> > > +	enum { INVALID_SIZE = 1 };
> > >  	struct se_device *dev = cmd->se_dev;
> > >  	unsigned char *cdb = cmd->t_task_cdb;
> > > -	unsigned int size;
> > > +	unsigned int size = INVALID_SIZE;
> > >  	u32 sectors = 0;
> > >  	sense_reason_t ret;
> > >  
> > > @@ -1212,7 +1213,7 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops)
> > >  			return TCM_ADDRESS_OUT_OF_RANGE;
> > >  		}
> > >  
> > > -		if (!(cmd->se_cmd_flags & SCF_COMPARE_AND_WRITE))
> > > +		if (size == INVALID_SIZE)
> > >  			size = sbc_get_size(cmd, sectors);
> > >  	}
> > >  
> > 
> > This patch has no effect.
> 
> Hello Nic,
> 
> That's a misinterpretation of your side. What this patch does is to ensure
> that 'size' remains zero if a VERIFY or WRITE AND VERIFY command is submitted
> with BYTCHK == 0. SBC mentions clearly that BYTCHK == 0 means that there is
> no Data-Out buffer, or in other words, that the size of the Data-Out buffer
> is zero.
> 
> From the sg_verify man page:
> 
>        When --ndo=NDO is not given then the verify starts at the logical block
>        address given by the --lba=LBA option and continues for --count=COUNT
>        blocks.
> 
> In other words, sg_verify is able to submit a VERIFY command without Data-Out
> buffer (NDO is the size of the Data-Out buffer in bytes).
> 

That's fine the spec says no data is associated with bytchk = 0.

The point is the 'size' value in sbc_parse_cdb() is what's extracted
from the received CDB, and compared against extended data transfer
length (cmd->data_length) in target_cmd_size_check() to determine
overflow or underflow.

Attempting to make 'size' in sbc_parse_cdb() enforce what the spec says,
instead of what it actually is in the received CDB is completely wrong.
No other CDB does this, and *VERIFY* is no exception.

If you're worried about non zero transfer length with bytchk = 0 getting
processed, go ahead and return TCM_INVALID_CDB_FIELD from
sbc_parse_verify() when this happens, like every other sanity check
does.

Of course, that's exactly the test case libiscsi does during
test_writeverify16_residuals, send bythck = 0 with overflow and
underflow with a non zero transfer length.

> > Anyways, I've fixed both cases and will post the proper fix inline
> > against patch #19.
> 
> Do you perhaps mean patch "target: Fix sbc_parse_verify bytchk = 0 handling"?
> (https://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending.git/commit/?h=for-next&id=d7d40280f868463d01a82186fd61cdc0e590381f)
> 
> If you want to know my opinion about that patch: it doesn't fix anything but
> breaks the sbc_parse_verify() function and definitely doesn't make the
> behavior of VERIFY nor WRITE AND VERIFY more compliant with the SCSI specs.

You are incorrect.

It addresses the regression your code introduced that broke existing
behavior for WRITE_VERIFY_*, when sbc_parse_verify() dropped
SCF_SCSI_DATA_CDB for bytchk = 0 that allowed overflow to trigger an
NULL pointer dereference.

Perhaps you should verify existing code before your sbc_parse_verify()
changes to see what I'm talking about.

--
To unsubscribe from this list: send the line "unsubscribe target-devel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Bart Van Assche May 10, 2017, 3:16 p.m. UTC | #4
On Tue, 2017-05-09 at 21:28 -0700, Nicholas A. Bellinger wrote:
> Attempting to make 'size' in sbc_parse_cdb() enforce what the spec says,
> instead of what it actually is in the received CDB is completely wrong.

Please look again at e.g. the sg_verify source code. If it sets BYTCHK to
zero it doesn't submit a Data-Out buffer. The only initiator that submits
a Data-Out buffer and sets BYTCHK to zero is libiscsi when testing overflow
behavior.

Bart.--
To unsubscribe from this list: send the line "unsubscribe target-devel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Patch
diff mbox

diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c
index a0ad618f1b1a..51489d96cb31 100644
--- a/drivers/target/target_core_sbc.c
+++ b/drivers/target/target_core_sbc.c
@@ -888,9 +888,10 @@  static sense_reason_t sbc_parse_verify(struct se_cmd *cmd, int *sectors,
 sense_reason_t
 sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops)
 {
+	enum { INVALID_SIZE = 1 };
 	struct se_device *dev = cmd->se_dev;
 	unsigned char *cdb = cmd->t_task_cdb;
-	unsigned int size;
+	unsigned int size = INVALID_SIZE;
 	u32 sectors = 0;
 	sense_reason_t ret;
 
@@ -1212,7 +1213,7 @@  sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops)
 			return TCM_ADDRESS_OUT_OF_RANGE;
 		}
 
-		if (!(cmd->se_cmd_flags & SCF_COMPARE_AND_WRITE))
+		if (size == INVALID_SIZE)
 			size = sbc_get_size(cmd, sectors);
 	}