cifs: Allocate validate negotiation request through kmalloc
Subsystems (3)
PATCH v4 1/1 cifs: Allocate validate negotiation request through kmalloc
From: Long Li <[email protected]>
The data buffer allocated on the stack can't be DMA'ed, ib_dma_map_page will return an invalid DMA address for a buffer on stack. Even worse, this incorrect address can't be detected by ib_dma_mapping_error. Sending data from this address to hardware will not fail, but the remote peer will get junk data.
Fix this by allocating the request on the heap in smb3_validate_negotiate.
Changes in v2:
Removed duplicated code on freeing buffers on function exit. (Thanks to Parav Pandit <[email protected]>) Fixed typo in the patch title.
Changes in v3:
Added "Fixes" to the patch.
Changed several sizeof() to use *pointer in place of struct.
Changes in v4:
Added detailed comments on the failure through RDMA. Allocate request buffer using GPF_NOFS. Fixed possible memory leak.
--- fs/cifs/smb2pdu.c | 61 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 33 insertions(+), 28 deletions(-)
fs/cifs/smb2pdu.c +33 -28
@@ -729,8 +729,8 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)int smb3_validate_negotiate (const unsigned int xid,struct cifs_tcon *tcon) { -int rc =0 ; -struct validate_negotiate_info_req vneg_inbuf; +int ret, rc = -EIO ; +struct validate_negotiate_info_req *pneg_inbuf;struct validate_negotiate_info_rsp *pneg_rsp =NULL ;u32 rsplen;u32 inbuflen;/* max of 4 dialects */
@@ -741,7 +741,6 @@ int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon)if (tcon->ses->server->rdma)return 0 ;#endif -/* In SMB3.11 preauth integrity supersedes validate negotiate */ if (tcon->ses->server->dialect ==SMB311_PROT_ID )return 0 ;
@@ -764,63 +763,67 @@ int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon)if (tcon->ses->session_flags &SMB2_SESSION_FLAG_IS_NULL )cifs_dbg (VFS ,"Unexpected null user (anonymous) auth flag sent by server\n" ); - vneg_inbuf.Capabilities = + pneg_inbuf =kmalloc (sizeof (*pneg_inbuf),GFP_NOFS ); +if (!pneg_inbuf) +return -ENOMEM ; + + pneg_inbuf->Capabilities =cpu_to_le32 (tcon->ses->server->vals->req_capabilities); -memcpy (vneg_inbuf.Guid, tcon->ses->server->client_guid, +memcpy (pneg_inbuf->Guid, tcon->ses->server->client_guid,SMB2_CLIENT_GUID_SIZE );if (tcon->ses->sign) - vneg_inbuf.SecurityMode = + pneg_inbuf->SecurityMode =cpu_to_le16 (SMB2_NEGOTIATE_SIGNING_REQUIRED );else if (global_secflags &CIFSSEC_MAY_SIGN ) - vneg_inbuf.SecurityMode = + pneg_inbuf->SecurityMode =cpu_to_le16 (SMB2_NEGOTIATE_SIGNING_ENABLED );else - vneg_inbuf.SecurityMode =0 ; + pneg_inbuf->SecurityMode =0 ;if (strcmp (tcon->ses->server->vals->version_string,SMB3ANY_VERSION_STRING ) ==0 ) { - vneg_inbuf.Dialects[0 ] =cpu_to_le16 (SMB30_PROT_ID ); - vneg_inbuf.Dialects[1 ] =cpu_to_le16 (SMB302_PROT_ID ); - vneg_inbuf.DialectCount =cpu_to_le16 (2 ); + pneg_inbuf->Dialects[0 ] =cpu_to_le16 (SMB30_PROT_ID ); + pneg_inbuf->Dialects[1 ] =cpu_to_le16 (SMB302_PROT_ID ); + pneg_inbuf->DialectCount =cpu_to_le16 (2 );/* structure is big enough for 3 dialects, sending only 2 */ inbuflen =sizeof (struct validate_negotiate_info_req ) -2 ; }else if (strcmp (tcon->ses->server->vals->version_string,SMBDEFAULT_VERSION_STRING ) ==0 ) { - vneg_inbuf.Dialects[0 ] =cpu_to_le16 (SMB21_PROT_ID ); - vneg_inbuf.Dialects[1 ] =cpu_to_le16 (SMB30_PROT_ID ); - vneg_inbuf.Dialects[2 ] =cpu_to_le16 (SMB302_PROT_ID ); - vneg_inbuf.DialectCount =cpu_to_le16 (3 ); + pneg_inbuf->Dialects[0 ] =cpu_to_le16 (SMB21_PROT_ID ); + pneg_inbuf->Dialects[1 ] =cpu_to_le16 (SMB30_PROT_ID ); + pneg_inbuf->Dialects[2 ] =cpu_to_le16 (SMB302_PROT_ID ); + pneg_inbuf->DialectCount =cpu_to_le16 (3 );/* structure is big enough for 3 dialects */ inbuflen =sizeof (struct validate_negotiate_info_req ); }else {/* otherwise specific dialect was requested */ - vneg_inbuf.Dialects[0 ] = + pneg_inbuf->Dialects[0 ] =cpu_to_le16 (tcon->ses->server->vals->protocol_id); - vneg_inbuf.DialectCount =cpu_to_le16 (1 ); + pneg_inbuf->DialectCount =cpu_to_le16 (1 );/* structure is big enough for 3 dialects, sending only 1 */ inbuflen =sizeof (struct validate_negotiate_info_req ) -4 ; } - rc =SMB2_ioctl (xid, tcon,NO_FILE_ID ,NO_FILE_ID , + ret =SMB2_ioctl (xid, tcon,NO_FILE_ID ,NO_FILE_ID ,FSCTL_VALIDATE_NEGOTIATE_INFO , true/* is_fsctl */ , - (char *)&vneg_inbuf,sizeof (struct validate_negotiate_info_req ), + (char *)pneg_inbuf,sizeof (*pneg_inbuf), (char **)&pneg_rsp, &rsplen); -if (rc !=0 ) { -cifs_dbg (VFS ,"validate protocol negotiate failed: %d\n" , rc); -return -EIO ; +if (ret) { +cifs_dbg (VFS ,"validate protocol negotiate failed: %d\n" , ret); + goto out_free_inbuf; } -if (rsplen !=sizeof (struct validate_negotiate_info_rsp )) { +if (rsplen !=sizeof (*pneg_rsp)) {cifs_dbg (VFS ,"invalid protocol negotiate response size: %d\n" , rsplen);/* relax check since Mac returns max bufsize allowed on ioctl */ if ((rsplen > CIFSMaxBufSize) || (rsplen <sizeof (struct validate_negotiate_info_rsp ))) - goto err_rsp_free; + goto out_free_rsp; }/* check validate negotiate info response matches what we got earlier */
@@ -838,14 +841,16 @@ int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon)/* validate negotiate successful */ cifs_dbg (FYI ,"validate negotiate info successful\n" ); -kfree (pneg_rsp); -return 0 ; + rc =0 ; + goto out_free_rsp; vneg_out:cifs_dbg (VFS ,"protocol revalidation - security settings mismatch\n" ); -err_rsp_free: +out_free_rsp:kfree (pneg_rsp); -return -EIO ; +out_free_inbuf: +kfree (pneg_inbuf); +return rc; }enum securityEnum
Signature · 1 line
2.7.4
Tom Talpey
reviewerLooks good, but I have two possibly style-related comments.
Quoted 35 lines · Long Li
From: Long Li <[email protected]>
The data buffer allocated on the stack can't be DMA'ed,
ib_dma_map_pagewill return an invalid DMA address for a buffer on stack. Even worse, this incorrect address can't be detected byib_dma_mapping_error. Sending data from this address to hardware will not fail, but the remote peer will get junk data.Fix this by allocating the request on the heap in
smb3_validate_negotiate.Changes in v2:
Removed duplicated code on freeing buffers on function exit. (Thanks to Parav Pandit <[email protected]>) Fixed typo in the patch title.Changes in v3:
Added "Fixes" to the patch.
Changed severalsizeof()to use *pointer in place of struct.Changes in v4:
Added detailed comments on the failure through RDMA. Allocate request buffer usingGPF_NOFS. Fixed possible memory leak.Fixes ff1c038addc4 ("Check SMB3 dialects against downgrade attacks")Signed-off-by Long Li <[email protected]>--- fs/cifs/smb2pdu.c | 61 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 33 insertions(+), 28 deletions(-)fs/cifs/smb2pdu.c +0
-0
fs/cifs/smb2pdu.c SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses) · line 732
Quoted 6 lines
fs/cifs/smb2pdu.c +1
-2@@ -729,8 +729,8 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)int smb3_validate_negotiate (const unsigned int xid,struct cifs_tcon *tcon) { -int rc =0 ; -struct validate_negotiate_info_req vneg_inbuf; +int ret, rc = -EIO ;
Seems awkward to have "rc" and "ret", and based on the code below I don't see why two variables are needed. Simplify? (see later comment)
Quoted 40 lines
fs/cifs/smb2pdu.c +10
-6+struct validate_negotiate_info_req *pneg_inbuf;struct validate_negotiate_info_rsp *pneg_rsp =NULL ;u32 rsplen;u32 inbuflen;/* max of 4 dialects */ @@ -741,7 +741,6 @@ int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon)if (tcon->ses->server->rdma)return 0 ;#endif -/* In SMB3.11 preauth integrity supersedes validate negotiate */ if (tcon->ses->server->dialect ==SMB311_PROT_ID )return 0 ;@@ -764,63 +763,67 @@ int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon)if (tcon->ses->session_flags &SMB2_SESSION_FLAG_IS_NULL )cifs_dbg (VFS ,"Unexpected null user (anonymous) auth flag sent by server\n" ); - vneg_inbuf.Capabilities = + pneg_inbuf =kmalloc (sizeof (*pneg_inbuf),GFP_NOFS ); +if (!pneg_inbuf) +return -ENOMEM ; + + pneg_inbuf->Capabilities =cpu_to_le32 (tcon->ses->server->vals->req_capabilities); -memcpy (vneg_inbuf.Guid, tcon->ses->server->client_guid, +memcpy (pneg_inbuf->Guid, tcon->ses->server->client_guid,SMB2_CLIENT_GUID_SIZE );if (tcon->ses->sign) - vneg_inbuf.SecurityMode = + pneg_inbuf->SecurityMode =cpu_to_le16 (SMB2_NEGOTIATE_SIGNING_REQUIRED );else if (global_secflags &CIFSSEC_MAY_SIGN ) - vneg_inbuf.SecurityMode = + pneg_inbuf->SecurityMode =cpu_to_le16 (SMB2_NEGOTIATE_SIGNING_ENABLED );else - vneg_inbuf.SecurityMode =0 ; + pneg_inbuf->SecurityMode =0 ;
fs/cifs/smb2pdu.c int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon) · line 791
Quoted 10 lines
fs/cifs/smb2pdu.c +3
-3if (strcmp (tcon->ses->server->vals->version_string,SMB3ANY_VERSION_STRING ) ==0 ) { - vneg_inbuf.Dialects[0 ] =cpu_to_le16 (SMB30_PROT_ID ); - vneg_inbuf.Dialects[1 ] =cpu_to_le16 (SMB302_PROT_ID ); - vneg_inbuf.DialectCount =cpu_to_le16 (2 ); + pneg_inbuf->Dialects[0 ] =cpu_to_le16 (SMB30_PROT_ID ); + pneg_inbuf->Dialects[1 ] =cpu_to_le16 (SMB302_PROT_ID ); + pneg_inbuf->DialectCount =cpu_to_le16 (2 );/* structure is big enough for 3 dialects, sending only 2 */ inbuflen =sizeof (struct validate_negotiate_info_req ) -2 ;
The "- 2" is a little confusing here. This was existing code, but I suggest you change this to a sizeof (u16) construct for consistency. It's reducing by the length of a single Dialects[n] entry.
Quoted 11 lines
fs/cifs/smb2pdu.c +4
-4}else if (strcmp (tcon->ses->server->vals->version_string,SMBDEFAULT_VERSION_STRING ) ==0 ) { - vneg_inbuf.Dialects[0 ] =cpu_to_le16 (SMB21_PROT_ID ); - vneg_inbuf.Dialects[1 ] =cpu_to_le16 (SMB30_PROT_ID ); - vneg_inbuf.Dialects[2 ] =cpu_to_le16 (SMB302_PROT_ID ); - vneg_inbuf.DialectCount =cpu_to_le16 (3 ); + pneg_inbuf->Dialects[0 ] =cpu_to_le16 (SMB21_PROT_ID ); + pneg_inbuf->Dialects[1 ] =cpu_to_le16 (SMB30_PROT_ID ); + pneg_inbuf->Dialects[2 ] =cpu_to_le16 (SMB302_PROT_ID ); + pneg_inbuf->DialectCount =cpu_to_le16 (3 );/* structure is big enough for 3 dialects */
fs/cifs/smb2pdu.c int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon) · line 806
Quoted 10 lines
fs/cifs/smb2pdu.c +2
-2inbuflen =sizeof (struct validate_negotiate_info_req ); }else {/* otherwise specific dialect was requested */ - vneg_inbuf.Dialects[0 ] = + pneg_inbuf->Dialects[0 ] =cpu_to_le16 (tcon->ses->server->vals->protocol_id); - vneg_inbuf.DialectCount =cpu_to_le16 (1 ); + pneg_inbuf->DialectCount =cpu_to_le16 (1 );/* structure is big enough for 3 dialects, sending only 1 */ inbuflen =sizeof (struct validate_negotiate_info_req ) -4 ;
Ditto previous sizeof (u16) comment, with a *2 this case.
Quoted 6 lines
fs/cifs/smb2pdu.c +1
-2} - rc = SMB2_ioctl(xid, tcon, NO_FILE_ID, NO_FILE_ID, + ret = SMB2_ioctl(xid, tcon, NO_FILE_ID, NO_FILE_ID, FSCTL_VALIDATE_NEGOTIATE_INFO, true /* is_fsctl */, - (char *)&vneg_inbuf, sizeof(struct validate_negotiate_info_req),
fs/cifs/smb2pdu.c int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon) · line 817
Quoted 10 lines
fs/cifs/smb2pdu.c +4
-3+ (char *)pneg_inbuf,sizeof (*pneg_inbuf), (char **)&pneg_rsp, &rsplen); -if (rc !=0 ) { -cifs_dbg (VFS ,"validate protocol negotiate failed: %d\n" , rc); -return -EIO ; +if (ret) { +cifs_dbg (VFS ,"validate protocol negotiate failed: %d\n" , ret); + goto out_free_inbuf; }
Why not leave "rc" alone, and set its value to -EIO before the goto if the ioctl fails? That will simplify and make the code much more readable IMO.
fs/cifs/smb2pdu.c int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon) · line 827
Quoted 12 lines
fs/cifs/smb2pdu.c +2
-2-if (rsplen !=sizeof (struct validate_negotiate_info_rsp )) { +if (rsplen !=sizeof (*pneg_rsp)) {cifs_dbg (VFS ,"invalid protocol negotiate response size: %d\n" , rsplen);/* relax check since Mac returns max bufsize allowed on ioctl */ if ((rsplen > CIFSMaxBufSize) || (rsplen <sizeof (struct validate_negotiate_info_rsp ))) - goto err_rsp_free; + goto out_free_rsp; }
Would need an rc = -EIO here too if above comment is accepted.
Tom.
Quoted 24 lines
fs/cifs/smb2pdu.c +6
-4/* check validate negotiate info response matches what we got earlier */ @@ -838,14 +841,16 @@ int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon)/* validate negotiate successful */ cifs_dbg (FYI ,"validate negotiate info successful\n" ); -kfree (pneg_rsp); -return 0 ; + rc =0 ; + goto out_free_rsp; vneg_out:cifs_dbg (VFS ,"protocol revalidation - security settings mismatch\n" ); -err_rsp_free: +out_free_rsp:kfree (pneg_rsp); -return -EIO ; +out_free_inbuf: +kfree (pneg_inbuf); +return rc; }enum securityEnum
2018-04-20 7:55 GMT-07:00 Tom Talpey <[email protected]>:
Quoted 103 lines
Looks good, but I have two possibly style-related comments.
Quoted 38 lines · Long Li
From: Long Li <[email protected]>
The data buffer allocated on the stack can't be DMA'ed,
ib_dma_map_pagewill
return an invalid DMA address for a buffer on stack. Even worse, this incorrect address can't be detected byib_dma_mapping_error. Sending data from this address to hardware will not fail, but the remote peer will get junk data.Fix this by allocating the request on the heap in
smb3_validate_negotiate.Changes in v2:
Removed duplicated code on freeing buffers on function exit. (Thanks to Parav Pandit <[email protected]>) Fixed typo in the patch title.Changes in v3:
Added "Fixes" to the patch.
Changed severalsizeof()to use *pointer in place of struct.Changes in v4:
Added detailed comments on the failure through RDMA. Allocate request buffer usingGPF_NOFS. Fixed possible memory leak.Fixes ff1c038addc4 ("Check SMB3 dialects against downgrade attacks")Signed-off-by Long Li <[email protected]>--- fs/cifs/smb2pdu.c | 61 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 33 insertions(+), 28 deletions(-)fs/cifs/smb2pdu.c +0
-0fs/cifs/smb2pdu.c SMB2_negotiate(const unsigned int xid, struct cifs_ses · line 733
Quoted 7 lines
fs/cifs/smb2pdu.c +1
-2@@ -729,8 +729,8 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)int smb3_validate_negotiate (const unsigned int xid,struct cifs_tcon *tcon) { -int rc =0 ; -struct validate_negotiate_info_req vneg_inbuf; +int ret, rc = -EIO ;Seems awkward to have "rc" and "ret", and based on the code below I don't see why two variables are needed. Simplify? (see later comment)
Quoted 48 lines
fs/cifs/smb2pdu.c +1
-0+struct validate_negotiate_info_req *pneg_inbuf;struct validate_negotiate_info_rsp *pneg_rsp =NULL ;u32 rsplen;u32 inbuflen; /* max of 4 dialects */
fs/cifs/smb2pdu.c +0
-1@@ -741,7 +741,6 @@ int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon)if (tcon->ses->server->rdma)return 0 ;#endif -/* In SMB3.11 preauth integrity supersedes validate negotiate */ if (tcon->ses->server->dialect ==SMB311_PROT_ID )return 0;fs/cifs/smb2pdu.c +12
-7@@ -764,63 +763,67 @@ int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon)if (tcon->ses->session_flags &SMB2_SESSION_FLAG_IS_NULL ) cifs_dbg(VFS, "Unexpected null user (anonymous) auth flag sent by server\n"); - vneg_inbuf.Capabilities = + pneg_inbuf = kmalloc(sizeof(*pneg_inbuf), GFP_NOFS); +if (!pneg_inbuf) +return -ENOMEM ; + + pneg_inbuf->Capabilities =cpu_to_le32 (tcon->ses->server->vals->req_capabilities); -memcpy (vneg_inbuf.Guid, tcon->ses->server->client_guid, +memcpy (pneg_inbuf->Guid, tcon->ses->server->client_guid,SMB2_CLIENT_GUID_SIZE );if (tcon->ses->sign) - vneg_inbuf.SecurityMode = + pneg_inbuf->SecurityMode =cpu_to_le16 (SMB2_NEGOTIATE_SIGNING_REQUIRED );else if (global_secflags &CIFSSEC_MAY_SIGN ) - vneg_inbuf.SecurityMode = + pneg_inbuf->SecurityMode =cpu_to_le16 (SMB2_NEGOTIATE_SIGNING_ENABLED );else - vneg_inbuf.SecurityMode =0 ; + pneg_inbuf->SecurityMode =0 ;if (strcmp (tcon->ses->server->vals->version_string,SMB3ANY_VERSION_STRING ) ==0 ) { - vneg_inbuf.Dialects[0 ] =cpu_to_le16 (SMB30_PROT_ID ); - vneg_inbuf.Dialects[1 ] =cpu_to_le16 (SMB302_PROT_ID ); - vneg_inbuf.DialectCount =cpu_to_le16 (2 ); + pneg_inbuf->Dialects[0 ] =cpu_to_le16 (SMB30_PROT_ID ); + pneg_inbuf->Dialects[1 ] =cpu_to_le16 (SMB302_PROT_ID ); + pneg_inbuf->DialectCount =cpu_to_le16 (2 );
Quoted 8 lines
fs/cifs/smb2pdu.c int smb3_validate_negotiate(const unsigned int xid, · line 792
Quoted 3 lines
fs/cifs/smb2pdu.c +0
-0/* structure is big enough for 3 dialects, sending only 2 */ inbuflen =sizeof (struct validate_negotiate_info_req ) -2 ;The "- 2" is a little confusing here. This was existing code, but I suggest you change this to a sizeof (u16) construct for consistency. It's reducing by the length of a single Dialects[n] entry.
I would suggest to make it "- sizeof(pneg_inbuf->Dialects[0])"...
Quoted 26 lines
Quoted 13 lines
fs/cifs/smb2pdu.c +4
-4}else if (strcmp (tcon->ses->server->vals->version_string,SMBDEFAULT_VERSION_STRING ) ==0 ) { - vneg_inbuf.Dialects[0 ] =cpu_to_le16 (SMB21_PROT_ID ); - vneg_inbuf.Dialects[1 ] =cpu_to_le16 (SMB30_PROT_ID ); - vneg_inbuf.Dialects[2 ] =cpu_to_le16 (SMB302_PROT_ID ); - vneg_inbuf.DialectCount =cpu_to_le16 (3 ); + pneg_inbuf->Dialects[0 ] =cpu_to_le16 (SMB21_PROT_ID ); + pneg_inbuf->Dialects[1 ] =cpu_to_le16 (SMB30_PROT_ID ); + pneg_inbuf->Dialects[2 ] =cpu_to_le16 (SMB302_PROT_ID ); + pneg_inbuf->DialectCount =cpu_to_le16 (3 );/* structure is big enough for 3 dialects */ inbuflen =sizeof (struct validate_negotiate_info_req );fs/cifs/smb2pdu.c int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon) · line 806
Quoted 10 lines
fs/cifs/smb2pdu.c +2
-2}else {/* otherwise specific dialect was requested */ - vneg_inbuf.Dialects[0 ] = + pneg_inbuf->Dialects[0 ] =cpu_to_le16 (tcon->ses->server->vals->protocol_id); - vneg_inbuf.DialectCount =cpu_to_le16 (1 ); + pneg_inbuf->DialectCount =cpu_to_le16 (1 );/* structure is big enough for 3 dialects, sending only 1 */ inbuflen =sizeof (struct validate_negotiate_info_req ) -4 ;
Quoted 1 line
Ditto previous sizeof (u16) comment, with a *2 this case.
... and "- 2 * sizeof(pneg_inbuf->Dialects[0])" respectively.
Quoted 70 lines
Quoted 8 lines
fs/cifs/smb2pdu.c +2
-1} - rc = SMB2_ioctl(xid, tcon, NO_FILE_ID, NO_FILE_ID, + ret = SMB2_ioctl(xid, tcon, NO_FILE_ID, NO_FILE_ID, FSCTL_VALIDATE_NEGOTIATE_INFO, true /* is_fsctl */, - (char *)&vneg_inbuf, sizeof(struct validate_negotiate_info_req), + (char *)pneg_inbuf, sizeof(*pneg_inbuf),fs/cifs/smb2pdu.c int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon) · line 817
Quoted 10 lines
fs/cifs/smb2pdu.c +3
-2(char **)&pneg_rsp, &rsplen); - if (rc != 0) { -cifs_dbg (VFS ,"validate protocol negotiate failed: %d\n" , rc); -return -EIO ; +if (ret) { +cifs_dbg (VFS ,"validate protocol negotiate failed: %d\n" , ret); + goto out_free_inbuf; }Why not leave "rc" alone, and set its value to
-EIObefore the goto if the ioctl fails? That will simplify and make the code much more readable IMO.fs/cifs/smb2pdu.c int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon) · line 827
Quoted 13 lines
fs/cifs/smb2pdu.c +1
-0- if (rsplen != sizeof(struct validate_negotiate_info_rsp)) { +if (rsplen !=sizeof (*pneg_rsp)) { cifs_dbg(VFS, "invalid protocol negotiate response size: %d\n", rsplen);/* relax check since Mac returns max bufsize allowed on ioctl */
if ((rsplen > CIFSMaxBufSize)
|| (rsplen < sizeof(structvalidate_negotiate_info_rsp)))fs/cifs/smb2pdu.c +1
-1- goto err_rsp_free; + goto out_free_rsp; }Would need an rc =
-EIOhere too if above comment is accepted.Tom.
Quoted 13 lines
/* check validate negotiate info response matches what we gotearlier */
fs/cifs/smb2pdu.c +2
-2@@ -838,14 +841,16 @@ int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon) /* validate negotiate successful */ cifs_dbg(FYI, "validate negotiate info successful\n"); -kfree (pneg_rsp); -return 0 ; + rc =0 ; + goto out_free_rsp; vneg_out:cifs_dbg (VFS ,"protocol revalidation - security settings mismatch\n");fs/cifs/smb2pdu.c int smb3_validate_negotiate(const unsigned int xid, · line 856
Quoted 10 lines
fs/cifs/smb2pdu.c +4
-2-err_rsp_free: +out_free_rsp:kfree (pneg_rsp); -return -EIO ; +out_free_inbuf: +kfree (pneg_inbuf); +return rc; }enum securityEnum --
To unsubscribe from this list: send the line "unsubscribe linux-cifs" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Quoted 44 lines
Subject: Re: [Patch v4] cifs: Allocate validate negotiation request through kmalloc
Looks good, but I have two possibly style-related comments.
Quoted 24 lines · Long Li
From: Long Li <[email protected]>
The data buffer allocated on the stack can't be DMA'ed,
ib_dma_map_pagewill return an invalid DMA address for a buffer on stack. Even worse, this incorrect address can't be detected byib_dma_mapping_error. Sending data from this address to hardware will not fail, but the remote peer will get junk data.Fix this by allocating the request on the heap in
smb3_validate_negotiate.Changes in v2:
Removed duplicated code on freeing buffers on function exit. (Thanks to Parav Pandit <[email protected]>) Fixed typo in the patch title.Changes in v3:
Added "Fixes" to the patch.
Changed severalsizeof()to use *pointer in place of struct.Changes in v4:
Added detailed comments on the failure through RDMA. Allocate request buffer usingGPF_NOFS. Fixed possible memory leak.Quoted 4 lines
Fixes ff1c038addc4 ("Check SMB3 dialects against downgrade attacks")Signed-off-by Long Li <[email protected]>--- fs/cifs/smb2pdu.c | 61 ++++++++++++++++++++++++++++++-------------------------
Quoted 9 lines
1 file changed, 33 insertions(+), 28 deletions(-)fs/cifs/smb2pdu.c index renamed from fs/cifs/smb2pdu.c +0
-00f044c4..caa2a1e 100644
fs/cifs/smb2pdu.c +0
-0@@ -729,8 +729,8 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)
Quoted 8 lines
fs/cifs/smb2pdu.c SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses) · line 732
Quoted 5 lines
fs/cifs/smb2pdu.c +1
-2int smb3_validate_negotiate (const unsigned int xid,struct cifs_tcon *tcon) { -int rc =0 ; -struct validate_negotiate_info_req vneg_inbuf; +int ret, rc = -EIO ;Seems awkward to have "rc" and "ret", and based on the code below I don't see why two variables are needed. Simplify? (see later comment)
This is for addressing a prior comment to reduce duplicate code. All the failure paths (after issuing I/O) returning -EIO, there are 5 of them. Set rc to -EIO at the beginning so we don’t need to set it multiple times.
Quoted 152 lines
fs/cifs/smb2pdu.c int smb3_validate_negotiate(const unsigned int
Quoted 14 lines
fs/cifs/smb2pdu.c +1
-0+struct validate_negotiate_info_req *pneg_inbuf;struct validate_negotiate_info_rsp *pneg_rsp =NULL ;u32 rsplen;u32 inbuflen; /* max of 4 dialects */ @@ -741,7 +741,6 @@ int
smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon)
if (tcon->ses->server->rdma)
return 0;
#endiffs/cifs/smb2pdu.c +0
-1-/* In SMB3.11 preauth integrity supersedes validate negotiate */ if (tcon->ses->server->dialect ==SMB311_PROT_ID )return 0 ;@@ -764,63 +763,67 @@ int smb3_validate_negotiate(const unsigned intxid, struct
cifs_tcon*tcon)fs/cifs/smb2pdu.c int smb3_validate_negotiate(const unsigned int · line 764
Quoted 2 lines
fs/cifs/smb2pdu.c +0
-0if (tcon->ses->session_flags &SMB2_SESSION_FLAG_IS_NULL ) cifs_dbg(VFS, "Unexpected null user (anonymous) auth flagsent by
Quoted 8 lines
fs/cifs/smb2pdu.c +5
-1server\n"); - vneg_inbuf.Capabilities = + pneg_inbuf =kmalloc (sizeof (*pneg_inbuf),GFP_NOFS ); +if (!pneg_inbuf) +return -ENOMEM ; + + pneg_inbuf->Capabilities =fs/cifs/smb2pdu.c int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon) · line 783
Quoted 10 lines
fs/cifs/smb2pdu.c +2
-2cpu_to_le32 (tcon->ses->server->vals- req_capabilities); -memcpy (vneg_inbuf.Guid, tcon->ses->server->client_guid, +memcpy (pneg_inbuf->Guid, tcon->ses->server->client_guid,SMB2_CLIENT_GUID_SIZE );if (tcon->ses->sign) - vneg_inbuf.SecurityMode = + pneg_inbuf->SecurityMode =cpu_to_le16(SMB2_NEGOTIATE_SIGNING_REQUIRED);fs/cifs/smb2pdu.c int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon) · line 783
Quoted 4 lines
fs/cifs/smb2pdu.c +1
-1else if (global_secflags &CIFSSEC_MAY_SIGN ) - vneg_inbuf.SecurityMode = + pneg_inbuf->SecurityMode =cpu_to_le16(SMB2_NEGOTIATE_SIGNING_ENABLED);Quoted 5 lines
fs/cifs/smb2pdu.c +1
-1else - vneg_inbuf.SecurityMode =0 ; + pneg_inbuf->SecurityMode =0 ;fs/cifs/smb2pdu.c int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon) · line 791
Quoted 10 lines
fs/cifs/smb2pdu.c +3
-3if (strcmp (tcon->ses->server->vals->version_string,SMB3ANY_VERSION_STRING ) ==0 ) { - vneg_inbuf.Dialects[0 ] =cpu_to_le16 (SMB30_PROT_ID ); - vneg_inbuf.Dialects[1 ] =cpu_to_le16 (SMB302_PROT_ID ); - vneg_inbuf.DialectCount =cpu_to_le16 (2 ); + pneg_inbuf->Dialects[0 ] =cpu_to_le16 (SMB30_PROT_ID ); + pneg_inbuf->Dialects[1 ] =cpu_to_le16 (SMB302_PROT_ID ); + pneg_inbuf->DialectCount =cpu_to_le16 (2 );/* structure is big enough for 3 dialects, sending only 2 */ inbuflen =sizeof (struct validate_negotiate_info_req ) -2 ;The "- 2" is a little confusing here. This was existing code, but I suggest you change this to a sizeof (u16) construct for consistency.
It's reducing by the length of a single Dialects[n] entry.Quoted 11 lines
fs/cifs/smb2pdu.c +4
-4}else if (strcmp (tcon->ses->server->vals->version_string,SMBDEFAULT_VERSION_STRING ) ==0 ) { - vneg_inbuf.Dialects[0 ] =cpu_to_le16 (SMB21_PROT_ID ); - vneg_inbuf.Dialects[1 ] =cpu_to_le16 (SMB30_PROT_ID ); - vneg_inbuf.Dialects[2 ] =cpu_to_le16 (SMB302_PROT_ID ); - vneg_inbuf.DialectCount =cpu_to_le16 (3 ); + pneg_inbuf->Dialects[0 ] =cpu_to_le16 (SMB21_PROT_ID ); + pneg_inbuf->Dialects[1 ] =cpu_to_le16 (SMB30_PROT_ID ); + pneg_inbuf->Dialects[2 ] =cpu_to_le16 (SMB302_PROT_ID ); + pneg_inbuf->DialectCount =cpu_to_le16 (3 );/* structure is big enough for 3 dialects */ fs/cifs/smb2pdu.c int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon) · line 806
Quoted 10 lines
fs/cifs/smb2pdu.c +2
-2inbuflen =sizeof (struct validate_negotiate_info_req ); }else {/* otherwise specific dialect was requested */ - vneg_inbuf.Dialects[0 ] = + pneg_inbuf->Dialects[0 ] =cpu_to_le16 (tcon->ses->server->vals->protocol_id); - vneg_inbuf.DialectCount =cpu_to_le16 (1 ); + pneg_inbuf->DialectCount =cpu_to_le16 (1 );/* structure is big enough for 3 dialects, sending only 1 */ inbuflen =sizeof (struct validate_negotiate_info_req ) -4 ;Ditto previous sizeof (u16) comment, with a *2 this case.
fs/cifs/smb2pdu.c int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon)
Quoted 6 lines
fs/cifs/smb2pdu.c +1
-2} - rc = SMB2_ioctl(xid, tcon, NO_FILE_ID, NO_FILE_ID, + ret = SMB2_ioctl(xid, tcon, NO_FILE_ID, NO_FILE_ID, FSCTL_VALIDATE_NEGOTIATE_INFO, true /* is_fsctl */, - (char *)&vneg_inbuf, sizeof(struct
validate_negotiate_info_req),fs/cifs/smb2pdu.c int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon) · line 817
Quoted 10 lines
fs/cifs/smb2pdu.c +4
-3+ (char *)pneg_inbuf,sizeof (*pneg_inbuf), (char **)&pneg_rsp, &rsplen); -if (rc !=0 ) { -cifs_dbg (VFS ,"validate protocol negotiate failed: %d\n" , rc); -return -EIO ; +if (ret) { +cifs_dbg (VFS ,"validate protocol negotiate failed: %d\n" , ret); + goto out_free_inbuf; }Why not leave "rc" alone, and set its value to
-EIObefore the goto if the ioctl fails? That will simplify and make the code much more readable IMO.fs/cifs/smb2pdu.c int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon)
Quoted 4 lines
fs/cifs/smb2pdu.c +1
-1-if (rsplen !=sizeof (struct validate_negotiate_info_rsp )) { +if (rsplen !=sizeof (*pneg_rsp)) { cifs_dbg(VFS, "invalid protocol negotiate responsesize: %d\n",
fs/cifs/smb2pdu.c int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon)
Quoted 3 lines
fs/cifs/smb2pdu.c +0
-0rsplen);/* relax check since Mac returns max bufsize allowed on ioctl */
fs/cifs/smb2pdu.c int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon) · line 827
Quoted 5 lines
fs/cifs/smb2pdu.c +1
-1if ((rsplen > CIFSMaxBufSize) || (rsplen <sizeof (struct validate_negotiate_info_rsp ))) - goto err_rsp_free; + goto out_free_rsp; }Would need an rc =
-EIOhere too if above comment is accepted.Tom.
Quoted 26 lines
fs/cifs/smb2pdu.c +0
-0/* check validate negotiate info response matches what we got earlier */ @@ -838,14 +841,16 @@ int
smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon)/* validate negotiate successful */ cifs_dbg(FYI, "validate negotiate info successful\n");fs/cifs/smb2pdu.c +2
-2-kfree (pneg_rsp); -return 0 ; + rc =0 ; + goto out_free_rsp; vneg_out: cifs_dbg(VFS, "protocol revalidation - security settingsmismatch\n");
fs/cifs/smb2pdu.c +4
-2-err_rsp_free: +out_free_rsp:kfree (pneg_rsp); -return -EIO ; +out_free_inbuf: +kfree (pneg_inbuf); +return rc; }enum securityEnum
Tom Talpey
reviewerQuoted 53 lines · Long Li
Quoted 44 lines
Subject: Re: [Patch v4] cifs: Allocate validate negotiation request through kmalloc
Looks good, but I have two possibly style-related comments.
Quoted 24 lines · Long Li
From: Long Li <[email protected]>
The data buffer allocated on the stack can't be DMA'ed,
ib_dma_map_pagewill return an invalid DMA address for a buffer on stack. Even worse, this incorrect address can't be detected byib_dma_mapping_error. Sending data from this address to hardware will not fail, but the remote peer will get junk data.Fix this by allocating the request on the heap in
smb3_validate_negotiate.Changes in v2:
Removed duplicated code on freeing buffers on function exit. (Thanks to Parav Pandit <[email protected]>) Fixed typo in the patch title.Changes in v3:
Added "Fixes" to the patch.
Changed severalsizeof()to use *pointer in place of struct.Changes in v4:
Added detailed comments on the failure through RDMA. Allocate request buffer usingGPF_NOFS. Fixed possible memory leak.Quoted 4 lines
Fixes ff1c038addc4 ("Check SMB3 dialects against downgrade attacks")Signed-off-by Long Li <[email protected]>--- fs/cifs/smb2pdu.c | 61 ++++++++++++++++++++++++++++++-------------------------
Quoted 9 lines
1 file changed, 33 insertions(+), 28 deletions(-)fs/cifs/smb2pdu.c index renamed from fs/cifs/smb2pdu.c +0
-00f044c4..caa2a1e 100644
fs/cifs/smb2pdu.c +0
-0@@ -729,8 +729,8 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)Quoted 8 lines
fs/cifs/smb2pdu.c SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses) · line 732
Quoted 5 lines
fs/cifs/smb2pdu.c +1
-2int smb3_validate_negotiate (const unsigned int xid,struct cifs_tcon *tcon) { -int rc =0 ; -struct validate_negotiate_info_req vneg_inbuf; +int ret, rc = -EIO ;Seems awkward to have "rc" and "ret", and based on the code below I don't see why two variables are needed. Simplify? (see later comment)
Quoted 3 lines
This is for addressing a prior comment to reduce duplicate code. All the failure paths (after issuing I/O) returning
-EIO, there are 5 of them. Set rc to-EIOat the beginning so we don’t need to set it multiple times.
Well, ok but now there are semi-duplicate and rather confusing "rc" and "ret" local variables, only one of which is actually returned.
How about a "goto err" with unconditonal -EIO, and just leave the "return 0" path alone, like it was? That would be much clearer IMO.
As-is, I needed to read it several times to convince myself the right rc was returned.
Tom,
Quoted 151 lines
Quoted 151 lines
fs/cifs/smb2pdu.c int smb3_validate_negotiate(const unsigned int
Quoted 15 lines
fs/cifs/smb2pdu.c +1
-0+struct validate_negotiate_info_req *pneg_inbuf;struct validate_negotiate_info_rsp *pneg_rsp =NULL ;u32 rsplen;u32 inbuflen; /* max of 4 dialects */ @@ -741,7 +741,6 @@ int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon) if (tcon->ses->server->rdma) return 0; #endiffs/cifs/smb2pdu.c +0
-1-/* In SMB3.11 preauth integrity supersedes validate negotiate */ if (tcon->ses->server->dialect ==SMB311_PROT_ID )return 0 ;@@ -764,63 +763,67 @@ int smb3_validate_negotiate(const unsigned intxid, struct
cifs_tcon*tcon)fs/cifs/smb2pdu.c int smb3_validate_negotiate(const unsigned int · line 764
Quoted 2 lines
fs/cifs/smb2pdu.c +0
-0if (tcon->ses->session_flags &SMB2_SESSION_FLAG_IS_NULL ) cifs_dbg(VFS, "Unexpected null user (anonymous) auth flagsent by
Quoted 8 lines
fs/cifs/smb2pdu.c +5
-1server\n"); - vneg_inbuf.Capabilities = + pneg_inbuf =kmalloc (sizeof (*pneg_inbuf),GFP_NOFS ); +if (!pneg_inbuf) +return -ENOMEM ; + + pneg_inbuf->Capabilities =fs/cifs/smb2pdu.c int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon) · line 783
Quoted 10 lines
fs/cifs/smb2pdu.c +2
-2cpu_to_le32 (tcon->ses->server->vals- req_capabilities); -memcpy (vneg_inbuf.Guid, tcon->ses->server->client_guid, +memcpy (pneg_inbuf->Guid, tcon->ses->server->client_guid,SMB2_CLIENT_GUID_SIZE );if (tcon->ses->sign) - vneg_inbuf.SecurityMode = + pneg_inbuf->SecurityMode =cpu_to_le16(SMB2_NEGOTIATE_SIGNING_REQUIRED);fs/cifs/smb2pdu.c int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon) · line 783
Quoted 4 lines
fs/cifs/smb2pdu.c +1
-1else if (global_secflags &CIFSSEC_MAY_SIGN ) - vneg_inbuf.SecurityMode = + pneg_inbuf->SecurityMode =cpu_to_le16(SMB2_NEGOTIATE_SIGNING_ENABLED);Quoted 5 lines
fs/cifs/smb2pdu.c +1
-1else - vneg_inbuf.SecurityMode =0 ; + pneg_inbuf->SecurityMode =0 ;fs/cifs/smb2pdu.c int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon) · line 791
Quoted 10 lines
fs/cifs/smb2pdu.c +3
-3if (strcmp (tcon->ses->server->vals->version_string,SMB3ANY_VERSION_STRING ) ==0 ) { - vneg_inbuf.Dialects[0 ] =cpu_to_le16 (SMB30_PROT_ID ); - vneg_inbuf.Dialects[1 ] =cpu_to_le16 (SMB302_PROT_ID ); - vneg_inbuf.DialectCount =cpu_to_le16 (2 ); + pneg_inbuf->Dialects[0 ] =cpu_to_le16 (SMB30_PROT_ID ); + pneg_inbuf->Dialects[1 ] =cpu_to_le16 (SMB302_PROT_ID ); + pneg_inbuf->DialectCount =cpu_to_le16 (2 );/* structure is big enough for 3 dialects, sending only 2 */ inbuflen =sizeof (struct validate_negotiate_info_req ) -2 ;The "- 2" is a little confusing here. This was existing code, but I suggest you change this to a sizeof (u16) construct for consistency.
It's reducing by the length of a single Dialects[n] entry.Quoted 11 lines
fs/cifs/smb2pdu.c +4
-4}else if (strcmp (tcon->ses->server->vals->version_string,SMBDEFAULT_VERSION_STRING ) ==0 ) { - vneg_inbuf.Dialects[0 ] =cpu_to_le16 (SMB21_PROT_ID ); - vneg_inbuf.Dialects[1 ] =cpu_to_le16 (SMB30_PROT_ID ); - vneg_inbuf.Dialects[2 ] =cpu_to_le16 (SMB302_PROT_ID ); - vneg_inbuf.DialectCount =cpu_to_le16 (3 ); + pneg_inbuf->Dialects[0 ] =cpu_to_le16 (SMB21_PROT_ID ); + pneg_inbuf->Dialects[1 ] =cpu_to_le16 (SMB30_PROT_ID ); + pneg_inbuf->Dialects[2 ] =cpu_to_le16 (SMB302_PROT_ID ); + pneg_inbuf->DialectCount =cpu_to_le16 (3 );/* structure is big enough for 3 dialects */ fs/cifs/smb2pdu.c int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon) · line 806
Quoted 10 lines
fs/cifs/smb2pdu.c +2
-2inbuflen =sizeof (struct validate_negotiate_info_req ); }else {/* otherwise specific dialect was requested */ - vneg_inbuf.Dialects[0 ] = + pneg_inbuf->Dialects[0 ] =cpu_to_le16 (tcon->ses->server->vals->protocol_id); - vneg_inbuf.DialectCount =cpu_to_le16 (1 ); + pneg_inbuf->DialectCount =cpu_to_le16 (1 );/* structure is big enough for 3 dialects, sending only 1 */ inbuflen =sizeof (struct validate_negotiate_info_req ) -4 ;Ditto previous sizeof (u16) comment, with a *2 this case.
fs/cifs/smb2pdu.c int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon)
Quoted 6 lines
fs/cifs/smb2pdu.c +1
-2} - rc = SMB2_ioctl(xid, tcon, NO_FILE_ID, NO_FILE_ID, + ret = SMB2_ioctl(xid, tcon, NO_FILE_ID, NO_FILE_ID, FSCTL_VALIDATE_NEGOTIATE_INFO, true /* is_fsctl */, - (char *)&vneg_inbuf, sizeof(struct
validate_negotiate_info_req),fs/cifs/smb2pdu.c int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon) · line 817
Quoted 10 lines
fs/cifs/smb2pdu.c +4
-3+ (char *)pneg_inbuf,sizeof (*pneg_inbuf), (char **)&pneg_rsp, &rsplen); -if (rc !=0 ) { -cifs_dbg (VFS ,"validate protocol negotiate failed: %d\n" , rc); -return -EIO ; +if (ret) { +cifs_dbg (VFS ,"validate protocol negotiate failed: %d\n" , ret); + goto out_free_inbuf; }Why not leave "rc" alone, and set its value to
-EIObefore the goto if the ioctl fails? That will simplify and make the code much more readable IMO.fs/cifs/smb2pdu.c int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon)
Quoted 4 lines
fs/cifs/smb2pdu.c +1
-1-if (rsplen !=sizeof (struct validate_negotiate_info_rsp )) { +if (rsplen !=sizeof (*pneg_rsp)) { cifs_dbg(VFS, "invalid protocol negotiate responsesize: %d\n",
fs/cifs/smb2pdu.c int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon)
Quoted 3 lines
fs/cifs/smb2pdu.c +0
-0rsplen);/* relax check since Mac returns max bufsize allowed on ioctl */
fs/cifs/smb2pdu.c int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon) · line 827
Quoted 5 lines
fs/cifs/smb2pdu.c +1
-1if ((rsplen > CIFSMaxBufSize) || (rsplen <sizeof (struct validate_negotiate_info_rsp ))) - goto err_rsp_free; + goto out_free_rsp; }Would need an rc =
-EIOhere too if above comment is accepted.Tom.
Quoted 24 lines
fs/cifs/smb2pdu.c +0
-0/* check validate negotiate info response matches what we got earlier */ @@ -838,14 +841,16 @@ int
smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon)/* validate negotiate successful */ cifs_dbg(FYI, "validate negotiate info successful\n");fs/cifs/smb2pdu.c +2
-2-kfree (pneg_rsp); -return 0 ; + rc =0 ; + goto out_free_rsp; vneg_out: cifs_dbg(VFS, "protocol revalidation - security settingsmismatch\n");
fs/cifs/smb2pdu.c +4
-2-err_rsp_free: +out_free_rsp:kfree (pneg_rsp); -return -EIO ; +out_free_inbuf: +kfree (pneg_inbuf); +return rc; }
Quoted 3 lines
Quoted 2 lines
Quoted 2 lines
enum securityEnum
N�����r��y���b�X��ǧv�^�){.n�+����{��ٚ�{ay�
ʇڙ�,j��f���h���z�
�w���
���j:+v���w�j�m��������zZ+�����ݢj"��!tml=
Quoted 1 line
Quoted 64 lines
Subject: Re: [Patch v4] cifs: Allocate validate negotiation request through kmalloc
Quoted 8 lines · Long Li
Quoted 8 lines
Subject: Re: [Patch v4] cifs: Allocate validate negotiation request through kmalloc
Looks good, but I have two possibly style-related comments.
Quoted 2 lines · Long Li
From: Long Li <[email protected]>
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
The data buffer allocated on the stack can't be DMA'ed,
ib_dma_map_pagewill return an invalid DMA address for a buffer on stack. Even worse, this incorrect address can't be detected byib_dma_mapping_error. Sending data from this address to hardware will not fail, but the remote peer will get junk data.Fix this by allocating the request on the heap in
smb3_validate_negotiate.Quoted 24 lines
Quoted 24 lines
Quoted 15 lines
Changes in v2:
Removed duplicated code on freeing buffers on function exit. (Thanks to Parav Pandit <[email protected]>) Fixed typo in the patch title.Changes in v3:
Added "Fixes" to the patch.
Changed severalsizeof()to use *pointer in place of struct.Changes in v4:
Added detailed comments on the failure through RDMA. Allocate request buffer usingGPF_NOFS. Fixed possible memory leak.Quoted 6 lines
Fixes ff1c038addc4 ("Check SMB3 dialects against downgradeattacks")
Signed-off-by Long Li <[email protected]>--- fs/cifs/smb2pdu.c | 61++++++++++++++++++++++++++++++--------------
-----------
Quoted 2 lines
1 file changed, 33 insertions(+), 28 deletions(-)Quoted 8 lines
Quoted 8 lines
fs/cifs/smb2pdu.c SMB2_negotiate(const unsigned int xid, struct · line 731
Quoted 8 lines
fs/cifs/smb2pdu.c index renamed from fs/cifs/smb2pdu.c +0
-00f044c4..caa2a1e 100644
fs/cifs/smb2pdu.c +0
-0@@ -729,8 +729,8 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses) int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon*tcon)
Quoted 11 lines
Quoted 7 lines
fs/cifs/smb2pdu.c SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses) · line 732
Quoted 4 lines
fs/cifs/smb2pdu.c +1
-2{ -int rc =0 ; -struct validate_negotiate_info_req vneg_inbuf; +int ret, rc = -EIO ;Seems awkward to have "rc" and "ret", and based on the code below I don't see why two variables are needed. Simplify? (see later comment)
This is for addressing a prior comment to reduce duplicate code. All the failure paths (after issuing I/O) returning
-EIO, there are 5 of them. Set rc to-EIOat the beginning so we don’t need to set it multiple
Quoted 7 lines
times.
Well, ok but now there are semi-duplicate and rather confusing "rc" and "ret" local variables, only one of which is actually returned.
How about a "goto err" with unconditonal
-EIO, and just leave the "return 0" path alone, like it was? That would be much clearer IMO.
That means we'll have to call kfree(pneg_rsp) and kfree(pneg_inbuf) on the return 0 path, as well as the return -EIO path.
I'm happy to do that if there is no objection.
Quoted 175 lines
As-is, I needed to read it several times to convince myself the right rc was returned.
Tom,
Quoted 15 lines
Quoted 15 lines
fs/cifs/smb2pdu.c int smb3_validate_negotiate(const unsigned
Quoted 15 lines
fs/cifs/smb2pdu.c +1
-0+struct validate_negotiate_info_req *pneg_inbuf;struct validate_negotiate_info_rsp *pneg_rsp =NULL ;u32 rsplen;u32 inbuflen; /* max of 4 dialects */ @@ -741,7 +741,6 @@ int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon) if (tcon->ses->server->rdma) return 0; #endiffs/cifs/smb2pdu.c +0
-1-/* In SMB3.11 preauth integrity supersedes validate negotiate */ if (tcon->ses->server->dialect ==SMB311_PROT_ID )return 0 ;@@ -764,63 +763,67 @@ int smb3_validate_negotiate(const unsignedint
Quoted 82 lines
Quoted 82 lines
xid, struct
cifs_tcon*tcon)fs/cifs/smb2pdu.c int smb3_validate_negotiate(const unsigned · line 764
Quoted 2 lines
fs/cifs/smb2pdu.c +0
-0if (tcon->ses->session_flags &SMB2_SESSION_FLAG_IS_NULL ) cifs_dbg(VFS, "Unexpected null user (anonymous) auth flagsent by
Quoted 8 lines
fs/cifs/smb2pdu.c +5
-1server\n"); - vneg_inbuf.Capabilities = + pneg_inbuf =kmalloc (sizeof (*pneg_inbuf),GFP_NOFS ); +if (!pneg_inbuf) +return -ENOMEM ; + + pneg_inbuf->Capabilities =fs/cifs/smb2pdu.c int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon) · line 783
Quoted 10 lines
fs/cifs/smb2pdu.c +2
-2cpu_to_le32 (tcon->ses->server->vals- req_capabilities); -memcpy (vneg_inbuf.Guid, tcon->ses->server->client_guid, +memcpy (pneg_inbuf->Guid, tcon->ses->server->client_guid,SMB2_CLIENT_GUID_SIZE );if (tcon->ses->sign) - vneg_inbuf.SecurityMode = + pneg_inbuf->SecurityMode =cpu_to_le16(SMB2_NEGOTIATE_SIGNING_REQUIRED);fs/cifs/smb2pdu.c int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon) · line 783
Quoted 4 lines
fs/cifs/smb2pdu.c +1
-1else if (global_secflags &CIFSSEC_MAY_SIGN ) - vneg_inbuf.SecurityMode = + pneg_inbuf->SecurityMode =cpu_to_le16(SMB2_NEGOTIATE_SIGNING_ENABLED);Quoted 5 lines
fs/cifs/smb2pdu.c +1
-1else - vneg_inbuf.SecurityMode =0 ; + pneg_inbuf->SecurityMode =0 ;fs/cifs/smb2pdu.c int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon) · line 791
Quoted 10 lines
fs/cifs/smb2pdu.c +3
-3if (strcmp (tcon->ses->server->vals->version_string,SMB3ANY_VERSION_STRING ) ==0 ) { - vneg_inbuf.Dialects[0 ] =cpu_to_le16 (SMB30_PROT_ID ); - vneg_inbuf.Dialects[1 ] =cpu_to_le16 (SMB302_PROT_ID ); - vneg_inbuf.DialectCount =cpu_to_le16 (2 ); + pneg_inbuf->Dialects[0 ] =cpu_to_le16 (SMB30_PROT_ID ); + pneg_inbuf->Dialects[1 ] =cpu_to_le16 (SMB302_PROT_ID ); + pneg_inbuf->DialectCount =cpu_to_le16 (2 );/* structure is big enough for 3 dialects, sending only 2 */ inbuflen =sizeof (struct validate_negotiate_info_req ) -2 ;The "- 2" is a little confusing here. This was existing code, but I suggest you change this to a sizeof (u16) construct for consistency. It's reducing by the length of a single Dialects[n] entry.
Quoted 11 lines
fs/cifs/smb2pdu.c +4
-4}else if (strcmp (tcon->ses->server->vals->version_string,SMBDEFAULT_VERSION_STRING ) ==0 ) { - vneg_inbuf.Dialects[0 ] =cpu_to_le16 (SMB21_PROT_ID ); - vneg_inbuf.Dialects[1 ] =cpu_to_le16 (SMB30_PROT_ID ); - vneg_inbuf.Dialects[2 ] =cpu_to_le16 (SMB302_PROT_ID ); - vneg_inbuf.DialectCount =cpu_to_le16 (3 ); + pneg_inbuf->Dialects[0 ] =cpu_to_le16 (SMB21_PROT_ID ); + pneg_inbuf->Dialects[1 ] =cpu_to_le16 (SMB30_PROT_ID ); + pneg_inbuf->Dialects[2 ] =cpu_to_le16 (SMB302_PROT_ID ); + pneg_inbuf->DialectCount =cpu_to_le16 (3 );/* structure is big enough for 3 dialects */ fs/cifs/smb2pdu.c int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon) · line 806
Quoted 10 lines
fs/cifs/smb2pdu.c +2
-2inbuflen =sizeof (struct validate_negotiate_info_req ); }else {/* otherwise specific dialect was requested */ - vneg_inbuf.Dialects[0 ] = + pneg_inbuf->Dialects[0 ] =cpu_to_le16 (tcon->ses->server->vals->protocol_id); - vneg_inbuf.DialectCount =cpu_to_le16 (1 ); + pneg_inbuf->DialectCount =cpu_to_le16 (1 );/* structure is big enough for 3 dialects, sending only 1 */ inbuflen =sizeof (struct validate_negotiate_info_req ) -4 ;Ditto previous sizeof (u16) comment, with a *2 this case.
fs/cifs/smb2pdu.c int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon)
Quoted 6 lines
fs/cifs/smb2pdu.c +1
-2} - rc = SMB2_ioctl(xid, tcon, NO_FILE_ID, NO_FILE_ID, + ret = SMB2_ioctl(xid, tcon, NO_FILE_ID, NO_FILE_ID, FSCTL_VALIDATE_NEGOTIATE_INFO, true /* is_fsctl */, - (char *)&vneg_inbuf, sizeof(struct
validate_negotiate_info_req),Quoted 3 lines
fs/cifs/smb2pdu.c +1
-0+ (char *)pneg_inbuf,sizeof (*pneg_inbuf), (char **)&pneg_rsp, &rsplen);Quoted 10 lines
Quoted 10 lines
fs/cifs/smb2pdu.c int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon) · line 817
Quoted 7 lines
fs/cifs/smb2pdu.c +3
-3-if (rc !=0 ) { -cifs_dbg (VFS ,"validate protocol negotiate failed: %d\n" , rc); -return -EIO ; +if (ret) { +cifs_dbg (VFS ,"validate protocol negotiate failed: %d\n" , ret); + goto out_free_inbuf; }Why not leave "rc" alone, and set its value to
-EIObefore the goto if the ioctl fails? That will simplify and make the code much more readableIMO.
Quoted 44 lines
Quoted 44 lines
fs/cifs/smb2pdu.c int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon)
Quoted 5 lines
fs/cifs/smb2pdu.c +1
-1-if (rsplen !=sizeof (struct validate_negotiate_info_rsp )) { +if (rsplen !=sizeof (*pneg_rsp)) { cifs_dbg(VFS, "invalid protocol negotiate responsesize: %d\n",
fs/cifs/smb2pdu.c int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon)
Quoted 3 lines
fs/cifs/smb2pdu.c +0
-0rsplen);/* relax check since Mac returns max bufsize allowed on ioctl */
fs/cifs/smb2pdu.c int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon) · line 827
Quoted 5 lines
fs/cifs/smb2pdu.c +1
-1if ((rsplen > CIFSMaxBufSize) || (rsplen <sizeof (struct validate_negotiate_info_rsp ))) - goto err_rsp_free; + goto out_free_rsp; }Would need an rc =
-EIOhere too if above comment is accepted.Tom.
Quoted 24 lines
fs/cifs/smb2pdu.c +0
-0/* check validate negotiate info response matches what we got earlier */ @@ -838,14 +841,16 @@ int
smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon)/* validate negotiate successful */ cifs_dbg(FYI, "validate negotiate info successful\n");fs/cifs/smb2pdu.c +2
-2-kfree (pneg_rsp); -return 0 ; + rc =0 ; + goto out_free_rsp; vneg_out: cifs_dbg(VFS, "protocol revalidation - security settingsmismatch\n");
fs/cifs/smb2pdu.c +4
-2-err_rsp_free: +out_free_rsp:kfree (pneg_rsp); -return -EIO ; +out_free_inbuf: +kfree (pneg_inbuf); +return rc; }Quoted 3 lines
Quoted 2 lines
Quoted 2 lines
enum securityEnum
N r y b X ǧv ^ ){.n + { ٚ {ay ʇڙ ,j f h z w
j:+v w j m zZ+ ݢj" !tml=
Quoted 1 line
--
To unsubscribe from this list: send the line "unsubscribe linux-cifs" in the body of a message to [email protected] More majordomo info at
https://na01.safelinks.protection.outlook.com/?url=http%3A%2F%2Fvger.ke
rnel.org%2Fmajordomo- info.html&data=02%7C01%7Clongli%40microsoft.com%7C713a34e4889147ee d4fd08d5a6ef951e%7C72f988bf86f141af91ab2d7cd011db47%7C1%7C0%7C63 6598470290134086&sdata=RfS2Gs9cqoxkofoFtqcMTtSquLOZD09ffLhdlWCj2S 4%3D&reserved=0