Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

SMB3: Fix length checking of SMB3.11 negotiate request

The length checking for SMB3.11 negotiate request includes
"negotiate contexts" which caused a buffer validation problem
and a confusing warning message on SMB3.11 mount e.g.:

SMB2 server sent bad RFC1001 len 236 not 170

Fix the length checking for SMB3.11 negotiate to account for
the new negotiate context so that we don't log a warning on
SMB3.11 mount by default but do log warnings if lengths returned
by the server are incorrect.

CC: Stable <stable@vger.kernel.org>
Signed-off-by: Steve French <smfrench@gmail.com>
Reviewed-by: Aurelien Aptel <aaptel@suse.com>
Reviewed-by: Pavel Shilovsky <pshilov@microsoft.com>

+46
+39
fs/cifs/smb2misc.c
··· 93 93 /* SMB2_OPLOCK_BREAK */ cpu_to_le16(24) 94 94 }; 95 95 96 + #ifdef CONFIG_CIFS_SMB311 97 + static __u32 get_neg_ctxt_len(struct smb2_hdr *hdr, __u32 len, __u32 non_ctxlen) 98 + { 99 + __u16 neg_count; 100 + __u32 nc_offset, size_of_pad_before_neg_ctxts; 101 + struct smb2_negotiate_rsp *pneg_rsp = (struct smb2_negotiate_rsp *)hdr; 102 + 103 + /* Negotiate contexts are only valid for latest dialect SMB3.11 */ 104 + neg_count = le16_to_cpu(pneg_rsp->NegotiateContextCount); 105 + if ((neg_count == 0) || 106 + (pneg_rsp->DialectRevision != cpu_to_le16(SMB311_PROT_ID))) 107 + return 0; 108 + 109 + /* Make sure that negotiate contexts start after gss security blob */ 110 + nc_offset = le32_to_cpu(pneg_rsp->NegotiateContextOffset); 111 + if (nc_offset < non_ctxlen - 4 /* RFC1001 len field */) { 112 + printk_once(KERN_WARNING "invalid negotiate context offset\n"); 113 + return 0; 114 + } 115 + size_of_pad_before_neg_ctxts = nc_offset - (non_ctxlen - 4); 116 + 117 + /* Verify that at least minimal negotiate contexts fit within frame */ 118 + if (len < nc_offset + (neg_count * sizeof(struct smb2_neg_context))) { 119 + printk_once(KERN_WARNING "negotiate context goes beyond end\n"); 120 + return 0; 121 + } 122 + 123 + cifs_dbg(FYI, "length of negcontexts %d pad %d\n", 124 + len - nc_offset, size_of_pad_before_neg_ctxts); 125 + 126 + /* length of negcontexts including pad from end of sec blob to them */ 127 + return (len - nc_offset) + size_of_pad_before_neg_ctxts; 128 + } 129 + #endif /* CIFS_SMB311 */ 130 + 96 131 int 97 132 smb2_check_message(char *buf, unsigned int length, struct TCP_Server_Info *srvr) 98 133 { ··· 233 198 234 199 clc_len = smb2_calc_size(hdr); 235 200 201 + #ifdef CONFIG_CIFS_SMB311 202 + if (shdr->Command == SMB2_NEGOTIATE) 203 + clc_len += get_neg_ctxt_len(hdr, len, clc_len); 204 + #endif /* SMB311 */ 236 205 if (srvr->vals->header_preamble_size + len != clc_len) { 237 206 cifs_dbg(FYI, "Calculated size %u length %zu mismatch mid %llu\n", 238 207 clc_len, srvr->vals->header_preamble_size + len, mid);
+7
fs/cifs/smb2pdu.h
··· 263 263 #define SMB2_NT_FIND 0x00100000 264 264 #define SMB2_LARGE_FILES 0x00200000 265 265 266 + struct smb2_neg_context { 267 + __le16 ContextType; 268 + __le16 DataLength; 269 + __le32 Reserved; 270 + /* Followed by array of data */ 271 + } __packed; 272 + 266 273 #define SMB311_SALT_SIZE 32 267 274 /* Hash Algorithm Types */ 268 275 #define SMB2_PREAUTH_INTEGRITY_SHA512 cpu_to_le16(0x0001)