diff options
author | Pavel Shilovsky <pshilovsky@samba.org> | 2012-09-18 19:20:30 -0400 |
---|---|---|
committer | Steve French <smfrench@gmail.com> | 2012-09-24 22:46:28 -0400 |
commit | 3c1bf7e48e9e463b65b1b90da4500a93dd2b27a7 (patch) | |
tree | c16caed7a01a5b1438b5acd8aa45929889da10ad /fs/cifs | |
parent | 009d344398bb3e844b31eb9e6a7860748c6f6dd3 (diff) |
CIFS: Enable signing in SMB2
Use hmac-sha256 and rather than hmac-md5 that is used for CIFS/SMB.
Signature field in SMB2 header is 16 bytes instead of 8 bytes.
Automatically enable signing by client when requested by the server
when signing ability is available to the client.
Signed-off-by: Shirish Pargaonkar <shirishpargaonkar@gmail.com>
Signed-off-by: Sachin Prabhu <sprabhu@redhat.com>
Signed-off-by: Pavel Shilovsky <piastryyy@gmail.com>
Signed-off-by: Steve French <smfrench@gmail.com>
Diffstat (limited to 'fs/cifs')
-rw-r--r-- | fs/cifs/Kconfig | 1 | ||||
-rw-r--r-- | fs/cifs/cifsencrypt.c | 30 | ||||
-rw-r--r-- | fs/cifs/cifsglob.h | 2 | ||||
-rw-r--r-- | fs/cifs/cifsproto.h | 1 | ||||
-rw-r--r-- | fs/cifs/smb2glob.h | 4 | ||||
-rw-r--r-- | fs/cifs/smb2pdu.c | 52 | ||||
-rw-r--r-- | fs/cifs/smb2proto.h | 2 | ||||
-rw-r--r-- | fs/cifs/smb2transport.c | 165 | ||||
-rw-r--r-- | fs/cifs/transport.c | 24 |
9 files changed, 253 insertions, 28 deletions
diff --git a/fs/cifs/Kconfig b/fs/cifs/Kconfig index a08306a8bec9..802930179c2b 100644 --- a/fs/cifs/Kconfig +++ b/fs/cifs/Kconfig | |||
@@ -9,6 +9,7 @@ config CIFS | |||
9 | select CRYPTO_ARC4 | 9 | select CRYPTO_ARC4 |
10 | select CRYPTO_ECB | 10 | select CRYPTO_ECB |
11 | select CRYPTO_DES | 11 | select CRYPTO_DES |
12 | select CRYPTO_SHA256 | ||
12 | help | 13 | help |
13 | This is the client VFS module for the Common Internet File System | 14 | This is the client VFS module for the Common Internet File System |
14 | (CIFS) protocol which is the successor to the Server Message Block | 15 | (CIFS) protocol which is the successor to the Server Message Block |
diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index 6a0d741159f0..724738c1a560 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c | |||
@@ -686,12 +686,17 @@ calc_seckey(struct cifs_ses *ses) | |||
686 | void | 686 | void |
687 | cifs_crypto_shash_release(struct TCP_Server_Info *server) | 687 | cifs_crypto_shash_release(struct TCP_Server_Info *server) |
688 | { | 688 | { |
689 | if (server->secmech.hmacsha256) | ||
690 | crypto_free_shash(server->secmech.hmacsha256); | ||
691 | |||
689 | if (server->secmech.md5) | 692 | if (server->secmech.md5) |
690 | crypto_free_shash(server->secmech.md5); | 693 | crypto_free_shash(server->secmech.md5); |
691 | 694 | ||
692 | if (server->secmech.hmacmd5) | 695 | if (server->secmech.hmacmd5) |
693 | crypto_free_shash(server->secmech.hmacmd5); | 696 | crypto_free_shash(server->secmech.hmacmd5); |
694 | 697 | ||
698 | kfree(server->secmech.sdeschmacsha256); | ||
699 | |||
695 | kfree(server->secmech.sdeschmacmd5); | 700 | kfree(server->secmech.sdeschmacmd5); |
696 | 701 | ||
697 | kfree(server->secmech.sdescmd5); | 702 | kfree(server->secmech.sdescmd5); |
@@ -716,6 +721,13 @@ cifs_crypto_shash_allocate(struct TCP_Server_Info *server) | |||
716 | goto crypto_allocate_md5_fail; | 721 | goto crypto_allocate_md5_fail; |
717 | } | 722 | } |
718 | 723 | ||
724 | server->secmech.hmacsha256 = crypto_alloc_shash("hmac(sha256)", 0, 0); | ||
725 | if (IS_ERR(server->secmech.hmacsha256)) { | ||
726 | cERROR(1, "could not allocate crypto hmacsha256\n"); | ||
727 | rc = PTR_ERR(server->secmech.hmacsha256); | ||
728 | goto crypto_allocate_hmacsha256_fail; | ||
729 | } | ||
730 | |||
719 | size = sizeof(struct shash_desc) + | 731 | size = sizeof(struct shash_desc) + |
720 | crypto_shash_descsize(server->secmech.hmacmd5); | 732 | crypto_shash_descsize(server->secmech.hmacmd5); |
721 | server->secmech.sdeschmacmd5 = kmalloc(size, GFP_KERNEL); | 733 | server->secmech.sdeschmacmd5 = kmalloc(size, GFP_KERNEL); |
@@ -727,7 +739,6 @@ cifs_crypto_shash_allocate(struct TCP_Server_Info *server) | |||
727 | server->secmech.sdeschmacmd5->shash.tfm = server->secmech.hmacmd5; | 739 | server->secmech.sdeschmacmd5->shash.tfm = server->secmech.hmacmd5; |
728 | server->secmech.sdeschmacmd5->shash.flags = 0x0; | 740 | server->secmech.sdeschmacmd5->shash.flags = 0x0; |
729 | 741 | ||
730 | |||
731 | size = sizeof(struct shash_desc) + | 742 | size = sizeof(struct shash_desc) + |
732 | crypto_shash_descsize(server->secmech.md5); | 743 | crypto_shash_descsize(server->secmech.md5); |
733 | server->secmech.sdescmd5 = kmalloc(size, GFP_KERNEL); | 744 | server->secmech.sdescmd5 = kmalloc(size, GFP_KERNEL); |
@@ -739,12 +750,29 @@ cifs_crypto_shash_allocate(struct TCP_Server_Info *server) | |||
739 | server->secmech.sdescmd5->shash.tfm = server->secmech.md5; | 750 | server->secmech.sdescmd5->shash.tfm = server->secmech.md5; |
740 | server->secmech.sdescmd5->shash.flags = 0x0; | 751 | server->secmech.sdescmd5->shash.flags = 0x0; |
741 | 752 | ||
753 | size = sizeof(struct shash_desc) + | ||
754 | crypto_shash_descsize(server->secmech.hmacsha256); | ||
755 | server->secmech.sdeschmacsha256 = kmalloc(size, GFP_KERNEL); | ||
756 | if (!server->secmech.sdeschmacsha256) { | ||
757 | cERROR(1, "%s: Can't alloc hmacsha256\n", __func__); | ||
758 | rc = -ENOMEM; | ||
759 | goto crypto_allocate_hmacsha256_sdesc_fail; | ||
760 | } | ||
761 | server->secmech.sdeschmacsha256->shash.tfm = server->secmech.hmacsha256; | ||
762 | server->secmech.sdeschmacsha256->shash.flags = 0x0; | ||
763 | |||
742 | return 0; | 764 | return 0; |
743 | 765 | ||
766 | crypto_allocate_hmacsha256_sdesc_fail: | ||
767 | kfree(server->secmech.sdescmd5); | ||
768 | |||
744 | crypto_allocate_md5_sdesc_fail: | 769 | crypto_allocate_md5_sdesc_fail: |
745 | kfree(server->secmech.sdeschmacmd5); | 770 | kfree(server->secmech.sdeschmacmd5); |
746 | 771 | ||
747 | crypto_allocate_hmacmd5_sdesc_fail: | 772 | crypto_allocate_hmacmd5_sdesc_fail: |
773 | crypto_free_shash(server->secmech.hmacsha256); | ||
774 | |||
775 | crypto_allocate_hmacsha256_fail: | ||
748 | crypto_free_shash(server->secmech.md5); | 776 | crypto_free_shash(server->secmech.md5); |
749 | 777 | ||
750 | crypto_allocate_md5_fail: | 778 | crypto_allocate_md5_fail: |
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 48c7c83a7a99..6217df707909 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h | |||
@@ -128,8 +128,10 @@ struct sdesc { | |||
128 | struct cifs_secmech { | 128 | struct cifs_secmech { |
129 | struct crypto_shash *hmacmd5; /* hmac-md5 hash function */ | 129 | struct crypto_shash *hmacmd5; /* hmac-md5 hash function */ |
130 | struct crypto_shash *md5; /* md5 hash function */ | 130 | struct crypto_shash *md5; /* md5 hash function */ |
131 | struct crypto_shash *hmacsha256; /* hmac-sha256 hash function */ | ||
131 | struct sdesc *sdeschmacmd5; /* ctxt to generate ntlmv2 hash, CR1 */ | 132 | struct sdesc *sdeschmacmd5; /* ctxt to generate ntlmv2 hash, CR1 */ |
132 | struct sdesc *sdescmd5; /* ctxt to generate cifs/smb signature */ | 133 | struct sdesc *sdescmd5; /* ctxt to generate cifs/smb signature */ |
134 | struct sdesc *sdeschmacsha256; /* ctxt to generate smb2 signature */ | ||
133 | }; | 135 | }; |
134 | 136 | ||
135 | /* per smb session structure/fields */ | 137 | /* per smb session structure/fields */ |
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index f20d0c8ee7ce..541738fcaebc 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h | |||
@@ -65,6 +65,7 @@ extern char *cifs_compose_mount_options(const char *sb_mountdata, | |||
65 | extern struct mid_q_entry *AllocMidQEntry(const struct smb_hdr *smb_buffer, | 65 | extern struct mid_q_entry *AllocMidQEntry(const struct smb_hdr *smb_buffer, |
66 | struct TCP_Server_Info *server); | 66 | struct TCP_Server_Info *server); |
67 | extern void DeleteMidQEntry(struct mid_q_entry *midEntry); | 67 | extern void DeleteMidQEntry(struct mid_q_entry *midEntry); |
68 | extern void cifs_delete_mid(struct mid_q_entry *mid); | ||
68 | extern void cifs_wake_up_task(struct mid_q_entry *mid); | 69 | extern void cifs_wake_up_task(struct mid_q_entry *mid); |
69 | extern int cifs_call_async(struct TCP_Server_Info *server, struct kvec *iov, | 70 | extern int cifs_call_async(struct TCP_Server_Info *server, struct kvec *iov, |
70 | unsigned int nvec, mid_receive_t *receive, | 71 | unsigned int nvec, mid_receive_t *receive, |
diff --git a/fs/cifs/smb2glob.h b/fs/cifs/smb2glob.h index 11505d73ff32..8635574ea8b6 100644 --- a/fs/cifs/smb2glob.h +++ b/fs/cifs/smb2glob.h | |||
@@ -47,4 +47,8 @@ | |||
47 | #define END_OF_CHAIN 4 | 47 | #define END_OF_CHAIN 4 |
48 | #define RELATED_REQUEST 8 | 48 | #define RELATED_REQUEST 8 |
49 | 49 | ||
50 | #define SMB2_SIGNATURE_SIZE (16) | ||
51 | #define SMB2_NTLMV2_SESSKEY_SIZE (16) | ||
52 | #define SMB2_HMACSHA256_SIZE (32) | ||
53 | |||
50 | #endif /* _SMB2_GLOB_H */ | 54 | #endif /* _SMB2_GLOB_H */ |
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index 00dc45a7881c..30c92c847fe8 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c | |||
@@ -118,9 +118,9 @@ smb2_hdr_assemble(struct smb2_hdr *hdr, __le16 smb2_cmd /* command */ , | |||
118 | /* BB how does SMB2 do case sensitive? */ | 118 | /* BB how does SMB2 do case sensitive? */ |
119 | /* if (tcon->nocase) | 119 | /* if (tcon->nocase) |
120 | hdr->Flags |= SMBFLG_CASELESS; */ | 120 | hdr->Flags |= SMBFLG_CASELESS; */ |
121 | /* if (tcon->ses && tcon->ses->server && | 121 | if (tcon->ses && tcon->ses->server && |
122 | (tcon->ses->server->sec_mode & SECMODE_SIGN_REQUIRED)) | 122 | (tcon->ses->server->sec_mode & SECMODE_SIGN_REQUIRED)) |
123 | hdr->Flags |= SMB2_FLAGS_SIGNED; */ | 123 | hdr->Flags |= SMB2_FLAGS_SIGNED; |
124 | out: | 124 | out: |
125 | pdu->StructureSize2 = cpu_to_le16(parmsize); | 125 | pdu->StructureSize2 = cpu_to_le16(parmsize); |
126 | return; | 126 | return; |
@@ -441,6 +441,38 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses) | |||
441 | rc = -EIO; | 441 | rc = -EIO; |
442 | goto neg_exit; | 442 | goto neg_exit; |
443 | } | 443 | } |
444 | |||
445 | cFYI(1, "sec_flags 0x%x", sec_flags); | ||
446 | if (sec_flags & CIFSSEC_MUST_SIGN) { | ||
447 | cFYI(1, "Signing required"); | ||
448 | if (!(server->sec_mode & (SMB2_NEGOTIATE_SIGNING_REQUIRED | | ||
449 | SMB2_NEGOTIATE_SIGNING_ENABLED))) { | ||
450 | cERROR(1, "signing required but server lacks support"); | ||
451 | rc = -EOPNOTSUPP; | ||
452 | goto neg_exit; | ||
453 | } | ||
454 | server->sec_mode |= SECMODE_SIGN_REQUIRED; | ||
455 | } else if (sec_flags & CIFSSEC_MAY_SIGN) { | ||
456 | cFYI(1, "Signing optional"); | ||
457 | if (server->sec_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED) { | ||
458 | cFYI(1, "Server requires signing"); | ||
459 | server->sec_mode |= SECMODE_SIGN_REQUIRED; | ||
460 | } else { | ||
461 | server->sec_mode &= | ||
462 | ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED); | ||
463 | } | ||
464 | } else { | ||
465 | cFYI(1, "Signing disabled"); | ||
466 | if (server->sec_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED) { | ||
467 | cERROR(1, "Server requires packet signing to be enabled" | ||
468 | " in /proc/fs/cifs/SecurityFlags."); | ||
469 | rc = -EOPNOTSUPP; | ||
470 | goto neg_exit; | ||
471 | } | ||
472 | server->sec_mode &= | ||
473 | ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED); | ||
474 | } | ||
475 | |||
444 | #ifdef CONFIG_SMB2_ASN1 /* BB REMOVEME when updated asn1.c ready */ | 476 | #ifdef CONFIG_SMB2_ASN1 /* BB REMOVEME when updated asn1.c ready */ |
445 | rc = decode_neg_token_init(security_blob, blob_length, | 477 | rc = decode_neg_token_init(security_blob, blob_length, |
446 | &server->sec_type); | 478 | &server->sec_type); |
@@ -669,6 +701,8 @@ SMB2_logoff(const unsigned int xid, struct cifs_ses *ses) | |||
669 | 701 | ||
670 | /* since no tcon, smb2_init can not do this, so do here */ | 702 | /* since no tcon, smb2_init can not do this, so do here */ |
671 | req->hdr.SessionId = ses->Suid; | 703 | req->hdr.SessionId = ses->Suid; |
704 | if (server->sec_mode & SECMODE_SIGN_REQUIRED) | ||
705 | req->hdr.Flags |= SMB2_FLAGS_SIGNED; | ||
672 | 706 | ||
673 | rc = SendReceiveNoRsp(xid, ses, (char *) &req->hdr, 0); | 707 | rc = SendReceiveNoRsp(xid, ses, (char *) &req->hdr, 0); |
674 | /* | 708 | /* |
@@ -1268,10 +1302,16 @@ smb2_readv_callback(struct mid_q_entry *mid) | |||
1268 | case MID_RESPONSE_RECEIVED: | 1302 | case MID_RESPONSE_RECEIVED: |
1269 | credits_received = le16_to_cpu(buf->CreditRequest); | 1303 | credits_received = le16_to_cpu(buf->CreditRequest); |
1270 | /* result already set, check signature */ | 1304 | /* result already set, check signature */ |
1271 | /* if (server->sec_mode & | 1305 | if (server->sec_mode & |
1272 | (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) | 1306 | (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) { |
1273 | if (smb2_verify_signature(mid->resp_buf, server)) | 1307 | int rc; |
1274 | cERROR(1, "Unexpected SMB signature"); */ | 1308 | |
1309 | rc = smb2_verify_signature2(rdata->iov, rdata->nr_iov, | ||
1310 | server); | ||
1311 | if (rc) | ||
1312 | cERROR(1, "SMB signature verification returned " | ||
1313 | "error = %d", rc); | ||
1314 | } | ||
1275 | /* FIXME: should this be counted toward the initiating task? */ | 1315 | /* FIXME: should this be counted toward the initiating task? */ |
1276 | task_io_account_read(rdata->bytes); | 1316 | task_io_account_read(rdata->bytes); |
1277 | cifs_stats_bytes_read(tcon, rdata->bytes); | 1317 | cifs_stats_bytes_read(tcon, rdata->bytes); |
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h index 192d0c7d91eb..dbbdc39fa209 100644 --- a/fs/cifs/smb2proto.h +++ b/fs/cifs/smb2proto.h | |||
@@ -39,6 +39,8 @@ extern char *smb2_get_data_area_len(int *off, int *len, struct smb2_hdr *hdr); | |||
39 | extern __le16 *cifs_convert_path_to_utf16(const char *from, | 39 | extern __le16 *cifs_convert_path_to_utf16(const char *from, |
40 | struct cifs_sb_info *cifs_sb); | 40 | struct cifs_sb_info *cifs_sb); |
41 | 41 | ||
42 | extern int smb2_verify_signature2(struct kvec *, unsigned int, | ||
43 | struct TCP_Server_Info *); | ||
42 | extern int smb2_check_receive(struct mid_q_entry *mid, | 44 | extern int smb2_check_receive(struct mid_q_entry *mid, |
43 | struct TCP_Server_Info *server, bool log_error); | 45 | struct TCP_Server_Info *server, bool log_error); |
44 | extern int smb2_setup_request(struct cifs_ses *ses, struct kvec *iov, | 46 | extern int smb2_setup_request(struct cifs_ses *ses, struct kvec *iov, |
diff --git a/fs/cifs/smb2transport.c b/fs/cifs/smb2transport.c index 31f5d420b3ea..66479f252ae5 100644 --- a/fs/cifs/smb2transport.c +++ b/fs/cifs/smb2transport.c | |||
@@ -36,6 +36,149 @@ | |||
36 | #include "smb2proto.h" | 36 | #include "smb2proto.h" |
37 | #include "cifs_debug.h" | 37 | #include "cifs_debug.h" |
38 | #include "smb2status.h" | 38 | #include "smb2status.h" |
39 | #include "smb2glob.h" | ||
40 | |||
41 | static int | ||
42 | smb2_calc_signature2(const struct kvec *iov, int n_vec, | ||
43 | struct TCP_Server_Info *server) | ||
44 | { | ||
45 | int i, rc; | ||
46 | unsigned char smb2_signature[SMB2_HMACSHA256_SIZE]; | ||
47 | unsigned char *sigptr = smb2_signature; | ||
48 | struct smb2_hdr *smb2_pdu = (struct smb2_hdr *)iov[0].iov_base; | ||
49 | |||
50 | memset(smb2_signature, 0x0, SMB2_HMACSHA256_SIZE); | ||
51 | memset(smb2_pdu->Signature, 0x0, SMB2_SIGNATURE_SIZE); | ||
52 | |||
53 | rc = crypto_shash_setkey(server->secmech.hmacsha256, | ||
54 | server->session_key.response, SMB2_NTLMV2_SESSKEY_SIZE); | ||
55 | if (rc) { | ||
56 | cERROR(1, "%s: Could not update with response\n", __func__); | ||
57 | return rc; | ||
58 | } | ||
59 | |||
60 | rc = crypto_shash_init(&server->secmech.sdeschmacsha256->shash); | ||
61 | if (rc) { | ||
62 | cERROR(1, "%s: Could not init md5\n", __func__); | ||
63 | return rc; | ||
64 | } | ||
65 | |||
66 | for (i = 0; i < n_vec; i++) { | ||
67 | if (iov[i].iov_len == 0) | ||
68 | continue; | ||
69 | if (iov[i].iov_base == NULL) { | ||
70 | cERROR(1, "null iovec entry"); | ||
71 | return -EIO; | ||
72 | } | ||
73 | /* | ||
74 | * The first entry includes a length field (which does not get | ||
75 | * signed that occupies the first 4 bytes before the header). | ||
76 | */ | ||
77 | if (i == 0) { | ||
78 | if (iov[0].iov_len <= 8) /* cmd field at offset 9 */ | ||
79 | break; /* nothing to sign or corrupt header */ | ||
80 | rc = | ||
81 | crypto_shash_update( | ||
82 | &server->secmech.sdeschmacsha256->shash, | ||
83 | iov[i].iov_base + 4, iov[i].iov_len - 4); | ||
84 | } else { | ||
85 | rc = | ||
86 | crypto_shash_update( | ||
87 | &server->secmech.sdeschmacsha256->shash, | ||
88 | iov[i].iov_base, iov[i].iov_len); | ||
89 | } | ||
90 | if (rc) { | ||
91 | cERROR(1, "%s: Could not update with payload\n", | ||
92 | __func__); | ||
93 | return rc; | ||
94 | } | ||
95 | } | ||
96 | |||
97 | rc = crypto_shash_final(&server->secmech.sdeschmacsha256->shash, | ||
98 | sigptr); | ||
99 | if (rc) | ||
100 | cERROR(1, "%s: Could not generate sha256 hash\n", __func__); | ||
101 | |||
102 | memcpy(smb2_pdu->Signature, sigptr, SMB2_SIGNATURE_SIZE); | ||
103 | |||
104 | return rc; | ||
105 | } | ||
106 | |||
107 | /* must be called with server->srv_mutex held */ | ||
108 | static int | ||
109 | smb2_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *server) | ||
110 | { | ||
111 | int rc = 0; | ||
112 | struct smb2_hdr *smb2_pdu = iov[0].iov_base; | ||
113 | |||
114 | if (!(smb2_pdu->Flags & SMB2_FLAGS_SIGNED) || | ||
115 | server->tcpStatus == CifsNeedNegotiate) | ||
116 | return rc; | ||
117 | |||
118 | if (!server->session_estab) { | ||
119 | strncpy(smb2_pdu->Signature, "BSRSPYL", 8); | ||
120 | return rc; | ||
121 | } | ||
122 | |||
123 | rc = smb2_calc_signature2(iov, n_vec, server); | ||
124 | |||
125 | return rc; | ||
126 | } | ||
127 | |||
128 | int | ||
129 | smb2_verify_signature2(struct kvec *iov, unsigned int n_vec, | ||
130 | struct TCP_Server_Info *server) | ||
131 | { | ||
132 | unsigned int rc; | ||
133 | char server_response_sig[16]; | ||
134 | struct smb2_hdr *smb2_pdu = (struct smb2_hdr *)iov[0].iov_base; | ||
135 | |||
136 | if ((smb2_pdu->Command == SMB2_NEGOTIATE) || | ||
137 | (smb2_pdu->Command == SMB2_OPLOCK_BREAK) || | ||
138 | (!server->session_estab)) | ||
139 | return 0; | ||
140 | |||
141 | /* | ||
142 | * BB what if signatures are supposed to be on for session but | ||
143 | * server does not send one? BB | ||
144 | */ | ||
145 | |||
146 | /* Do not need to verify session setups with signature "BSRSPYL " */ | ||
147 | if (memcmp(smb2_pdu->Signature, "BSRSPYL ", 8) == 0) | ||
148 | cFYI(1, "dummy signature received for smb command 0x%x", | ||
149 | smb2_pdu->Command); | ||
150 | |||
151 | /* | ||
152 | * Save off the origiginal signature so we can modify the smb and check | ||
153 | * our calculated signature against what the server sent. | ||
154 | */ | ||
155 | memcpy(server_response_sig, smb2_pdu->Signature, SMB2_SIGNATURE_SIZE); | ||
156 | |||
157 | memset(smb2_pdu->Signature, 0, SMB2_SIGNATURE_SIZE); | ||
158 | |||
159 | mutex_lock(&server->srv_mutex); | ||
160 | rc = smb2_calc_signature2(iov, n_vec, server); | ||
161 | mutex_unlock(&server->srv_mutex); | ||
162 | |||
163 | if (rc) | ||
164 | return rc; | ||
165 | |||
166 | if (memcmp(server_response_sig, smb2_pdu->Signature, | ||
167 | SMB2_SIGNATURE_SIZE)) | ||
168 | return -EACCES; | ||
169 | else | ||
170 | return 0; | ||
171 | } | ||
172 | |||
173 | static int | ||
174 | smb2_verify_signature(struct smb2_hdr *smb2_pdu, struct TCP_Server_Info *server) | ||
175 | { | ||
176 | struct kvec iov; | ||
177 | |||
178 | iov.iov_base = (char *)smb2_pdu; | ||
179 | iov.iov_len = get_rfc1002_length(smb2_pdu) + 4; | ||
180 | return smb2_verify_signature2(&iov, 1, server); | ||
181 | } | ||
39 | 182 | ||
40 | /* | 183 | /* |
41 | * Set message id for the request. Should be called after wait_for_free_request | 184 | * Set message id for the request. Should be called after wait_for_free_request |
@@ -118,12 +261,15 @@ smb2_check_receive(struct mid_q_entry *mid, struct TCP_Server_Info *server, | |||
118 | 261 | ||
119 | dump_smb(mid->resp_buf, min_t(u32, 80, len)); | 262 | dump_smb(mid->resp_buf, min_t(u32, 80, len)); |
120 | /* convert the length into a more usable form */ | 263 | /* convert the length into a more usable form */ |
121 | /* BB - uncomment with SMB2 signing implementation */ | 264 | if ((len > 24) && |
122 | /* if ((len > 24) && | ||
123 | (server->sec_mode & (SECMODE_SIGN_REQUIRED|SECMODE_SIGN_ENABLED))) { | 265 | (server->sec_mode & (SECMODE_SIGN_REQUIRED|SECMODE_SIGN_ENABLED))) { |
124 | if (smb2_verify_signature(mid->resp_buf, server)) | 266 | int rc; |
125 | cERROR(1, "Unexpected SMB signature"); | 267 | |
126 | } */ | 268 | rc = smb2_verify_signature(mid->resp_buf, server); |
269 | if (rc) | ||
270 | cERROR(1, "SMB signature verification returned error = " | ||
271 | "%d", rc); | ||
272 | } | ||
127 | 273 | ||
128 | return map_smb2_to_linux_error(mid->resp_buf, log_error); | 274 | return map_smb2_to_linux_error(mid->resp_buf, log_error); |
129 | } | 275 | } |
@@ -141,9 +287,9 @@ smb2_setup_request(struct cifs_ses *ses, struct kvec *iov, | |||
141 | rc = smb2_get_mid_entry(ses, hdr, &mid); | 287 | rc = smb2_get_mid_entry(ses, hdr, &mid); |
142 | if (rc) | 288 | if (rc) |
143 | return rc; | 289 | return rc; |
144 | /* rc = smb2_sign_smb2(iov, nvec, ses->server); | 290 | rc = smb2_sign_smb2(iov, nvec, ses->server); |
145 | if (rc) | 291 | if (rc) |
146 | delete_mid(mid); */ | 292 | cifs_delete_mid(mid); |
147 | *ret_mid = mid; | 293 | *ret_mid = mid; |
148 | return rc; | 294 | return rc; |
149 | } | 295 | } |
@@ -162,11 +308,12 @@ smb2_setup_async_request(struct TCP_Server_Info *server, struct kvec *iov, | |||
162 | if (mid == NULL) | 308 | if (mid == NULL) |
163 | return -ENOMEM; | 309 | return -ENOMEM; |
164 | 310 | ||
165 | /* rc = smb2_sign_smb2(iov, nvec, server); | 311 | rc = smb2_sign_smb2(iov, nvec, server); |
166 | if (rc) { | 312 | if (rc) { |
167 | DeleteMidQEntry(mid); | 313 | DeleteMidQEntry(mid); |
168 | return rc; | 314 | return rc; |
169 | }*/ | 315 | } |
316 | |||
170 | *ret_mid = mid; | 317 | *ret_mid = mid; |
171 | return rc; | 318 | return rc; |
172 | } | 319 | } |
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index d9b639b95fa8..c4d7825dfc0a 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c | |||
@@ -109,8 +109,8 @@ DeleteMidQEntry(struct mid_q_entry *midEntry) | |||
109 | mempool_free(midEntry, cifs_mid_poolp); | 109 | mempool_free(midEntry, cifs_mid_poolp); |
110 | } | 110 | } |
111 | 111 | ||
112 | static void | 112 | void |
113 | delete_mid(struct mid_q_entry *mid) | 113 | cifs_delete_mid(struct mid_q_entry *mid) |
114 | { | 114 | { |
115 | spin_lock(&GlobalMid_Lock); | 115 | spin_lock(&GlobalMid_Lock); |
116 | list_del(&mid->qhead); | 116 | list_del(&mid->qhead); |
@@ -419,7 +419,7 @@ cifs_call_async(struct TCP_Server_Info *server, struct kvec *iov, | |||
419 | if (rc == 0) | 419 | if (rc == 0) |
420 | return 0; | 420 | return 0; |
421 | 421 | ||
422 | delete_mid(mid); | 422 | cifs_delete_mid(mid); |
423 | add_credits(server, 1, optype); | 423 | add_credits(server, 1, optype); |
424 | wake_up(&server->request_q); | 424 | wake_up(&server->request_q); |
425 | return rc; | 425 | return rc; |
@@ -532,7 +532,7 @@ cifs_setup_request(struct cifs_ses *ses, struct kvec *iov, | |||
532 | return rc; | 532 | return rc; |
533 | rc = cifs_sign_smbv(iov, nvec, ses->server, &mid->sequence_number); | 533 | rc = cifs_sign_smbv(iov, nvec, ses->server, &mid->sequence_number); |
534 | if (rc) | 534 | if (rc) |
535 | delete_mid(mid); | 535 | cifs_delete_mid(mid); |
536 | *ret_mid = mid; | 536 | *ret_mid = mid; |
537 | return rc; | 537 | return rc; |
538 | } | 538 | } |
@@ -652,11 +652,11 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses, | |||
652 | rc = ses->server->ops->check_receive(midQ, ses->server, | 652 | rc = ses->server->ops->check_receive(midQ, ses->server, |
653 | flags & CIFS_LOG_ERROR); | 653 | flags & CIFS_LOG_ERROR); |
654 | 654 | ||
655 | /* mark it so buf will not be freed by delete_mid */ | 655 | /* mark it so buf will not be freed by cifs_delete_mid */ |
656 | if ((flags & CIFS_NO_RESP) == 0) | 656 | if ((flags & CIFS_NO_RESP) == 0) |
657 | midQ->resp_buf = NULL; | 657 | midQ->resp_buf = NULL; |
658 | out: | 658 | out: |
659 | delete_mid(midQ); | 659 | cifs_delete_mid(midQ); |
660 | add_credits(ses->server, credits, optype); | 660 | add_credits(ses->server, credits, optype); |
661 | 661 | ||
662 | return rc; | 662 | return rc; |
@@ -762,7 +762,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses, | |||
762 | memcpy(out_buf, midQ->resp_buf, *pbytes_returned + 4); | 762 | memcpy(out_buf, midQ->resp_buf, *pbytes_returned + 4); |
763 | rc = cifs_check_receive(midQ, ses->server, 0); | 763 | rc = cifs_check_receive(midQ, ses->server, 0); |
764 | out: | 764 | out: |
765 | delete_mid(midQ); | 765 | cifs_delete_mid(midQ); |
766 | add_credits(ses->server, 1, 0); | 766 | add_credits(ses->server, 1, 0); |
767 | 767 | ||
768 | return rc; | 768 | return rc; |
@@ -846,7 +846,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon, | |||
846 | 846 | ||
847 | rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number); | 847 | rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number); |
848 | if (rc) { | 848 | if (rc) { |
849 | delete_mid(midQ); | 849 | cifs_delete_mid(midQ); |
850 | mutex_unlock(&ses->server->srv_mutex); | 850 | mutex_unlock(&ses->server->srv_mutex); |
851 | return rc; | 851 | return rc; |
852 | } | 852 | } |
@@ -859,7 +859,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon, | |||
859 | mutex_unlock(&ses->server->srv_mutex); | 859 | mutex_unlock(&ses->server->srv_mutex); |
860 | 860 | ||
861 | if (rc < 0) { | 861 | if (rc < 0) { |
862 | delete_mid(midQ); | 862 | cifs_delete_mid(midQ); |
863 | return rc; | 863 | return rc; |
864 | } | 864 | } |
865 | 865 | ||
@@ -880,7 +880,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon, | |||
880 | blocking lock to return. */ | 880 | blocking lock to return. */ |
881 | rc = send_cancel(ses->server, in_buf, midQ); | 881 | rc = send_cancel(ses->server, in_buf, midQ); |
882 | if (rc) { | 882 | if (rc) { |
883 | delete_mid(midQ); | 883 | cifs_delete_mid(midQ); |
884 | return rc; | 884 | return rc; |
885 | } | 885 | } |
886 | } else { | 886 | } else { |
@@ -892,7 +892,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon, | |||
892 | /* If we get -ENOLCK back the lock may have | 892 | /* If we get -ENOLCK back the lock may have |
893 | already been removed. Don't exit in this case. */ | 893 | already been removed. Don't exit in this case. */ |
894 | if (rc && rc != -ENOLCK) { | 894 | if (rc && rc != -ENOLCK) { |
895 | delete_mid(midQ); | 895 | cifs_delete_mid(midQ); |
896 | return rc; | 896 | return rc; |
897 | } | 897 | } |
898 | } | 898 | } |
@@ -929,7 +929,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon, | |||
929 | memcpy(out_buf, midQ->resp_buf, *pbytes_returned + 4); | 929 | memcpy(out_buf, midQ->resp_buf, *pbytes_returned + 4); |
930 | rc = cifs_check_receive(midQ, ses->server, 0); | 930 | rc = cifs_check_receive(midQ, ses->server, 0); |
931 | out: | 931 | out: |
932 | delete_mid(midQ); | 932 | cifs_delete_mid(midQ); |
933 | if (rstart && rc == -EACCES) | 933 | if (rstart && rc == -EACCES) |
934 | return -ERESTARTSYS; | 934 | return -ERESTARTSYS; |
935 | return rc; | 935 | return rc; |