aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs/smb2misc.c
diff options
context:
space:
mode:
authorPavel Shilovsky <pshilov@microsoft.com>2016-10-24 18:33:04 -0400
committerSteve French <smfrench@gmail.com>2017-02-01 17:46:34 -0500
commit31473fc4f9653b73750d3792ffce6a6e1bdf0da7 (patch)
treebb789f590f828d3da748de876a7fafa43e654e7a /fs/cifs/smb2misc.c
parent9c25702cee1405099f982894c865c163de7909a8 (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.c61
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
32static int 33static int
33check_smb2_hdr(struct smb2_hdr *hdr, __u64 mid) 34check_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] = {
95int 96int
96smb2_check_message(char *buf, unsigned int length, struct TCP_Server_Info *srvr) 97smb2_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] = {
261char * 264char *
262smb2_get_data_area_len(int *off, int *len, struct smb2_hdr *hdr) 265smb2_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)
358unsigned int 362unsigned int
359smb2_calc_size(void *buf) 363smb2_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 !=