diff options
| -rw-r--r-- | fs/cifs/cifsglob.h | 8 | ||||
| -rw-r--r-- | fs/cifs/cifsproto.h | 5 | ||||
| -rw-r--r-- | fs/cifs/connect.c | 2 | ||||
| -rw-r--r-- | fs/cifs/misc.c | 2 | ||||
| -rw-r--r-- | fs/cifs/smb2misc.c | 36 | ||||
| -rw-r--r-- | fs/cifs/smb2ops.c | 13 | ||||
| -rw-r--r-- | fs/cifs/smb2pdu.c | 10 | ||||
| -rw-r--r-- | fs/cifs/smb2pdu.h | 8 | ||||
| -rw-r--r-- | fs/cifs/smb2proto.h | 3 | ||||
| -rw-r--r-- | fs/cifs/smb2transport.c | 102 |
10 files changed, 156 insertions, 33 deletions
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 9d14926531ba..a25b2513f146 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h | |||
| @@ -227,7 +227,7 @@ struct smb_version_operations { | |||
| 227 | void (*print_stats)(struct seq_file *m, struct cifs_tcon *); | 227 | void (*print_stats)(struct seq_file *m, struct cifs_tcon *); |
| 228 | void (*dump_share_caps)(struct seq_file *, struct cifs_tcon *); | 228 | void (*dump_share_caps)(struct seq_file *, struct cifs_tcon *); |
| 229 | /* verify the message */ | 229 | /* verify the message */ |
| 230 | int (*check_message)(char *, unsigned int); | 230 | int (*check_message)(char *, unsigned int, struct TCP_Server_Info *); |
| 231 | bool (*is_oplock_break)(char *, struct TCP_Server_Info *); | 231 | bool (*is_oplock_break)(char *, struct TCP_Server_Info *); |
| 232 | void (*downgrade_oplock)(struct TCP_Server_Info *, | 232 | void (*downgrade_oplock)(struct TCP_Server_Info *, |
| 233 | struct cifsInodeInfo *, bool); | 233 | struct cifsInodeInfo *, bool); |
| @@ -630,6 +630,7 @@ struct TCP_Server_Info { | |||
| 630 | #ifdef CONFIG_CIFS_SMB2 | 630 | #ifdef CONFIG_CIFS_SMB2 |
| 631 | unsigned int max_read; | 631 | unsigned int max_read; |
| 632 | unsigned int max_write; | 632 | unsigned int max_write; |
| 633 | __u8 preauth_hash[512]; | ||
| 633 | #endif /* CONFIG_CIFS_SMB2 */ | 634 | #endif /* CONFIG_CIFS_SMB2 */ |
| 634 | unsigned long echo_interval; | 635 | unsigned long echo_interval; |
| 635 | }; | 636 | }; |
| @@ -813,7 +814,10 @@ struct cifs_ses { | |||
| 813 | bool need_reconnect:1; /* connection reset, uid now invalid */ | 814 | bool need_reconnect:1; /* connection reset, uid now invalid */ |
| 814 | #ifdef CONFIG_CIFS_SMB2 | 815 | #ifdef CONFIG_CIFS_SMB2 |
| 815 | __u16 session_flags; | 816 | __u16 session_flags; |
| 816 | char smb3signingkey[SMB3_SIGN_KEY_SIZE]; /* for signing smb3 packets */ | 817 | __u8 smb3signingkey[SMB3_SIGN_KEY_SIZE]; |
| 818 | __u8 smb3encryptionkey[SMB3_SIGN_KEY_SIZE]; | ||
| 819 | __u8 smb3decryptionkey[SMB3_SIGN_KEY_SIZE]; | ||
| 820 | __u8 preauth_hash[512]; | ||
| 817 | #endif /* CONFIG_CIFS_SMB2 */ | 821 | #endif /* CONFIG_CIFS_SMB2 */ |
| 818 | }; | 822 | }; |
| 819 | 823 | ||
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index c63fd1dde25b..eed7ff50faf0 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h | |||
| @@ -102,7 +102,7 @@ extern int SendReceiveBlockingLock(const unsigned int xid, | |||
| 102 | struct smb_hdr *out_buf, | 102 | struct smb_hdr *out_buf, |
| 103 | int *bytes_returned); | 103 | int *bytes_returned); |
| 104 | extern int cifs_reconnect(struct TCP_Server_Info *server); | 104 | extern int cifs_reconnect(struct TCP_Server_Info *server); |
| 105 | extern int checkSMB(char *buf, unsigned int length); | 105 | extern int checkSMB(char *buf, unsigned int len, struct TCP_Server_Info *srvr); |
| 106 | extern bool is_valid_oplock_break(char *, struct TCP_Server_Info *); | 106 | extern bool is_valid_oplock_break(char *, struct TCP_Server_Info *); |
| 107 | extern bool backup_cred(struct cifs_sb_info *); | 107 | extern bool backup_cred(struct cifs_sb_info *); |
| 108 | extern bool is_size_safe_to_change(struct cifsInodeInfo *, __u64 eof); | 108 | extern bool is_size_safe_to_change(struct cifsInodeInfo *, __u64 eof); |
| @@ -439,7 +439,8 @@ extern int setup_ntlm_response(struct cifs_ses *, const struct nls_table *); | |||
| 439 | extern int setup_ntlmv2_rsp(struct cifs_ses *, const struct nls_table *); | 439 | extern int setup_ntlmv2_rsp(struct cifs_ses *, const struct nls_table *); |
| 440 | extern void cifs_crypto_shash_release(struct TCP_Server_Info *); | 440 | extern void cifs_crypto_shash_release(struct TCP_Server_Info *); |
| 441 | extern int calc_seckey(struct cifs_ses *); | 441 | extern int calc_seckey(struct cifs_ses *); |
| 442 | extern int generate_smb3signingkey(struct cifs_ses *); | 442 | extern int generate_smb30signingkey(struct cifs_ses *); |
| 443 | extern int generate_smb311signingkey(struct cifs_ses *); | ||
| 443 | 444 | ||
| 444 | #ifdef CONFIG_CIFS_WEAK_PW_HASH | 445 | #ifdef CONFIG_CIFS_WEAK_PW_HASH |
| 445 | extern int calc_lanman_hash(const char *password, const char *cryptkey, | 446 | extern int calc_lanman_hash(const char *password, const char *cryptkey, |
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index de53c5558fe3..6ab9e83b899e 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c | |||
| @@ -831,7 +831,7 @@ standard_receive3(struct TCP_Server_Info *server, struct mid_q_entry *mid) | |||
| 831 | * 48 bytes is enough to display the header and a little bit | 831 | * 48 bytes is enough to display the header and a little bit |
| 832 | * into the payload for debugging purposes. | 832 | * into the payload for debugging purposes. |
| 833 | */ | 833 | */ |
| 834 | length = server->ops->check_message(buf, server->total_read); | 834 | length = server->ops->check_message(buf, server->total_read, server); |
| 835 | if (length != 0) | 835 | if (length != 0) |
| 836 | cifs_dump_mem("Bad SMB: ", buf, | 836 | cifs_dump_mem("Bad SMB: ", buf, |
| 837 | min_t(unsigned int, server->total_read, 48)); | 837 | min_t(unsigned int, server->total_read, 48)); |
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index 8442b8b8e0be..813fe13c2ae1 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c | |||
| @@ -310,7 +310,7 @@ check_smb_hdr(struct smb_hdr *smb) | |||
| 310 | } | 310 | } |
| 311 | 311 | ||
| 312 | int | 312 | int |
| 313 | checkSMB(char *buf, unsigned int total_read) | 313 | checkSMB(char *buf, unsigned int total_read, struct TCP_Server_Info *server) |
| 314 | { | 314 | { |
| 315 | struct smb_hdr *smb = (struct smb_hdr *)buf; | 315 | struct smb_hdr *smb = (struct smb_hdr *)buf; |
| 316 | __u32 rfclen = be32_to_cpu(smb->smb_buf_length); | 316 | __u32 rfclen = be32_to_cpu(smb->smb_buf_length); |
diff --git a/fs/cifs/smb2misc.c b/fs/cifs/smb2misc.c index 1c5907019045..389fb9f8c84e 100644 --- a/fs/cifs/smb2misc.c +++ b/fs/cifs/smb2misc.c | |||
| @@ -38,7 +38,7 @@ check_smb2_hdr(struct smb2_hdr *hdr, __u64 mid) | |||
| 38 | * Make sure that this really is an SMB, that it is a response, | 38 | * Make sure that this really is an SMB, that it is a response, |
| 39 | * and that the message ids match. | 39 | * and that the message ids match. |
| 40 | */ | 40 | */ |
| 41 | if ((*(__le32 *)hdr->ProtocolId == SMB2_PROTO_NUMBER) && | 41 | if ((hdr->ProtocolId == SMB2_PROTO_NUMBER) && |
| 42 | (mid == wire_mid)) { | 42 | (mid == wire_mid)) { |
| 43 | if (hdr->Flags & SMB2_FLAGS_SERVER_TO_REDIR) | 43 | if (hdr->Flags & SMB2_FLAGS_SERVER_TO_REDIR) |
| 44 | return 0; | 44 | return 0; |
| @@ -50,9 +50,9 @@ check_smb2_hdr(struct smb2_hdr *hdr, __u64 mid) | |||
| 50 | cifs_dbg(VFS, "Received Request not response\n"); | 50 | cifs_dbg(VFS, "Received Request not response\n"); |
| 51 | } | 51 | } |
| 52 | } else { /* bad signature or mid */ | 52 | } else { /* bad signature or mid */ |
| 53 | if (*(__le32 *)hdr->ProtocolId != SMB2_PROTO_NUMBER) | 53 | if (hdr->ProtocolId != SMB2_PROTO_NUMBER) |
| 54 | cifs_dbg(VFS, "Bad protocol string signature header %x\n", | 54 | cifs_dbg(VFS, "Bad protocol string signature header %x\n", |
| 55 | *(unsigned int *) hdr->ProtocolId); | 55 | le32_to_cpu(hdr->ProtocolId)); |
| 56 | if (mid != wire_mid) | 56 | if (mid != wire_mid) |
| 57 | cifs_dbg(VFS, "Mids do not match: %llu and %llu\n", | 57 | cifs_dbg(VFS, "Mids do not match: %llu and %llu\n", |
| 58 | mid, wire_mid); | 58 | mid, wire_mid); |
| @@ -93,11 +93,11 @@ static const __le16 smb2_rsp_struct_sizes[NUMBER_OF_SMB2_COMMANDS] = { | |||
| 93 | }; | 93 | }; |
| 94 | 94 | ||
| 95 | int | 95 | int |
| 96 | smb2_check_message(char *buf, unsigned int length) | 96 | smb2_check_message(char *buf, unsigned int length, struct TCP_Server_Info *srvr) |
| 97 | { | 97 | { |
| 98 | struct smb2_hdr *hdr = (struct smb2_hdr *)buf; | 98 | struct smb2_hdr *hdr = (struct smb2_hdr *)buf; |
| 99 | struct smb2_pdu *pdu = (struct smb2_pdu *)hdr; | 99 | struct smb2_pdu *pdu = (struct smb2_pdu *)hdr; |
| 100 | __u64 mid = le64_to_cpu(hdr->MessageId); | 100 | __u64 mid; |
| 101 | __u32 len = get_rfc1002_length(buf); | 101 | __u32 len = get_rfc1002_length(buf); |
| 102 | __u32 clc_len; /* calculated length */ | 102 | __u32 clc_len; /* calculated length */ |
| 103 | int command; | 103 | int command; |
| @@ -111,6 +111,30 @@ smb2_check_message(char *buf, unsigned int length) | |||
| 111 | * ie Validate the wct via smb2_struct_sizes table above | 111 | * ie Validate the wct via smb2_struct_sizes table above |
| 112 | */ | 112 | */ |
| 113 | 113 | ||
| 114 | if (hdr->ProtocolId == SMB2_TRANSFORM_PROTO_NUM) { | ||
| 115 | struct smb2_transform_hdr *thdr = | ||
| 116 | (struct smb2_transform_hdr *)buf; | ||
| 117 | struct cifs_ses *ses = NULL; | ||
| 118 | struct list_head *tmp; | ||
| 119 | |||
| 120 | /* decrypt frame now that it is completely read in */ | ||
| 121 | spin_lock(&cifs_tcp_ses_lock); | ||
| 122 | list_for_each(tmp, &srvr->smb_ses_list) { | ||
| 123 | ses = list_entry(tmp, struct cifs_ses, smb_ses_list); | ||
| 124 | if (ses->Suid == thdr->SessionId) | ||
| 125 | break; | ||
| 126 | |||
| 127 | ses = NULL; | ||
| 128 | } | ||
| 129 | spin_unlock(&cifs_tcp_ses_lock); | ||
| 130 | if (ses == NULL) { | ||
| 131 | cifs_dbg(VFS, "no decryption - session id not found\n"); | ||
| 132 | return 1; | ||
| 133 | } | ||
| 134 | } | ||
| 135 | |||
| 136 | |||
| 137 | mid = le64_to_cpu(hdr->MessageId); | ||
| 114 | if (length < sizeof(struct smb2_pdu)) { | 138 | if (length < sizeof(struct smb2_pdu)) { |
| 115 | if ((length >= sizeof(struct smb2_hdr)) && (hdr->Status != 0)) { | 139 | if ((length >= sizeof(struct smb2_hdr)) && (hdr->Status != 0)) { |
| 116 | pdu->StructureSize2 = 0; | 140 | pdu->StructureSize2 = 0; |
| @@ -322,7 +346,7 @@ smb2_get_data_area_len(int *off, int *len, struct smb2_hdr *hdr) | |||
| 322 | 346 | ||
| 323 | /* return pointer to beginning of data area, ie offset from SMB start */ | 347 | /* return pointer to beginning of data area, ie offset from SMB start */ |
| 324 | if ((*off != 0) && (*len != 0)) | 348 | if ((*off != 0) && (*len != 0)) |
| 325 | return (char *)(&hdr->ProtocolId[0]) + *off; | 349 | return (char *)(&hdr->ProtocolId) + *off; |
| 326 | else | 350 | else |
| 327 | return NULL; | 351 | return NULL; |
| 328 | } | 352 | } |
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index 53ccdde6ff18..3525ed756173 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c | |||
| @@ -182,6 +182,11 @@ smb2_find_mid(struct TCP_Server_Info *server, char *buf) | |||
| 182 | struct smb2_hdr *hdr = (struct smb2_hdr *)buf; | 182 | struct smb2_hdr *hdr = (struct smb2_hdr *)buf; |
| 183 | __u64 wire_mid = le64_to_cpu(hdr->MessageId); | 183 | __u64 wire_mid = le64_to_cpu(hdr->MessageId); |
| 184 | 184 | ||
| 185 | if (hdr->ProtocolId == SMB2_TRANSFORM_PROTO_NUM) { | ||
| 186 | cifs_dbg(VFS, "encrypted frame parsing not supported yet"); | ||
| 187 | return NULL; | ||
| 188 | } | ||
| 189 | |||
| 185 | spin_lock(&GlobalMid_Lock); | 190 | spin_lock(&GlobalMid_Lock); |
| 186 | list_for_each_entry(mid, &server->pending_mid_q, qhead) { | 191 | list_for_each_entry(mid, &server->pending_mid_q, qhead) { |
| 187 | if ((mid->mid == wire_mid) && | 192 | if ((mid->mid == wire_mid) && |
| @@ -1692,7 +1697,7 @@ struct smb_version_operations smb30_operations = { | |||
| 1692 | .get_lease_key = smb2_get_lease_key, | 1697 | .get_lease_key = smb2_get_lease_key, |
| 1693 | .set_lease_key = smb2_set_lease_key, | 1698 | .set_lease_key = smb2_set_lease_key, |
| 1694 | .new_lease_key = smb2_new_lease_key, | 1699 | .new_lease_key = smb2_new_lease_key, |
| 1695 | .generate_signingkey = generate_smb3signingkey, | 1700 | .generate_signingkey = generate_smb30signingkey, |
| 1696 | .calc_signature = smb3_calc_signature, | 1701 | .calc_signature = smb3_calc_signature, |
| 1697 | .set_integrity = smb3_set_integrity, | 1702 | .set_integrity = smb3_set_integrity, |
| 1698 | .is_read_op = smb21_is_read_op, | 1703 | .is_read_op = smb21_is_read_op, |
| @@ -1779,7 +1784,7 @@ struct smb_version_operations smb311_operations = { | |||
| 1779 | .get_lease_key = smb2_get_lease_key, | 1784 | .get_lease_key = smb2_get_lease_key, |
| 1780 | .set_lease_key = smb2_set_lease_key, | 1785 | .set_lease_key = smb2_set_lease_key, |
| 1781 | .new_lease_key = smb2_new_lease_key, | 1786 | .new_lease_key = smb2_new_lease_key, |
| 1782 | .generate_signingkey = generate_smb3signingkey, | 1787 | .generate_signingkey = generate_smb311signingkey, |
| 1783 | .calc_signature = smb3_calc_signature, | 1788 | .calc_signature = smb3_calc_signature, |
| 1784 | .set_integrity = smb3_set_integrity, | 1789 | .set_integrity = smb3_set_integrity, |
| 1785 | .is_read_op = smb21_is_read_op, | 1790 | .is_read_op = smb21_is_read_op, |
| @@ -1838,7 +1843,7 @@ struct smb_version_values smb21_values = { | |||
| 1838 | struct smb_version_values smb30_values = { | 1843 | struct smb_version_values smb30_values = { |
| 1839 | .version_string = SMB30_VERSION_STRING, | 1844 | .version_string = SMB30_VERSION_STRING, |
| 1840 | .protocol_id = SMB30_PROT_ID, | 1845 | .protocol_id = SMB30_PROT_ID, |
| 1841 | .req_capabilities = SMB2_GLOBAL_CAP_DFS | SMB2_GLOBAL_CAP_LEASING | SMB2_GLOBAL_CAP_LARGE_MTU | SMB2_GLOBAL_CAP_PERSISTENT_HANDLES, | 1846 | .req_capabilities = SMB2_GLOBAL_CAP_DFS | SMB2_GLOBAL_CAP_LEASING | SMB2_GLOBAL_CAP_LARGE_MTU | SMB2_GLOBAL_CAP_PERSISTENT_HANDLES | SMB2_GLOBAL_CAP_ENCRYPTION, |
| 1842 | .large_lock_type = 0, | 1847 | .large_lock_type = 0, |
| 1843 | .exclusive_lock_type = SMB2_LOCKFLAG_EXCLUSIVE_LOCK, | 1848 | .exclusive_lock_type = SMB2_LOCKFLAG_EXCLUSIVE_LOCK, |
| 1844 | .shared_lock_type = SMB2_LOCKFLAG_SHARED_LOCK, | 1849 | .shared_lock_type = SMB2_LOCKFLAG_SHARED_LOCK, |
| @@ -1858,7 +1863,7 @@ struct smb_version_values smb30_values = { | |||
| 1858 | struct smb_version_values smb302_values = { | 1863 | struct smb_version_values smb302_values = { |
| 1859 | .version_string = SMB302_VERSION_STRING, | 1864 | .version_string = SMB302_VERSION_STRING, |
| 1860 | .protocol_id = SMB302_PROT_ID, | 1865 | .protocol_id = SMB302_PROT_ID, |
| 1861 | .req_capabilities = SMB2_GLOBAL_CAP_DFS | SMB2_GLOBAL_CAP_LEASING | SMB2_GLOBAL_CAP_LARGE_MTU | SMB2_GLOBAL_CAP_PERSISTENT_HANDLES, | 1866 | .req_capabilities = SMB2_GLOBAL_CAP_DFS | SMB2_GLOBAL_CAP_LEASING | SMB2_GLOBAL_CAP_LARGE_MTU | SMB2_GLOBAL_CAP_PERSISTENT_HANDLES | SMB2_GLOBAL_CAP_ENCRYPTION, |
| 1862 | .large_lock_type = 0, | 1867 | .large_lock_type = 0, |
| 1863 | .exclusive_lock_type = SMB2_LOCKFLAG_EXCLUSIVE_LOCK, | 1868 | .exclusive_lock_type = SMB2_LOCKFLAG_EXCLUSIVE_LOCK, |
| 1864 | .shared_lock_type = SMB2_LOCKFLAG_SHARED_LOCK, | 1869 | .shared_lock_type = SMB2_LOCKFLAG_SHARED_LOCK, |
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index 767555518d40..10f8d5cf5681 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c | |||
| @@ -97,10 +97,7 @@ smb2_hdr_assemble(struct smb2_hdr *hdr, __le16 smb2_cmd /* command */ , | |||
| 97 | hdr->smb2_buf_length = cpu_to_be32(parmsize + sizeof(struct smb2_hdr) | 97 | hdr->smb2_buf_length = cpu_to_be32(parmsize + sizeof(struct smb2_hdr) |
| 98 | - 4 /* RFC 1001 length field itself not counted */); | 98 | - 4 /* RFC 1001 length field itself not counted */); |
| 99 | 99 | ||
| 100 | hdr->ProtocolId[0] = 0xFE; | 100 | hdr->ProtocolId = SMB2_PROTO_NUMBER; |
| 101 | hdr->ProtocolId[1] = 'S'; | ||
| 102 | hdr->ProtocolId[2] = 'M'; | ||
| 103 | hdr->ProtocolId[3] = 'B'; | ||
| 104 | hdr->StructureSize = cpu_to_le16(64); | 101 | hdr->StructureSize = cpu_to_le16(64); |
| 105 | hdr->Command = smb2_cmd; | 102 | hdr->Command = smb2_cmd; |
| 106 | hdr->CreditRequest = cpu_to_le16(2); /* BB make this dynamic */ | 103 | hdr->CreditRequest = cpu_to_le16(2); /* BB make this dynamic */ |
| @@ -1573,7 +1570,8 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, | |||
| 1573 | goto ioctl_exit; | 1570 | goto ioctl_exit; |
| 1574 | } | 1571 | } |
| 1575 | 1572 | ||
| 1576 | memcpy(*out_data, rsp->hdr.ProtocolId + le32_to_cpu(rsp->OutputOffset), | 1573 | memcpy(*out_data, |
| 1574 | (char *)&rsp->hdr.ProtocolId + le32_to_cpu(rsp->OutputOffset), | ||
| 1577 | *plen); | 1575 | *plen); |
| 1578 | ioctl_exit: | 1576 | ioctl_exit: |
| 1579 | free_rsp_buf(resp_buftype, rsp); | 1577 | free_rsp_buf(resp_buftype, rsp); |
| @@ -2093,7 +2091,7 @@ SMB2_read(const unsigned int xid, struct cifs_io_parms *io_parms, | |||
| 2093 | } | 2091 | } |
| 2094 | 2092 | ||
| 2095 | if (*buf) { | 2093 | if (*buf) { |
| 2096 | memcpy(*buf, (char *)rsp->hdr.ProtocolId + rsp->DataOffset, | 2094 | memcpy(*buf, (char *)&rsp->hdr.ProtocolId + rsp->DataOffset, |
| 2097 | *nbytes); | 2095 | *nbytes); |
| 2098 | free_rsp_buf(resp_buftype, iov[0].iov_base); | 2096 | free_rsp_buf(resp_buftype, iov[0].iov_base); |
| 2099 | } else if (resp_buftype != CIFS_NO_BUFFER) { | 2097 | } else if (resp_buftype != CIFS_NO_BUFFER) { |
diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h index 4af52780ec35..ff88d9feb01e 100644 --- a/fs/cifs/smb2pdu.h +++ b/fs/cifs/smb2pdu.h | |||
| @@ -86,6 +86,7 @@ | |||
| 86 | #define MAX_SMB2_HDR_SIZE 0x78 /* 4 len + 64 hdr + (2*24 wct) + 2 bct + 2 pad */ | 86 | #define MAX_SMB2_HDR_SIZE 0x78 /* 4 len + 64 hdr + (2*24 wct) + 2 bct + 2 pad */ |
| 87 | 87 | ||
| 88 | #define SMB2_PROTO_NUMBER cpu_to_le32(0x424d53fe) | 88 | #define SMB2_PROTO_NUMBER cpu_to_le32(0x424d53fe) |
| 89 | #define SMB2_TRANSFORM_PROTO_NUM cpu_to_le32(0x424d53fd) | ||
| 89 | 90 | ||
| 90 | /* | 91 | /* |
| 91 | * SMB2 Header Definition | 92 | * SMB2 Header Definition |
| @@ -102,7 +103,7 @@ struct smb2_hdr { | |||
| 102 | __be32 smb2_buf_length; /* big endian on wire */ | 103 | __be32 smb2_buf_length; /* big endian on wire */ |
| 103 | /* length is only two or three bytes - with | 104 | /* length is only two or three bytes - with |
| 104 | one or two byte type preceding it that MBZ */ | 105 | one or two byte type preceding it that MBZ */ |
| 105 | __u8 ProtocolId[4]; /* 0xFE 'S' 'M' 'B' */ | 106 | __le32 ProtocolId; /* 0xFE 'S' 'M' 'B' */ |
| 106 | __le16 StructureSize; /* 64 */ | 107 | __le16 StructureSize; /* 64 */ |
| 107 | __le16 CreditCharge; /* MBZ */ | 108 | __le16 CreditCharge; /* MBZ */ |
| 108 | __le32 Status; /* Error from server */ | 109 | __le32 Status; /* Error from server */ |
| @@ -128,11 +129,10 @@ struct smb2_transform_hdr { | |||
| 128 | one or two byte type preceding it that MBZ */ | 129 | one or two byte type preceding it that MBZ */ |
| 129 | __u8 ProtocolId[4]; /* 0xFD 'S' 'M' 'B' */ | 130 | __u8 ProtocolId[4]; /* 0xFD 'S' 'M' 'B' */ |
| 130 | __u8 Signature[16]; | 131 | __u8 Signature[16]; |
| 131 | __u8 Nonce[11]; | 132 | __u8 Nonce[16]; |
| 132 | __u8 Reserved[5]; | ||
| 133 | __le32 OriginalMessageSize; | 133 | __le32 OriginalMessageSize; |
| 134 | __u16 Reserved1; | 134 | __u16 Reserved1; |
| 135 | __le16 EncryptionAlgorithm; | 135 | __le16 Flags; /* EncryptionAlgorithm */ |
| 136 | __u64 SessionId; | 136 | __u64 SessionId; |
| 137 | } __packed; | 137 | } __packed; |
| 138 | 138 | ||
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h index 79dc650c18b2..4f07dc93608d 100644 --- a/fs/cifs/smb2proto.h +++ b/fs/cifs/smb2proto.h | |||
| @@ -34,7 +34,8 @@ struct smb_rqst; | |||
| 34 | ***************************************************************** | 34 | ***************************************************************** |
| 35 | */ | 35 | */ |
| 36 | extern int map_smb2_to_linux_error(char *buf, bool log_err); | 36 | extern int map_smb2_to_linux_error(char *buf, bool log_err); |
| 37 | extern int smb2_check_message(char *buf, unsigned int length); | 37 | extern int smb2_check_message(char *buf, unsigned int length, |
| 38 | struct TCP_Server_Info *server); | ||
| 38 | extern unsigned int smb2_calc_size(void *buf); | 39 | extern unsigned int smb2_calc_size(void *buf); |
| 39 | extern char *smb2_get_data_area_len(int *off, int *len, struct smb2_hdr *hdr); | 40 | extern char *smb2_get_data_area_len(int *off, int *len, struct smb2_hdr *hdr); |
| 40 | extern __le16 *cifs_convert_path_to_utf16(const char *from, | 41 | extern __le16 *cifs_convert_path_to_utf16(const char *from, |
diff --git a/fs/cifs/smb2transport.c b/fs/cifs/smb2transport.c index d4c5b6f109a7..8732a43b1008 100644 --- a/fs/cifs/smb2transport.c +++ b/fs/cifs/smb2transport.c | |||
| @@ -222,8 +222,8 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) | |||
| 222 | return rc; | 222 | return rc; |
| 223 | } | 223 | } |
| 224 | 224 | ||
| 225 | int | 225 | static int generate_key(struct cifs_ses *ses, struct kvec label, |
| 226 | generate_smb3signingkey(struct cifs_ses *ses) | 226 | struct kvec context, __u8 *key, unsigned int key_size) |
| 227 | { | 227 | { |
| 228 | unsigned char zero = 0x0; | 228 | unsigned char zero = 0x0; |
| 229 | __u8 i[4] = {0, 0, 0, 1}; | 229 | __u8 i[4] = {0, 0, 0, 1}; |
| @@ -233,7 +233,7 @@ generate_smb3signingkey(struct cifs_ses *ses) | |||
| 233 | unsigned char *hashptr = prfhash; | 233 | unsigned char *hashptr = prfhash; |
| 234 | 234 | ||
| 235 | memset(prfhash, 0x0, SMB2_HMACSHA256_SIZE); | 235 | memset(prfhash, 0x0, SMB2_HMACSHA256_SIZE); |
| 236 | memset(ses->smb3signingkey, 0x0, SMB3_SIGNKEY_SIZE); | 236 | memset(key, 0x0, key_size); |
| 237 | 237 | ||
| 238 | rc = smb3_crypto_shash_allocate(ses->server); | 238 | rc = smb3_crypto_shash_allocate(ses->server); |
| 239 | if (rc) { | 239 | if (rc) { |
| @@ -262,7 +262,7 @@ generate_smb3signingkey(struct cifs_ses *ses) | |||
| 262 | } | 262 | } |
| 263 | 263 | ||
| 264 | rc = crypto_shash_update(&ses->server->secmech.sdeschmacsha256->shash, | 264 | rc = crypto_shash_update(&ses->server->secmech.sdeschmacsha256->shash, |
| 265 | "SMB2AESCMAC", 12); | 265 | label.iov_base, label.iov_len); |
| 266 | if (rc) { | 266 | if (rc) { |
| 267 | cifs_dbg(VFS, "%s: Could not update with label\n", __func__); | 267 | cifs_dbg(VFS, "%s: Could not update with label\n", __func__); |
| 268 | goto smb3signkey_ret; | 268 | goto smb3signkey_ret; |
| @@ -276,7 +276,7 @@ generate_smb3signingkey(struct cifs_ses *ses) | |||
| 276 | } | 276 | } |
| 277 | 277 | ||
| 278 | rc = crypto_shash_update(&ses->server->secmech.sdeschmacsha256->shash, | 278 | rc = crypto_shash_update(&ses->server->secmech.sdeschmacsha256->shash, |
| 279 | "SmbSign", 8); | 279 | context.iov_base, context.iov_len); |
| 280 | if (rc) { | 280 | if (rc) { |
| 281 | cifs_dbg(VFS, "%s: Could not update with context\n", __func__); | 281 | cifs_dbg(VFS, "%s: Could not update with context\n", __func__); |
| 282 | goto smb3signkey_ret; | 282 | goto smb3signkey_ret; |
| @@ -296,12 +296,102 @@ generate_smb3signingkey(struct cifs_ses *ses) | |||
| 296 | goto smb3signkey_ret; | 296 | goto smb3signkey_ret; |
| 297 | } | 297 | } |
| 298 | 298 | ||
| 299 | memcpy(ses->smb3signingkey, hashptr, SMB3_SIGNKEY_SIZE); | 299 | memcpy(key, hashptr, key_size); |
| 300 | 300 | ||
| 301 | smb3signkey_ret: | 301 | smb3signkey_ret: |
| 302 | return rc; | 302 | return rc; |
| 303 | } | 303 | } |
| 304 | 304 | ||
| 305 | struct derivation { | ||
| 306 | struct kvec label; | ||
| 307 | struct kvec context; | ||
| 308 | }; | ||
| 309 | |||
| 310 | struct derivation_triplet { | ||
| 311 | struct derivation signing; | ||
| 312 | struct derivation encryption; | ||
| 313 | struct derivation decryption; | ||
| 314 | }; | ||
| 315 | |||
| 316 | static int | ||
| 317 | generate_smb3signingkey(struct cifs_ses *ses, | ||
| 318 | const struct derivation_triplet *ptriplet) | ||
| 319 | { | ||
| 320 | int rc; | ||
| 321 | |||
| 322 | rc = generate_key(ses, ptriplet->signing.label, | ||
| 323 | ptriplet->signing.context, ses->smb3signingkey, | ||
| 324 | SMB3_SIGN_KEY_SIZE); | ||
| 325 | if (rc) | ||
| 326 | return rc; | ||
| 327 | |||
| 328 | rc = generate_key(ses, ptriplet->encryption.label, | ||
| 329 | ptriplet->encryption.context, ses->smb3encryptionkey, | ||
| 330 | SMB3_SIGN_KEY_SIZE); | ||
| 331 | if (rc) | ||
| 332 | return rc; | ||
| 333 | |||
| 334 | return generate_key(ses, ptriplet->decryption.label, | ||
| 335 | ptriplet->decryption.context, | ||
| 336 | ses->smb3decryptionkey, SMB3_SIGN_KEY_SIZE); | ||
| 337 | } | ||
| 338 | |||
| 339 | int | ||
| 340 | generate_smb30signingkey(struct cifs_ses *ses) | ||
| 341 | |||
| 342 | { | ||
| 343 | struct derivation_triplet triplet; | ||
| 344 | struct derivation *d; | ||
| 345 | |||
| 346 | d = &triplet.signing; | ||
| 347 | d->label.iov_base = "SMB2AESCMAC"; | ||
| 348 | d->label.iov_len = 12; | ||
| 349 | d->context.iov_base = "SmbSign"; | ||
| 350 | d->context.iov_len = 8; | ||
| 351 | |||
| 352 | d = &triplet.encryption; | ||
| 353 | d->label.iov_base = "SMB2AESCCM"; | ||
| 354 | d->label.iov_len = 11; | ||
| 355 | d->context.iov_base = "ServerIn "; | ||
| 356 | d->context.iov_len = 10; | ||
| 357 | |||
| 358 | d = &triplet.decryption; | ||
| 359 | d->label.iov_base = "SMB2AESCCM"; | ||
| 360 | d->label.iov_len = 11; | ||
| 361 | d->context.iov_base = "ServerOut"; | ||
| 362 | d->context.iov_len = 10; | ||
| 363 | |||
| 364 | return generate_smb3signingkey(ses, &triplet); | ||
| 365 | } | ||
| 366 | |||
| 367 | int | ||
| 368 | generate_smb311signingkey(struct cifs_ses *ses) | ||
| 369 | |||
| 370 | { | ||
| 371 | struct derivation_triplet triplet; | ||
| 372 | struct derivation *d; | ||
| 373 | |||
| 374 | d = &triplet.signing; | ||
| 375 | d->label.iov_base = "SMB2AESCMAC"; | ||
| 376 | d->label.iov_len = 12; | ||
| 377 | d->context.iov_base = "SmbSign"; | ||
| 378 | d->context.iov_len = 8; | ||
| 379 | |||
| 380 | d = &triplet.encryption; | ||
| 381 | d->label.iov_base = "SMB2AESCCM"; | ||
| 382 | d->label.iov_len = 11; | ||
| 383 | d->context.iov_base = "ServerIn "; | ||
| 384 | d->context.iov_len = 10; | ||
| 385 | |||
| 386 | d = &triplet.decryption; | ||
| 387 | d->label.iov_base = "SMB2AESCCM"; | ||
| 388 | d->label.iov_len = 11; | ||
| 389 | d->context.iov_base = "ServerOut"; | ||
| 390 | d->context.iov_len = 10; | ||
| 391 | |||
| 392 | return generate_smb3signingkey(ses, &triplet); | ||
| 393 | } | ||
| 394 | |||
| 305 | int | 395 | int |
| 306 | smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) | 396 | smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) |
| 307 | { | 397 | { |
