diff options
author | Pavel Shilovsky <pshilov@microsoft.com> | 2016-10-24 18:33:04 -0400 |
---|---|---|
committer | Steve French <smfrench@gmail.com> | 2017-02-01 17:46:34 -0500 |
commit | 31473fc4f9653b73750d3792ffce6a6e1bdf0da7 (patch) | |
tree | bb789f590f828d3da748de876a7fafa43e654e7a /fs/cifs/smb2misc.c | |
parent | 9c25702cee1405099f982894c865c163de7909a8 (diff) |
CIFS: Separate SMB2 header structure
In order to support compounding and encryption we need to separate
RFC1001 length field and SMB2 header structure because the protocol
treats them differently. This change will allow to simplify parsing
of such complex SMB2 packets further.
Signed-off-by: Pavel Shilovsky <pshilov@microsoft.com>
Diffstat (limited to 'fs/cifs/smb2misc.c')
-rw-r--r-- | fs/cifs/smb2misc.c | 61 |
1 files changed, 33 insertions, 28 deletions
diff --git a/fs/cifs/smb2misc.c b/fs/cifs/smb2misc.c index 3d383489b9cf..fd516ea8b8f8 100644 --- a/fs/cifs/smb2misc.c +++ b/fs/cifs/smb2misc.c | |||
@@ -28,31 +28,32 @@ | |||
28 | #include "cifs_debug.h" | 28 | #include "cifs_debug.h" |
29 | #include "cifs_unicode.h" | 29 | #include "cifs_unicode.h" |
30 | #include "smb2status.h" | 30 | #include "smb2status.h" |
31 | #include "smb2glob.h" | ||
31 | 32 | ||
32 | static int | 33 | static int |
33 | check_smb2_hdr(struct smb2_hdr *hdr, __u64 mid) | 34 | check_smb2_hdr(struct smb2_sync_hdr *shdr, __u64 mid) |
34 | { | 35 | { |
35 | __u64 wire_mid = le64_to_cpu(hdr->MessageId); | 36 | __u64 wire_mid = le64_to_cpu(shdr->MessageId); |
36 | 37 | ||
37 | /* | 38 | /* |
38 | * Make sure that this really is an SMB, that it is a response, | 39 | * Make sure that this really is an SMB, that it is a response, |
39 | * and that the message ids match. | 40 | * and that the message ids match. |
40 | */ | 41 | */ |
41 | if ((hdr->ProtocolId == SMB2_PROTO_NUMBER) && | 42 | if ((shdr->ProtocolId == SMB2_PROTO_NUMBER) && |
42 | (mid == wire_mid)) { | 43 | (mid == wire_mid)) { |
43 | if (hdr->Flags & SMB2_FLAGS_SERVER_TO_REDIR) | 44 | if (shdr->Flags & SMB2_FLAGS_SERVER_TO_REDIR) |
44 | return 0; | 45 | return 0; |
45 | else { | 46 | else { |
46 | /* only one valid case where server sends us request */ | 47 | /* only one valid case where server sends us request */ |
47 | if (hdr->Command == SMB2_OPLOCK_BREAK) | 48 | if (shdr->Command == SMB2_OPLOCK_BREAK) |
48 | return 0; | 49 | return 0; |
49 | else | 50 | else |
50 | cifs_dbg(VFS, "Received Request not response\n"); | 51 | cifs_dbg(VFS, "Received Request not response\n"); |
51 | } | 52 | } |
52 | } else { /* bad signature or mid */ | 53 | } else { /* bad signature or mid */ |
53 | if (hdr->ProtocolId != SMB2_PROTO_NUMBER) | 54 | if (shdr->ProtocolId != SMB2_PROTO_NUMBER) |
54 | cifs_dbg(VFS, "Bad protocol string signature header %x\n", | 55 | cifs_dbg(VFS, "Bad protocol string signature header %x\n", |
55 | le32_to_cpu(hdr->ProtocolId)); | 56 | le32_to_cpu(shdr->ProtocolId)); |
56 | if (mid != wire_mid) | 57 | if (mid != wire_mid) |
57 | cifs_dbg(VFS, "Mids do not match: %llu and %llu\n", | 58 | cifs_dbg(VFS, "Mids do not match: %llu and %llu\n", |
58 | mid, wire_mid); | 59 | mid, wire_mid); |
@@ -95,8 +96,9 @@ static const __le16 smb2_rsp_struct_sizes[NUMBER_OF_SMB2_COMMANDS] = { | |||
95 | int | 96 | int |
96 | smb2_check_message(char *buf, unsigned int length, struct TCP_Server_Info *srvr) | 97 | smb2_check_message(char *buf, unsigned int length, struct TCP_Server_Info *srvr) |
97 | { | 98 | { |
98 | struct smb2_hdr *hdr = (struct smb2_hdr *)buf; | 99 | struct smb2_pdu *pdu = (struct smb2_pdu *)buf; |
99 | struct smb2_pdu *pdu = (struct smb2_pdu *)hdr; | 100 | struct smb2_hdr *hdr = &pdu->hdr; |
101 | struct smb2_sync_hdr *shdr = get_sync_hdr(buf); | ||
100 | __u64 mid; | 102 | __u64 mid; |
101 | __u32 len = get_rfc1002_length(buf); | 103 | __u32 len = get_rfc1002_length(buf); |
102 | __u32 clc_len; /* calculated length */ | 104 | __u32 clc_len; /* calculated length */ |
@@ -111,7 +113,7 @@ smb2_check_message(char *buf, unsigned int length, struct TCP_Server_Info *srvr) | |||
111 | * ie Validate the wct via smb2_struct_sizes table above | 113 | * ie Validate the wct via smb2_struct_sizes table above |
112 | */ | 114 | */ |
113 | 115 | ||
114 | if (hdr->ProtocolId == SMB2_TRANSFORM_PROTO_NUM) { | 116 | if (shdr->ProtocolId == SMB2_TRANSFORM_PROTO_NUM) { |
115 | struct smb2_transform_hdr *thdr = | 117 | struct smb2_transform_hdr *thdr = |
116 | (struct smb2_transform_hdr *)buf; | 118 | (struct smb2_transform_hdr *)buf; |
117 | struct cifs_ses *ses = NULL; | 119 | struct cifs_ses *ses = NULL; |
@@ -133,10 +135,10 @@ smb2_check_message(char *buf, unsigned int length, struct TCP_Server_Info *srvr) | |||
133 | } | 135 | } |
134 | } | 136 | } |
135 | 137 | ||
136 | 138 | mid = le64_to_cpu(shdr->MessageId); | |
137 | mid = le64_to_cpu(hdr->MessageId); | ||
138 | if (length < sizeof(struct smb2_pdu)) { | 139 | if (length < sizeof(struct smb2_pdu)) { |
139 | if ((length >= sizeof(struct smb2_hdr)) && (hdr->Status != 0)) { | 140 | if ((length >= sizeof(struct smb2_hdr)) |
141 | && (shdr->Status != 0)) { | ||
140 | pdu->StructureSize2 = 0; | 142 | pdu->StructureSize2 = 0; |
141 | /* | 143 | /* |
142 | * As with SMB/CIFS, on some error cases servers may | 144 | * As with SMB/CIFS, on some error cases servers may |
@@ -154,29 +156,30 @@ smb2_check_message(char *buf, unsigned int length, struct TCP_Server_Info *srvr) | |||
154 | return 1; | 156 | return 1; |
155 | } | 157 | } |
156 | 158 | ||
157 | if (check_smb2_hdr(hdr, mid)) | 159 | if (check_smb2_hdr(shdr, mid)) |
158 | return 1; | 160 | return 1; |
159 | 161 | ||
160 | if (hdr->StructureSize != SMB2_HEADER_STRUCTURE_SIZE) { | 162 | if (shdr->StructureSize != SMB2_HEADER_STRUCTURE_SIZE) { |
161 | cifs_dbg(VFS, "Illegal structure size %u\n", | 163 | cifs_dbg(VFS, "Illegal structure size %u\n", |
162 | le16_to_cpu(hdr->StructureSize)); | 164 | le16_to_cpu(shdr->StructureSize)); |
163 | return 1; | 165 | return 1; |
164 | } | 166 | } |
165 | 167 | ||
166 | command = le16_to_cpu(hdr->Command); | 168 | command = le16_to_cpu(shdr->Command); |
167 | if (command >= NUMBER_OF_SMB2_COMMANDS) { | 169 | if (command >= NUMBER_OF_SMB2_COMMANDS) { |
168 | cifs_dbg(VFS, "Illegal SMB2 command %d\n", command); | 170 | cifs_dbg(VFS, "Illegal SMB2 command %d\n", command); |
169 | return 1; | 171 | return 1; |
170 | } | 172 | } |
171 | 173 | ||
172 | if (smb2_rsp_struct_sizes[command] != pdu->StructureSize2) { | 174 | if (smb2_rsp_struct_sizes[command] != pdu->StructureSize2) { |
173 | if (command != SMB2_OPLOCK_BREAK_HE && (hdr->Status == 0 || | 175 | if (command != SMB2_OPLOCK_BREAK_HE && (shdr->Status == 0 || |
174 | pdu->StructureSize2 != SMB2_ERROR_STRUCTURE_SIZE2)) { | 176 | pdu->StructureSize2 != SMB2_ERROR_STRUCTURE_SIZE2)) { |
175 | /* error packets have 9 byte structure size */ | 177 | /* error packets have 9 byte structure size */ |
176 | cifs_dbg(VFS, "Illegal response size %u for command %d\n", | 178 | cifs_dbg(VFS, "Illegal response size %u for command %d\n", |
177 | le16_to_cpu(pdu->StructureSize2), command); | 179 | le16_to_cpu(pdu->StructureSize2), command); |
178 | return 1; | 180 | return 1; |
179 | } else if (command == SMB2_OPLOCK_BREAK_HE && (hdr->Status == 0) | 181 | } else if (command == SMB2_OPLOCK_BREAK_HE |
182 | && (shdr->Status == 0) | ||
180 | && (le16_to_cpu(pdu->StructureSize2) != 44) | 183 | && (le16_to_cpu(pdu->StructureSize2) != 44) |
181 | && (le16_to_cpu(pdu->StructureSize2) != 36)) { | 184 | && (le16_to_cpu(pdu->StructureSize2) != 36)) { |
182 | /* special case for SMB2.1 lease break message */ | 185 | /* special case for SMB2.1 lease break message */ |
@@ -199,7 +202,7 @@ smb2_check_message(char *buf, unsigned int length, struct TCP_Server_Info *srvr) | |||
199 | clc_len, 4 + len, mid); | 202 | clc_len, 4 + len, mid); |
200 | /* create failed on symlink */ | 203 | /* create failed on symlink */ |
201 | if (command == SMB2_CREATE_HE && | 204 | if (command == SMB2_CREATE_HE && |
202 | hdr->Status == STATUS_STOPPED_ON_SYMLINK) | 205 | shdr->Status == STATUS_STOPPED_ON_SYMLINK) |
203 | return 0; | 206 | return 0; |
204 | /* Windows 7 server returns 24 bytes more */ | 207 | /* Windows 7 server returns 24 bytes more */ |
205 | if (clc_len + 20 == len && command == SMB2_OPLOCK_BREAK_HE) | 208 | if (clc_len + 20 == len && command == SMB2_OPLOCK_BREAK_HE) |
@@ -261,11 +264,12 @@ static const bool has_smb2_data_area[NUMBER_OF_SMB2_COMMANDS] = { | |||
261 | char * | 264 | char * |
262 | smb2_get_data_area_len(int *off, int *len, struct smb2_hdr *hdr) | 265 | smb2_get_data_area_len(int *off, int *len, struct smb2_hdr *hdr) |
263 | { | 266 | { |
267 | struct smb2_sync_hdr *shdr = get_sync_hdr(hdr); | ||
264 | *off = 0; | 268 | *off = 0; |
265 | *len = 0; | 269 | *len = 0; |
266 | 270 | ||
267 | /* error responses do not have data area */ | 271 | /* error responses do not have data area */ |
268 | if (hdr->Status && hdr->Status != STATUS_MORE_PROCESSING_REQUIRED && | 272 | if (shdr->Status && shdr->Status != STATUS_MORE_PROCESSING_REQUIRED && |
269 | (((struct smb2_err_rsp *)hdr)->StructureSize) == | 273 | (((struct smb2_err_rsp *)hdr)->StructureSize) == |
270 | SMB2_ERROR_STRUCTURE_SIZE2) | 274 | SMB2_ERROR_STRUCTURE_SIZE2) |
271 | return NULL; | 275 | return NULL; |
@@ -275,7 +279,7 @@ smb2_get_data_area_len(int *off, int *len, struct smb2_hdr *hdr) | |||
275 | * of the data buffer offset and data buffer length for the particular | 279 | * of the data buffer offset and data buffer length for the particular |
276 | * command. | 280 | * command. |
277 | */ | 281 | */ |
278 | switch (hdr->Command) { | 282 | switch (shdr->Command) { |
279 | case SMB2_NEGOTIATE: | 283 | case SMB2_NEGOTIATE: |
280 | *off = le16_to_cpu( | 284 | *off = le16_to_cpu( |
281 | ((struct smb2_negotiate_rsp *)hdr)->SecurityBufferOffset); | 285 | ((struct smb2_negotiate_rsp *)hdr)->SecurityBufferOffset); |
@@ -346,7 +350,7 @@ smb2_get_data_area_len(int *off, int *len, struct smb2_hdr *hdr) | |||
346 | 350 | ||
347 | /* return pointer to beginning of data area, ie offset from SMB start */ | 351 | /* return pointer to beginning of data area, ie offset from SMB start */ |
348 | if ((*off != 0) && (*len != 0)) | 352 | if ((*off != 0) && (*len != 0)) |
349 | return (char *)(&hdr->ProtocolId) + *off; | 353 | return (char *)shdr + *off; |
350 | else | 354 | else |
351 | return NULL; | 355 | return NULL; |
352 | } | 356 | } |
@@ -358,12 +362,13 @@ smb2_get_data_area_len(int *off, int *len, struct smb2_hdr *hdr) | |||
358 | unsigned int | 362 | unsigned int |
359 | smb2_calc_size(void *buf) | 363 | smb2_calc_size(void *buf) |
360 | { | 364 | { |
361 | struct smb2_hdr *hdr = (struct smb2_hdr *)buf; | 365 | struct smb2_pdu *pdu = (struct smb2_pdu *)buf; |
362 | struct smb2_pdu *pdu = (struct smb2_pdu *)hdr; | 366 | struct smb2_hdr *hdr = &pdu->hdr; |
367 | struct smb2_sync_hdr *shdr = get_sync_hdr(hdr); | ||
363 | int offset; /* the offset from the beginning of SMB to data area */ | 368 | int offset; /* the offset from the beginning of SMB to data area */ |
364 | int data_length; /* the length of the variable length data area */ | 369 | int data_length; /* the length of the variable length data area */ |
365 | /* Structure Size has already been checked to make sure it is 64 */ | 370 | /* Structure Size has already been checked to make sure it is 64 */ |
366 | int len = 4 + le16_to_cpu(pdu->hdr.StructureSize); | 371 | int len = 4 + le16_to_cpu(shdr->StructureSize); |
367 | 372 | ||
368 | /* | 373 | /* |
369 | * StructureSize2, ie length of fixed parameter area has already | 374 | * StructureSize2, ie length of fixed parameter area has already |
@@ -371,7 +376,7 @@ smb2_calc_size(void *buf) | |||
371 | */ | 376 | */ |
372 | len += le16_to_cpu(pdu->StructureSize2); | 377 | len += le16_to_cpu(pdu->StructureSize2); |
373 | 378 | ||
374 | if (has_smb2_data_area[le16_to_cpu(hdr->Command)] == false) | 379 | if (has_smb2_data_area[le16_to_cpu(shdr->Command)] == false) |
375 | goto calc_size_exit; | 380 | goto calc_size_exit; |
376 | 381 | ||
377 | smb2_get_data_area_len(&offset, &data_length, hdr); | 382 | smb2_get_data_area_len(&offset, &data_length, hdr); |
@@ -582,7 +587,7 @@ smb2_is_valid_oplock_break(char *buffer, struct TCP_Server_Info *server) | |||
582 | 587 | ||
583 | cifs_dbg(FYI, "Checking for oplock break\n"); | 588 | cifs_dbg(FYI, "Checking for oplock break\n"); |
584 | 589 | ||
585 | if (rsp->hdr.Command != SMB2_OPLOCK_BREAK) | 590 | if (rsp->hdr.sync_hdr.Command != SMB2_OPLOCK_BREAK) |
586 | return false; | 591 | return false; |
587 | 592 | ||
588 | if (rsp->StructureSize != | 593 | if (rsp->StructureSize != |