cifs: fix NULL deref in SMB2_read

Message ID 20171120223633.16117-1-lsahlber@redhat.com
State New
Headers show
Series
  • cifs: fix NULL deref in SMB2_read
Related show

Commit Message

Leif Sahlberg Nov. 20, 2017, 10:36 p.m.
Signed-off-by: Ronnie Sahlberg <lsahlber@redhat.com>
---
 fs/cifs/smb2pdu.c | 30 +++++++++++++++---------------
 1 file changed, 15 insertions(+), 15 deletions(-)

Comments

Pavel Shilovsky Nov. 20, 2017, 10:52 p.m. | #1
2017-11-20 14:36 GMT-08:00 Ronnie Sahlberg <lsahlber@redhat.com>:
> Signed-off-by: Ronnie Sahlberg <lsahlber@redhat.com>
> ---
>  fs/cifs/smb2pdu.c | 30 +++++++++++++++---------------
>  1 file changed, 15 insertions(+), 15 deletions(-)
>
> diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
> index f92b39bbb929..a555d2b39b30 100644
> --- a/fs/cifs/smb2pdu.c
> +++ b/fs/cifs/smb2pdu.c
> @@ -2649,27 +2649,27 @@ SMB2_read(const unsigned int xid, struct cifs_io_parms *io_parms,
>         cifs_small_buf_release(req);
>
>         rsp = (struct smb2_read_rsp *)rsp_iov.iov_base;
> -       shdr = get_sync_hdr(rsp);
>
> -       if (shdr->Status == STATUS_END_OF_FILE) {
> +       if (rc) {
> +               if (rc != -ENODATA) {
> +                       cifs_stats_fail_inc(io_parms->tcon, SMB2_READ_HE);
> +                       cifs_dbg(VFS, "Send error in read = %d\n", rc);
> +               }
>                 free_rsp_buf(resp_buftype, rsp_iov.iov_base);
> -               return 0;
> +               return rc == -ENODATA ? 0 : rc;
>         }
>
> -       if (rc) {
> -               cifs_stats_fail_inc(io_parms->tcon, SMB2_READ_HE);
> -               cifs_dbg(VFS, "Send error in read = %d\n", rc);
> -       } else {
> -               *nbytes = le32_to_cpu(rsp->DataLength);
> -               if ((*nbytes > CIFS_MAX_MSGSIZE) ||
> -                   (*nbytes > io_parms->length)) {
> -                       cifs_dbg(FYI, "bad length %d for count %d\n",
> -                                *nbytes, io_parms->length);
> -                       rc = -EIO;
> -                       *nbytes = 0;
> -               }
> +       *nbytes = le32_to_cpu(rsp->DataLength);
> +       if ((*nbytes > CIFS_MAX_MSGSIZE) ||
> +           (*nbytes > io_parms->length)) {
> +               cifs_dbg(FYI, "bad length %d for count %d\n",
> +                        *nbytes, io_parms->length);
> +               rc = -EIO;
> +               *nbytes = 0;
>         }
>
> +       shdr = get_sync_hdr(rsp);
> +
>         if (*buf) {
>                 memcpy(*buf, (char *)shdr + rsp->DataOffset, *nbytes);
>                 free_rsp_buf(resp_buftype, rsp_iov.iov_base);
> --
> 2.13.3
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-cifs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reviewed-by: Pavel Shilovsky <pshilov@microsoft.com>

Stable candidate?

--
Best regards,
Pavel Shilovsky
--
To unsubscribe from this list: send the line "unsubscribe linux-cifs" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Steve French Nov. 20, 2017, 11:19 p.m. | #2
Merged into cifs-2.6.git for-next

added cc:stable

On Mon, Nov 20, 2017 at 4:52 PM, Pavel Shilovsky <piastryyy@gmail.com> wrote:
> 2017-11-20 14:36 GMT-08:00 Ronnie Sahlberg <lsahlber@redhat.com>:
>> Signed-off-by: Ronnie Sahlberg <lsahlber@redhat.com>
>> ---
>>  fs/cifs/smb2pdu.c | 30 +++++++++++++++---------------
>>  1 file changed, 15 insertions(+), 15 deletions(-)
>>
>> diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
>> index f92b39bbb929..a555d2b39b30 100644
>> --- a/fs/cifs/smb2pdu.c
>> +++ b/fs/cifs/smb2pdu.c
>> @@ -2649,27 +2649,27 @@ SMB2_read(const unsigned int xid, struct cifs_io_parms *io_parms,
>>         cifs_small_buf_release(req);
>>
>>         rsp = (struct smb2_read_rsp *)rsp_iov.iov_base;
>> -       shdr = get_sync_hdr(rsp);
>>
>> -       if (shdr->Status == STATUS_END_OF_FILE) {
>> +       if (rc) {
>> +               if (rc != -ENODATA) {
>> +                       cifs_stats_fail_inc(io_parms->tcon, SMB2_READ_HE);
>> +                       cifs_dbg(VFS, "Send error in read = %d\n", rc);
>> +               }
>>                 free_rsp_buf(resp_buftype, rsp_iov.iov_base);
>> -               return 0;
>> +               return rc == -ENODATA ? 0 : rc;
>>         }
>>
>> -       if (rc) {
>> -               cifs_stats_fail_inc(io_parms->tcon, SMB2_READ_HE);
>> -               cifs_dbg(VFS, "Send error in read = %d\n", rc);
>> -       } else {
>> -               *nbytes = le32_to_cpu(rsp->DataLength);
>> -               if ((*nbytes > CIFS_MAX_MSGSIZE) ||
>> -                   (*nbytes > io_parms->length)) {
>> -                       cifs_dbg(FYI, "bad length %d for count %d\n",
>> -                                *nbytes, io_parms->length);
>> -                       rc = -EIO;
>> -                       *nbytes = 0;
>> -               }
>> +       *nbytes = le32_to_cpu(rsp->DataLength);
>> +       if ((*nbytes > CIFS_MAX_MSGSIZE) ||
>> +           (*nbytes > io_parms->length)) {
>> +               cifs_dbg(FYI, "bad length %d for count %d\n",
>> +                        *nbytes, io_parms->length);
>> +               rc = -EIO;
>> +               *nbytes = 0;
>>         }
>>
>> +       shdr = get_sync_hdr(rsp);
>> +
>>         if (*buf) {
>>                 memcpy(*buf, (char *)shdr + rsp->DataOffset, *nbytes);
>>                 free_rsp_buf(resp_buftype, rsp_iov.iov_base);
>> --
>> 2.13.3
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-cifs" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>
> Reviewed-by: Pavel Shilovsky <pshilov@microsoft.com>
>
> Stable candidate?
>
> --
> Best regards,
> Pavel Shilovsky

Patch

diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index f92b39bbb929..a555d2b39b30 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -2649,27 +2649,27 @@  SMB2_read(const unsigned int xid, struct cifs_io_parms *io_parms,
 	cifs_small_buf_release(req);
 
 	rsp = (struct smb2_read_rsp *)rsp_iov.iov_base;
-	shdr = get_sync_hdr(rsp);
 
-	if (shdr->Status == STATUS_END_OF_FILE) {
+	if (rc) {
+		if (rc != -ENODATA) {
+			cifs_stats_fail_inc(io_parms->tcon, SMB2_READ_HE);
+			cifs_dbg(VFS, "Send error in read = %d\n", rc);
+		}
 		free_rsp_buf(resp_buftype, rsp_iov.iov_base);
-		return 0;
+		return rc == -ENODATA ? 0 : rc;
 	}
 
-	if (rc) {
-		cifs_stats_fail_inc(io_parms->tcon, SMB2_READ_HE);
-		cifs_dbg(VFS, "Send error in read = %d\n", rc);
-	} else {
-		*nbytes = le32_to_cpu(rsp->DataLength);
-		if ((*nbytes > CIFS_MAX_MSGSIZE) ||
-		    (*nbytes > io_parms->length)) {
-			cifs_dbg(FYI, "bad length %d for count %d\n",
-				 *nbytes, io_parms->length);
-			rc = -EIO;
-			*nbytes = 0;
-		}
+	*nbytes = le32_to_cpu(rsp->DataLength);
+	if ((*nbytes > CIFS_MAX_MSGSIZE) ||
+	    (*nbytes > io_parms->length)) {
+		cifs_dbg(FYI, "bad length %d for count %d\n",
+			 *nbytes, io_parms->length);
+		rc = -EIO;
+		*nbytes = 0;
 	}
 
+	shdr = get_sync_hdr(rsp);
+
 	if (*buf) {
 		memcpy(*buf, (char *)shdr + rsp->DataOffset, *nbytes);
 		free_rsp_buf(resp_buftype, rsp_iov.iov_base);