Skip to content

Commit 2796d30

Browse files
longlimsftsmfrench
authored andcommitted
cifs: Allocate validate negotiation request through kmalloc
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. Changes in v5: Removed variable ret for checking return value. Changed to use pneg_inbuf->Dialects[0] to calculate unused space in pneg_inbuf. Fixes: ff1c038 ("Check SMB3 dialects against downgrade attacks") Signed-off-by: Long Li <[email protected]> Signed-off-by: Steve French <[email protected]> Reviewed-by: Ronnie Sahlberg <[email protected]> Reviewed-by: Tom Talpey <[email protected]>
1 parent 036db8b commit 2796d30

File tree

1 file changed

+38
-30
lines changed

1 file changed

+38
-30
lines changed

fs/cifs/smb2pdu.c

Lines changed: 38 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -730,8 +730,8 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)
730730

731731
int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon)
732732
{
733-
int rc = 0;
734-
struct validate_negotiate_info_req vneg_inbuf;
733+
int rc;
734+
struct validate_negotiate_info_req *pneg_inbuf;
735735
struct validate_negotiate_info_rsp *pneg_rsp = NULL;
736736
u32 rsplen;
737737
u32 inbuflen; /* max of 4 dialects */
@@ -765,63 +765,69 @@ int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon)
765765
if (tcon->ses->session_flags & SMB2_SESSION_FLAG_IS_NULL)
766766
cifs_dbg(VFS, "Unexpected null user (anonymous) auth flag sent by server\n");
767767

768-
vneg_inbuf.Capabilities =
768+
pneg_inbuf = kmalloc(sizeof(*pneg_inbuf), GFP_NOFS);
769+
if (!pneg_inbuf)
770+
return -ENOMEM;
771+
772+
pneg_inbuf->Capabilities =
769773
cpu_to_le32(tcon->ses->server->vals->req_capabilities);
770-
memcpy(vneg_inbuf.Guid, tcon->ses->server->client_guid,
774+
memcpy(pneg_inbuf->Guid, tcon->ses->server->client_guid,
771775
SMB2_CLIENT_GUID_SIZE);
772776

773777
if (tcon->ses->sign)
774-
vneg_inbuf.SecurityMode =
778+
pneg_inbuf->SecurityMode =
775779
cpu_to_le16(SMB2_NEGOTIATE_SIGNING_REQUIRED);
776780
else if (global_secflags & CIFSSEC_MAY_SIGN)
777-
vneg_inbuf.SecurityMode =
781+
pneg_inbuf->SecurityMode =
778782
cpu_to_le16(SMB2_NEGOTIATE_SIGNING_ENABLED);
779783
else
780-
vneg_inbuf.SecurityMode = 0;
784+
pneg_inbuf->SecurityMode = 0;
781785

782786

783787
if (strcmp(tcon->ses->server->vals->version_string,
784788
SMB3ANY_VERSION_STRING) == 0) {
785-
vneg_inbuf.Dialects[0] = cpu_to_le16(SMB30_PROT_ID);
786-
vneg_inbuf.Dialects[1] = cpu_to_le16(SMB302_PROT_ID);
787-
vneg_inbuf.DialectCount = cpu_to_le16(2);
789+
pneg_inbuf->Dialects[0] = cpu_to_le16(SMB30_PROT_ID);
790+
pneg_inbuf->Dialects[1] = cpu_to_le16(SMB302_PROT_ID);
791+
pneg_inbuf->DialectCount = cpu_to_le16(2);
788792
/* structure is big enough for 3 dialects, sending only 2 */
789-
inbuflen = sizeof(struct validate_negotiate_info_req) - 2;
793+
inbuflen = sizeof(*pneg_inbuf) -
794+
sizeof(pneg_inbuf->Dialects[0]);
790795
} else if (strcmp(tcon->ses->server->vals->version_string,
791796
SMBDEFAULT_VERSION_STRING) == 0) {
792-
vneg_inbuf.Dialects[0] = cpu_to_le16(SMB21_PROT_ID);
793-
vneg_inbuf.Dialects[1] = cpu_to_le16(SMB30_PROT_ID);
794-
vneg_inbuf.Dialects[2] = cpu_to_le16(SMB302_PROT_ID);
795-
vneg_inbuf.DialectCount = cpu_to_le16(3);
797+
pneg_inbuf->Dialects[0] = cpu_to_le16(SMB21_PROT_ID);
798+
pneg_inbuf->Dialects[1] = cpu_to_le16(SMB30_PROT_ID);
799+
pneg_inbuf->Dialects[2] = cpu_to_le16(SMB302_PROT_ID);
800+
pneg_inbuf->DialectCount = cpu_to_le16(3);
796801
/* structure is big enough for 3 dialects */
797-
inbuflen = sizeof(struct validate_negotiate_info_req);
802+
inbuflen = sizeof(*pneg_inbuf);
798803
} else {
799804
/* otherwise specific dialect was requested */
800-
vneg_inbuf.Dialects[0] =
805+
pneg_inbuf->Dialects[0] =
801806
cpu_to_le16(tcon->ses->server->vals->protocol_id);
802-
vneg_inbuf.DialectCount = cpu_to_le16(1);
807+
pneg_inbuf->DialectCount = cpu_to_le16(1);
803808
/* structure is big enough for 3 dialects, sending only 1 */
804-
inbuflen = sizeof(struct validate_negotiate_info_req) - 4;
809+
inbuflen = sizeof(*pneg_inbuf) -
810+
sizeof(pneg_inbuf->Dialects[0]) * 2;
805811
}
806812

807813
rc = SMB2_ioctl(xid, tcon, NO_FILE_ID, NO_FILE_ID,
808814
FSCTL_VALIDATE_NEGOTIATE_INFO, true /* is_fsctl */,
809-
(char *)&vneg_inbuf, sizeof(struct validate_negotiate_info_req),
810-
(char **)&pneg_rsp, &rsplen);
815+
(char *)pneg_inbuf, inbuflen, (char **)&pneg_rsp, &rsplen);
811816

812817
if (rc != 0) {
813818
cifs_dbg(VFS, "validate protocol negotiate failed: %d\n", rc);
814-
return -EIO;
819+
rc = -EIO;
820+
goto out_free_inbuf;
815821
}
816822

817-
if (rsplen != sizeof(struct validate_negotiate_info_rsp)) {
823+
rc = -EIO;
824+
if (rsplen != sizeof(*pneg_rsp)) {
818825
cifs_dbg(VFS, "invalid protocol negotiate response size: %d\n",
819826
rsplen);
820827

821828
/* relax check since Mac returns max bufsize allowed on ioctl */
822-
if ((rsplen > CIFSMaxBufSize)
823-
|| (rsplen < sizeof(struct validate_negotiate_info_rsp)))
824-
goto err_rsp_free;
829+
if (rsplen > CIFSMaxBufSize || rsplen < sizeof(*pneg_rsp))
830+
goto out_free_rsp;
825831
}
826832

827833
/* check validate negotiate info response matches what we got earlier */
@@ -838,15 +844,17 @@ int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon)
838844
goto vneg_out;
839845

840846
/* validate negotiate successful */
847+
rc = 0;
841848
cifs_dbg(FYI, "validate negotiate info successful\n");
842-
kfree(pneg_rsp);
843-
return 0;
849+
goto out_free_rsp;
844850

845851
vneg_out:
846852
cifs_dbg(VFS, "protocol revalidation - security settings mismatch\n");
847-
err_rsp_free:
853+
out_free_rsp:
848854
kfree(pneg_rsp);
849-
return -EIO;
855+
out_free_inbuf:
856+
kfree(pneg_inbuf);
857+
return rc;
850858
}
851859

852860
enum securityEnum

0 commit comments

Comments
 (0)