| .. | .. |
|---|
| 29 | 29 | #include "cifs_unicode.h" |
|---|
| 30 | 30 | #include "smb2status.h" |
|---|
| 31 | 31 | #include "smb2glob.h" |
|---|
| 32 | +#include "nterr.h" |
|---|
| 32 | 33 | |
|---|
| 33 | 34 | static int |
|---|
| 34 | 35 | check_smb2_hdr(struct smb2_sync_hdr *shdr, __u64 mid) |
|---|
| .. | .. |
|---|
| 93 | 94 | /* SMB2_OPLOCK_BREAK */ cpu_to_le16(24) |
|---|
| 94 | 95 | }; |
|---|
| 95 | 96 | |
|---|
| 97 | +#define SMB311_NEGPROT_BASE_SIZE (sizeof(struct smb2_sync_hdr) + sizeof(struct smb2_negotiate_rsp)) |
|---|
| 98 | + |
|---|
| 96 | 99 | static __u32 get_neg_ctxt_len(struct smb2_sync_hdr *hdr, __u32 len, |
|---|
| 97 | 100 | __u32 non_ctxlen) |
|---|
| 98 | 101 | { |
|---|
| .. | .. |
|---|
| 108 | 111 | |
|---|
| 109 | 112 | /* Make sure that negotiate contexts start after gss security blob */ |
|---|
| 110 | 113 | nc_offset = le32_to_cpu(pneg_rsp->NegotiateContextOffset); |
|---|
| 111 | | - if (nc_offset < non_ctxlen) { |
|---|
| 112 | | - printk_once(KERN_WARNING "invalid negotiate context offset\n"); |
|---|
| 114 | + if (nc_offset + 1 < non_ctxlen) { |
|---|
| 115 | + pr_warn_once("Invalid negotiate context offset %d\n", nc_offset); |
|---|
| 113 | 116 | return 0; |
|---|
| 114 | | - } |
|---|
| 115 | | - size_of_pad_before_neg_ctxts = nc_offset - non_ctxlen; |
|---|
| 117 | + } else if (nc_offset + 1 == non_ctxlen) { |
|---|
| 118 | + cifs_dbg(FYI, "no SPNEGO security blob in negprot rsp\n"); |
|---|
| 119 | + size_of_pad_before_neg_ctxts = 0; |
|---|
| 120 | + } else if (non_ctxlen == SMB311_NEGPROT_BASE_SIZE) |
|---|
| 121 | + /* has padding, but no SPNEGO blob */ |
|---|
| 122 | + size_of_pad_before_neg_ctxts = nc_offset - non_ctxlen + 1; |
|---|
| 123 | + else |
|---|
| 124 | + size_of_pad_before_neg_ctxts = nc_offset - non_ctxlen; |
|---|
| 116 | 125 | |
|---|
| 117 | 126 | /* Verify that at least minimal negotiate contexts fit within frame */ |
|---|
| 118 | 127 | if (len < nc_offset + (neg_count * sizeof(struct smb2_neg_context))) { |
|---|
| 119 | | - printk_once(KERN_WARNING "negotiate context goes beyond end\n"); |
|---|
| 128 | + pr_warn_once("negotiate context goes beyond end\n"); |
|---|
| 120 | 129 | return 0; |
|---|
| 121 | 130 | } |
|---|
| 122 | 131 | |
|---|
| .. | .. |
|---|
| 189 | 198 | return 1; |
|---|
| 190 | 199 | |
|---|
| 191 | 200 | if (shdr->StructureSize != SMB2_HEADER_STRUCTURE_SIZE) { |
|---|
| 192 | | - cifs_dbg(VFS, "Illegal structure size %u\n", |
|---|
| 201 | + cifs_dbg(VFS, "Invalid structure size %u\n", |
|---|
| 193 | 202 | le16_to_cpu(shdr->StructureSize)); |
|---|
| 194 | 203 | return 1; |
|---|
| 195 | 204 | } |
|---|
| 196 | 205 | |
|---|
| 197 | 206 | command = le16_to_cpu(shdr->Command); |
|---|
| 198 | 207 | if (command >= NUMBER_OF_SMB2_COMMANDS) { |
|---|
| 199 | | - cifs_dbg(VFS, "Illegal SMB2 command %d\n", command); |
|---|
| 208 | + cifs_dbg(VFS, "Invalid SMB2 command %d\n", command); |
|---|
| 200 | 209 | return 1; |
|---|
| 201 | 210 | } |
|---|
| 202 | 211 | |
|---|
| .. | .. |
|---|
| 204 | 213 | if (command != SMB2_OPLOCK_BREAK_HE && (shdr->Status == 0 || |
|---|
| 205 | 214 | pdu->StructureSize2 != SMB2_ERROR_STRUCTURE_SIZE2)) { |
|---|
| 206 | 215 | /* error packets have 9 byte structure size */ |
|---|
| 207 | | - cifs_dbg(VFS, "Illegal response size %u for command %d\n", |
|---|
| 216 | + cifs_dbg(VFS, "Invalid response size %u for command %d\n", |
|---|
| 208 | 217 | le16_to_cpu(pdu->StructureSize2), command); |
|---|
| 209 | 218 | return 1; |
|---|
| 210 | 219 | } else if (command == SMB2_OPLOCK_BREAK_HE |
|---|
| .. | .. |
|---|
| 212 | 221 | && (le16_to_cpu(pdu->StructureSize2) != 44) |
|---|
| 213 | 222 | && (le16_to_cpu(pdu->StructureSize2) != 36)) { |
|---|
| 214 | 223 | /* special case for SMB2.1 lease break message */ |
|---|
| 215 | | - cifs_dbg(VFS, "Illegal response size %d for oplock break\n", |
|---|
| 224 | + cifs_dbg(VFS, "Invalid response size %d for oplock break\n", |
|---|
| 216 | 225 | le16_to_cpu(pdu->StructureSize2)); |
|---|
| 217 | 226 | return 1; |
|---|
| 218 | 227 | } |
|---|
| .. | .. |
|---|
| 249 | 258 | * of junk. Other servers match RFC1001 len to actual |
|---|
| 250 | 259 | * SMB2/SMB3 frame length (header + smb2 response specific data) |
|---|
| 251 | 260 | * Some windows servers also pad up to 8 bytes when compounding. |
|---|
| 252 | | - * If pad is longer than eight bytes, log the server behavior |
|---|
| 253 | | - * (once), since may indicate a problem but allow it and continue |
|---|
| 254 | | - * since the frame is parseable. |
|---|
| 255 | 261 | */ |
|---|
| 256 | | - if (clc_len < len) { |
|---|
| 257 | | - pr_warn_once( |
|---|
| 258 | | - "srv rsp padded more than expected. Length %d not %d for cmd:%d mid:%llu\n", |
|---|
| 259 | | - len, clc_len, command, mid); |
|---|
| 262 | + if (clc_len < len) |
|---|
| 260 | 263 | return 0; |
|---|
| 261 | | - } |
|---|
| 264 | + |
|---|
| 262 | 265 | pr_warn_once( |
|---|
| 263 | 266 | "srv rsp too short, len %d not %d. cmd:%d mid:%llu\n", |
|---|
| 264 | 267 | len, clc_len, command, mid); |
|---|
| .. | .. |
|---|
| 359 | 362 | ((struct smb2_ioctl_rsp *)shdr)->OutputCount); |
|---|
| 360 | 363 | break; |
|---|
| 361 | 364 | case SMB2_CHANGE_NOTIFY: |
|---|
| 365 | + *off = le16_to_cpu( |
|---|
| 366 | + ((struct smb2_change_notify_rsp *)shdr)->OutputBufferOffset); |
|---|
| 367 | + *len = le32_to_cpu( |
|---|
| 368 | + ((struct smb2_change_notify_rsp *)shdr)->OutputBufferLength); |
|---|
| 369 | + break; |
|---|
| 362 | 370 | default: |
|---|
| 363 | | - /* BB FIXME for unimplemented cases above */ |
|---|
| 364 | | - cifs_dbg(VFS, "no length check for command\n"); |
|---|
| 371 | + cifs_dbg(VFS, "no length check for command %d\n", le16_to_cpu(shdr->Command)); |
|---|
| 365 | 372 | break; |
|---|
| 366 | 373 | } |
|---|
| 367 | 374 | |
|---|
| .. | .. |
|---|
| 747 | 754 | { |
|---|
| 748 | 755 | struct close_cancelled_open *cancelled = container_of(work, |
|---|
| 749 | 756 | struct close_cancelled_open, work); |
|---|
| 757 | + struct cifs_tcon *tcon = cancelled->tcon; |
|---|
| 758 | + int rc; |
|---|
| 750 | 759 | |
|---|
| 751 | | - cifs_dbg(VFS, "Close unmatched open\n"); |
|---|
| 760 | + if (cancelled->mid) |
|---|
| 761 | + cifs_tcon_dbg(VFS, "Close unmatched open for MID:%llx\n", |
|---|
| 762 | + cancelled->mid); |
|---|
| 763 | + else |
|---|
| 764 | + cifs_tcon_dbg(VFS, "Close interrupted close\n"); |
|---|
| 752 | 765 | |
|---|
| 753 | | - SMB2_close(0, cancelled->tcon, cancelled->fid.persistent_fid, |
|---|
| 754 | | - cancelled->fid.volatile_fid); |
|---|
| 755 | | - cifs_put_tcon(cancelled->tcon); |
|---|
| 766 | + rc = SMB2_close(0, tcon, cancelled->fid.persistent_fid, |
|---|
| 767 | + cancelled->fid.volatile_fid); |
|---|
| 768 | + if (rc) |
|---|
| 769 | + cifs_tcon_dbg(VFS, "Close cancelled mid failed rc:%d\n", rc); |
|---|
| 770 | + |
|---|
| 771 | + cifs_put_tcon(tcon); |
|---|
| 756 | 772 | kfree(cancelled); |
|---|
| 757 | 773 | } |
|---|
| 758 | 774 | |
|---|
| 759 | | -/* Caller should already has an extra reference to @tcon */ |
|---|
| 775 | +/* |
|---|
| 776 | + * Caller should already has an extra reference to @tcon |
|---|
| 777 | + * This function is used to queue work to close a handle to prevent leaks |
|---|
| 778 | + * on the server. |
|---|
| 779 | + * We handle two cases. If an open was interrupted after we sent the |
|---|
| 780 | + * SMB2_CREATE to the server but before we processed the reply, and second |
|---|
| 781 | + * if a close was interrupted before we sent the SMB2_CLOSE to the server. |
|---|
| 782 | + */ |
|---|
| 760 | 783 | static int |
|---|
| 761 | | -__smb2_handle_cancelled_close(struct cifs_tcon *tcon, __u64 persistent_fid, |
|---|
| 762 | | - __u64 volatile_fid) |
|---|
| 784 | +__smb2_handle_cancelled_cmd(struct cifs_tcon *tcon, __u16 cmd, __u64 mid, |
|---|
| 785 | + __u64 persistent_fid, __u64 volatile_fid) |
|---|
| 763 | 786 | { |
|---|
| 764 | 787 | struct close_cancelled_open *cancelled; |
|---|
| 765 | 788 | |
|---|
| .. | .. |
|---|
| 770 | 793 | cancelled->fid.persistent_fid = persistent_fid; |
|---|
| 771 | 794 | cancelled->fid.volatile_fid = volatile_fid; |
|---|
| 772 | 795 | cancelled->tcon = tcon; |
|---|
| 796 | + cancelled->cmd = cmd; |
|---|
| 797 | + cancelled->mid = mid; |
|---|
| 773 | 798 | INIT_WORK(&cancelled->work, smb2_cancelled_close_fid); |
|---|
| 774 | 799 | WARN_ON(queue_work(cifsiod_wq, &cancelled->work) == false); |
|---|
| 775 | 800 | |
|---|
| .. | .. |
|---|
| 784 | 809 | |
|---|
| 785 | 810 | cifs_dbg(FYI, "%s: tc_count=%d\n", __func__, tcon->tc_count); |
|---|
| 786 | 811 | spin_lock(&cifs_tcp_ses_lock); |
|---|
| 812 | + if (tcon->tc_count <= 0) { |
|---|
| 813 | + struct TCP_Server_Info *server = NULL; |
|---|
| 814 | + |
|---|
| 815 | + WARN_ONCE(tcon->tc_count < 0, "tcon refcount is negative"); |
|---|
| 816 | + spin_unlock(&cifs_tcp_ses_lock); |
|---|
| 817 | + |
|---|
| 818 | + if (tcon->ses) |
|---|
| 819 | + server = tcon->ses->server; |
|---|
| 820 | + |
|---|
| 821 | + cifs_server_dbg(FYI, "tid=%u: tcon is closing, skipping async close retry of fid %llu %llu\n", |
|---|
| 822 | + tcon->tid, persistent_fid, volatile_fid); |
|---|
| 823 | + |
|---|
| 824 | + return 0; |
|---|
| 825 | + } |
|---|
| 787 | 826 | tcon->tc_count++; |
|---|
| 788 | 827 | spin_unlock(&cifs_tcp_ses_lock); |
|---|
| 789 | 828 | |
|---|
| 790 | | - rc = __smb2_handle_cancelled_close(tcon, persistent_fid, volatile_fid); |
|---|
| 829 | + rc = __smb2_handle_cancelled_cmd(tcon, SMB2_CLOSE_HE, 0, |
|---|
| 830 | + persistent_fid, volatile_fid); |
|---|
| 791 | 831 | if (rc) |
|---|
| 792 | 832 | cifs_put_tcon(tcon); |
|---|
| 793 | 833 | |
|---|
| .. | .. |
|---|
| 795 | 835 | } |
|---|
| 796 | 836 | |
|---|
| 797 | 837 | int |
|---|
| 798 | | -smb2_handle_cancelled_mid(char *buffer, struct TCP_Server_Info *server) |
|---|
| 838 | +smb2_handle_cancelled_mid(struct mid_q_entry *mid, struct TCP_Server_Info *server) |
|---|
| 799 | 839 | { |
|---|
| 800 | | - struct smb2_sync_hdr *sync_hdr = (struct smb2_sync_hdr *)buffer; |
|---|
| 801 | | - struct smb2_create_rsp *rsp = (struct smb2_create_rsp *)buffer; |
|---|
| 840 | + struct smb2_sync_hdr *sync_hdr = mid->resp_buf; |
|---|
| 841 | + struct smb2_create_rsp *rsp = mid->resp_buf; |
|---|
| 802 | 842 | struct cifs_tcon *tcon; |
|---|
| 803 | 843 | int rc; |
|---|
| 804 | 844 | |
|---|
| 805 | | - if (sync_hdr->Command != SMB2_CREATE || |
|---|
| 845 | + if ((mid->optype & CIFS_CP_CREATE_CLOSE_OP) || sync_hdr->Command != SMB2_CREATE || |
|---|
| 806 | 846 | sync_hdr->Status != STATUS_SUCCESS) |
|---|
| 807 | 847 | return 0; |
|---|
| 808 | 848 | |
|---|
| .. | .. |
|---|
| 811 | 851 | if (!tcon) |
|---|
| 812 | 852 | return -ENOENT; |
|---|
| 813 | 853 | |
|---|
| 814 | | - rc = __smb2_handle_cancelled_close(tcon, rsp->PersistentFileId, |
|---|
| 815 | | - rsp->VolatileFileId); |
|---|
| 854 | + rc = __smb2_handle_cancelled_cmd(tcon, |
|---|
| 855 | + le16_to_cpu(sync_hdr->Command), |
|---|
| 856 | + le64_to_cpu(sync_hdr->MessageId), |
|---|
| 857 | + rsp->PersistentFileId, |
|---|
| 858 | + rsp->VolatileFileId); |
|---|
| 816 | 859 | if (rc) |
|---|
| 817 | 860 | cifs_put_tcon(tcon); |
|---|
| 818 | 861 | |
|---|
| .. | .. |
|---|
| 831 | 874 | int i, rc; |
|---|
| 832 | 875 | struct sdesc *d; |
|---|
| 833 | 876 | struct smb2_sync_hdr *hdr; |
|---|
| 877 | + struct TCP_Server_Info *server = cifs_ses_server(ses); |
|---|
| 834 | 878 | |
|---|
| 835 | | - if (ses->server->tcpStatus == CifsGood) { |
|---|
| 836 | | - /* skip non smb311 connections */ |
|---|
| 837 | | - if (ses->server->dialect != SMB311_PROT_ID) |
|---|
| 838 | | - return 0; |
|---|
| 879 | + hdr = (struct smb2_sync_hdr *)iov[0].iov_base; |
|---|
| 880 | + /* neg prot are always taken */ |
|---|
| 881 | + if (hdr->Command == SMB2_NEGOTIATE) |
|---|
| 882 | + goto ok; |
|---|
| 839 | 883 | |
|---|
| 840 | | - /* skip last sess setup response */ |
|---|
| 841 | | - hdr = (struct smb2_sync_hdr *)iov[0].iov_base; |
|---|
| 842 | | - if (hdr->Flags & SMB2_FLAGS_SIGNED) |
|---|
| 843 | | - return 0; |
|---|
| 844 | | - } |
|---|
| 884 | + /* |
|---|
| 885 | + * If we process a command which wasn't a negprot it means the |
|---|
| 886 | + * neg prot was already done, so the server dialect was set |
|---|
| 887 | + * and we can test it. Preauth requires 3.1.1 for now. |
|---|
| 888 | + */ |
|---|
| 889 | + if (server->dialect != SMB311_PROT_ID) |
|---|
| 890 | + return 0; |
|---|
| 845 | 891 | |
|---|
| 846 | | - rc = smb311_crypto_shash_allocate(ses->server); |
|---|
| 892 | + if (hdr->Command != SMB2_SESSION_SETUP) |
|---|
| 893 | + return 0; |
|---|
| 894 | + |
|---|
| 895 | + /* skip last sess setup response */ |
|---|
| 896 | + if ((hdr->Flags & SMB2_FLAGS_SERVER_TO_REDIR) |
|---|
| 897 | + && (hdr->Status == NT_STATUS_OK |
|---|
| 898 | + || (hdr->Status != |
|---|
| 899 | + cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED)))) |
|---|
| 900 | + return 0; |
|---|
| 901 | + |
|---|
| 902 | +ok: |
|---|
| 903 | + rc = smb311_crypto_shash_allocate(server); |
|---|
| 847 | 904 | if (rc) |
|---|
| 848 | 905 | return rc; |
|---|
| 849 | 906 | |
|---|
| 850 | | - d = ses->server->secmech.sdescsha512; |
|---|
| 907 | + d = server->secmech.sdescsha512; |
|---|
| 851 | 908 | rc = crypto_shash_init(&d->shash); |
|---|
| 852 | 909 | if (rc) { |
|---|
| 853 | | - cifs_dbg(VFS, "%s: could not init sha512 shash\n", __func__); |
|---|
| 910 | + cifs_dbg(VFS, "%s: Could not init sha512 shash\n", __func__); |
|---|
| 854 | 911 | return rc; |
|---|
| 855 | 912 | } |
|---|
| 856 | 913 | |
|---|
| 857 | 914 | rc = crypto_shash_update(&d->shash, ses->preauth_sha_hash, |
|---|
| 858 | 915 | SMB2_PREAUTH_HASH_SIZE); |
|---|
| 859 | 916 | if (rc) { |
|---|
| 860 | | - cifs_dbg(VFS, "%s: could not update sha512 shash\n", __func__); |
|---|
| 917 | + cifs_dbg(VFS, "%s: Could not update sha512 shash\n", __func__); |
|---|
| 861 | 918 | return rc; |
|---|
| 862 | 919 | } |
|---|
| 863 | 920 | |
|---|
| .. | .. |
|---|
| 865 | 922 | rc = crypto_shash_update(&d->shash, |
|---|
| 866 | 923 | iov[i].iov_base, iov[i].iov_len); |
|---|
| 867 | 924 | if (rc) { |
|---|
| 868 | | - cifs_dbg(VFS, "%s: could not update sha512 shash\n", |
|---|
| 925 | + cifs_dbg(VFS, "%s: Could not update sha512 shash\n", |
|---|
| 869 | 926 | __func__); |
|---|
| 870 | 927 | return rc; |
|---|
| 871 | 928 | } |
|---|
| .. | .. |
|---|
| 873 | 930 | |
|---|
| 874 | 931 | rc = crypto_shash_final(&d->shash, ses->preauth_sha_hash); |
|---|
| 875 | 932 | if (rc) { |
|---|
| 876 | | - cifs_dbg(VFS, "%s: could not finalize sha512 shash\n", |
|---|
| 933 | + cifs_dbg(VFS, "%s: Could not finalize sha512 shash\n", |
|---|
| 877 | 934 | __func__); |
|---|
| 878 | 935 | return rc; |
|---|
| 879 | 936 | } |
|---|